writing Library help? (deprecated conversion from string constant)

I’m trying to turn my Parallel printer sketch into a library. This is my first effort in making a library, so I’m encountering a few problems.

My full sketch is here http://forum.arduino.cc/index.php?topic=205174.0, and it works fine as far as it goes. My first problem is in setting up the prototype and and getting it to work. In my header I have this prototype:

void printString(char toPrint[]);
void I2C_Thermal_Printer::printString(char toPrint[]){
  int wStart = 0, //start of word in string
  wEnd = 0;  //end of word
  int count = 0, //string position counter
  wordLen = 0;  //length of string
  while (toPrint[count] != '\0'){
    wStart = count;
    wordLen = 0;
    wEnd = count;
    count ++;
    wordLen++;
    for (int n = wEnd; n > (wStart - 1); n--){
      printChar(toPrint[n]);
    }
  }

But when I try to use the library, I cannot compile my ketch because I get the following error:

sketch_dec18a.ino:10: warning: deprecated conversion from string constant to 'char*'

Here is my sketch:

#include <I2C_Thermal_Printer_Test.h>

I2C_Thermal_Printer printer(10, 11, 0x20);

void setup(){
}

void loop(){
  printer.printString("This is a test of my new Library!");
  printer.lineFeed(10);
  printer.doCut();
  delay(20000);
}

My Header:

/* I2C_Thermal_Printer.h for controlling a Thermal Printer with a PFC8574
   Jimmy Patrick, 12/18/2013
*/



#ifndef I2C_Thermal_Printer_h
#define I2C_Thermal_Printer_h

#include "Arduino.h"

class I2C_Thermal_Printer
{
    public:
        void I2C_Thermal_Printer(int strobePin, int busyPin, byte i2c_addr);
        void waitForPrinter(int port);
        void doStrobe();
        void setData(char text);
        void printChar(char toPrint);
        void initializePrinter();
        void alignCenter();
        void alignRight();
        void alignLeft();
        void underline();
        void thickUnderline();
        void noUnderline();
        void doCut();
        void doBuzzer(int repeat);
        void fontA();
        void fontB();
        void lineFeed(int lines);
        void boldOn();
        void boldOff();
        void inverse();
        void notInverse();
        void printSize(byte fontsize);
        void upsideDown();
        void notUpsideDown();
        void printString(char toPrint[]);
    private:
        int _busyPin;
        int _strobePin;
        byte _i2c_addr;
        int _strobeWait;
};
        
        
        
#endif

and my library cpp file:

//I2C_Thermal_Printer.cpp

#include "Arduino.h"
#include "I2C_Thermal_Printer.h"

I2C_Thermal_Printer::I2C_Thermal_Printer(int strobePin, int busyPin, byte i2c_addr){
    Wire.begin(i2c_addr);
    pinMode(strobePin, OUTPUT);
    pinMode(busyPin, INPUT);
    digitalWrite(strobePin, HIGH);
    initializePrinter();
    _strobeWait = 10;
    _busyPin = busyPin;
    _strobePin = strobePin;
    _i2c_addr = i2c_addr;
    delay(500);
    }
    
    
    
void I2C_Thermal_Printer::waitForPrinter(int port){
  while(digitalRead(port) == 1){
     // wait for busy to go low
  }
}

void I2C_Thermal_Printer::doStrobe(){
  digitalWrite(strobePin, LOW);
  delayMicroseconds(_strobeWait);
  digitalWrite(strobePin, HIGH);
  }
  
void I2C_Thermal_Printer::setData(char text){
  Wire.beginTransmission(_i2c_addr);
  Wire.write(text);
  Wire.endTransmission();
  doStrobe();
}



void I2C_Thermal_Printer::printChar(char toPrint){
  waitForPrinter(_busyPin);
  setData(toPrint);
  doStrobe();  
}

void I2C_Thermal_Printer::initializePrinter(){
  printChar((byte)0x1B);
  printChar((byte)0x40);
}

void I2C_Thermal_Printer::alignCenter(){
  printChar((byte)0x1B);
  printChar((byte)0x61);
  printChar(1);
}

void I2C_Thermal_Printer::alignRight(){
  printChar((byte)0x1B);
  printChar((byte)0x61);
  printChar(2);
}

void alignLeft(){
  printChar((byte)0x1B);
  printChar((byte)0x61);
  printChar(0);
}
  

void I2C_Thermal_Printer::underline(){
  printChar((byte)0x1B);
  printChar((byte)0x2D);
  printChar(1);
}

void I2C_Thermal_Printer::thickUnderline(){
  printChar((byte)0x1B);
  printChar((byte)0x2D);
  printChar(2);
}

void I2C_Thermal_Printer::noUnderline(){
  printChar((byte)0x1B);
  printChar((byte)0x2D);
  printChar(0);
}


void I2C_Thermal_Printer::doCut(){
  printChar((byte)0x1D);
  printChar((byte)0x56);
  printChar(49);
}

//Do the buzzer in increments of 200ms
void I2C_Thermal_Printer::doBuzzer(int repeat){
  for (int i = 0; i < repeat; i++){ 
    printChar((byte)0x1B);
    printChar((byte)0x1E);
    printChar(49);
  } 
}

//Select  the font. Valid params are 0 or 1
void I2C_Thermal_Printer::fontA(){
  printChar((byte)0x1B);
  printChar((byte)0x4D);
  printChar(0);
}

void I2C_Thermal_Printer::fontB(){
  printChar((byte)0x1B);
  printChar((byte)0x4D);
  printChar(1);
}

//Line feed (the number of lines to feed) 
void I2C_Thermal_Printer::lineFeed(int lines){
  printChar((byte)0x1B);
  printChar((byte)0x64);
  printChar(lines);
}
  
void I2C_Thermal_Printer::boldOn(){
  printChar((byte)0x1B);
  printChar((byte)0x45);
  printChar(1);
}

void I2C_Thermal_Printer::boldOff(){
  printChar((byte)0x1B);
  printChar((byte)0x45);
  printChar(0);
}

void I2C_Thermal_Printer::inverse(){
  printChar((byte)0x1D);
  printChar((byte)0x42);
  printChar(1);
}

void I2C_Thermal_Printer::notInverse(){
  printChar((byte)0x1D);
  printChar((byte)0x42);
  printChar(0);
}

//I don't understand the font size description in the manual. 
// fontsize 00 = standard, and the size changes based on this byte, 
// MSB is Horizontal and LSB is Vertical
// 22 is larger, 33 is even larger. Needs work.
void I2C_Thermal_Printer::printSize(byte fontsize){
  printChar((byte)0x1D);
  printChar((byte)0x21);
  printChar(fontsize);
}

void I2C_Thermal_Printer::upsideDown(){
  printChar((byte)0x1B);
  printChar((byte)0x7B);
  printChar(1);
}

void I2C_Thermal_Printer::notUpsideDown(){
  printChar((byte)0x1B);
  printChar((byte)0x7B);
  printChar(0);
}

void I2C_Thermal_Printer::printString(char toPrint[]){
  int wStart = 0, //start of word in string
  wEnd = 0;  //end of word
  int count = 0, //string position counter
  wordLen = 0;  //length of string
  while (toPrint[count] != '\0'){
    wStart = count;
    wordLen = 0;
    wEnd = count;
    count ++;
    wordLen++;
    for (int n = wEnd; n > (wStart - 1); n--){
      printChar(toPrint[n]);
    }
  }
}

Can anyone help me with the printString function?

Thanks

Jimmy

One tip make a helper function

void printCommand(byte command, byte param)
{
  printChar(0x1B);
  printChar(command);
  printChar(param);
}

// then you can reduce footprint a lot e.g. 
void alignLeft() { printCommand(0x61, 0); }

and maybe even

#define ALIGN_LEFT 0x61;
void alignLeft() { printCommand(ALIGN_LEFT , 0); }

add header with version number to handle updates, and feedback from users.

//
//    FILE:  
//  AUTHOR:  
// VERSION: 0.1.03
// PURPOSE:  
//    DATE: 2013-11-05
//     URL:
//
// Released to the public domain
//

Now I'm going to look at the string...

if you derive your class from print like in my parPrinter class here

you get all the print commands for free, including printing floats and int’s longs etc.

The only command you need to implement is the call : size_t ::write(uint8_t data)

should take less than an hour…

.h file

/* I2C_Thermal_Printer.h for controlling a Thermal Printer with a PFC8574
   Jimmy Patrick, 12/18/2013
*/

#ifndef I2C_Thermal_Printer_h
#define I2C_Thermal_Printer_h

#include "Arduino.h"

class I2C_Thermal_Printer: public Print
{
    public:
        void I2C_Thermal_Printer(int strobePin, int busyPin, byte i2c_addr);
        void waitForPrinter(int port);
        void doStrobe();
        void setData(char text);
        void printChar(char data);

        size_t write(uint8_t data) { printChar(data);  return 1; }
        
        void initializePrinter();
        void alignCenter();
        void alignRight();
        void alignLeft();
        void underline();
        void thickUnderline();
        void noUnderline();
        void doCut();
        void doBuzzer(int repeat);
        void fontA();
        void fontB();
        void lineFeed(int lines);
        void boldOn();
        void boldOff();
        void inverse();
        void notInverse();
        void printSize(byte fontsize);
        void upsideDown();
        void notUpsideDown();

         // removed printString 

    private:
        int _busyPin;
        int _strobePin;
        byte _i2c_addr;
        int _strobeWait;
};
#endif

.cpp has no changes.

!!not tested but you should get the idea

Thanks Rob. Interestingly, I did look at your thread about ParPrinter a few times, but I didn't really understand the idea of extending the print class. I started looking at some of adafruit's libraries and saw that same construct there. Then I looked at the playground and saw this Arduino Playground - Printclass. I think I will be able to take the posts you've just made, and the other examples and come up with something.

Thanks for the info,

Jimmy

Well, this compiles fine with the changes I've made, but it doesn't print a thing. I've put it up on github so anyone can use it if I get it working.

I'll keep looking at it, but it may be beyond my skills.

Jimmy

As a follow up, when I use this library the Arduino doesn't do anything. I put a

Serial.print(".");

in loop() and it never even gets to loop. I don't have a scope, so I can't see what the 8574 is doing, but I think I've just done something stupid in trying to make the library work.

I have tried to simplify my code so that I can understand it better and find out why it doesn’t work. Here I present my simplified version in case anyone can see my errors. The problem is that my extending of Print class doesn’t do anything.

My Sketch:

#include <test_lib.h>
#include <Wire.h>

test_lib printer;

void setup(){
  printer.begin();
}

void loop(){
    
    delayMicroseconds(10);
    printer.print("B");
    delayMicroseconds(10); 
    printer.printA();  
}

prints “A” and then feeds the paper then does the paper cutter action.

Here is my .h file:

//
//    FILE:  test_lib.h
//  AUTHOR:  Jimmy Patrick
// VERSION:  0.0.01
// PURPOSE:  Controls a Parallel Printer through a PFC8574
//    DATE:  2013-12-18
//     URL:
//
// Released to the public domain
//


#ifndef test_lib_h
#define test_lib_h

#include "Arduino.h"

class test_lib : public Print
{
    public:
        test_lib();
        void printChar(char toPrint);
        void printA();
        void begin();
        size_t write(uint8_t); 
    private:
};
#endif

and this is the .cpp file:

//
//    FILE:  test_lib.cpp
//  AUTHOR:  Jimmy Patrick
// VERSION:  0.0.01
// PURPOSE:  Controls a Parallel Printer through a PFC8574
//    DATE:  2013-12-18
//     URL:
//
// Released to the public domain
//


#include "Arduino.h"
#include "test_lib.h"
#include "Wire.h"



test_lib::test_lib(){
    }
    
    
void test_lib::begin(){
    Wire.begin(0x20);
    pinMode(10, OUTPUT);
    pinMode(11, INPUT);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    delay(200);
    }
    
void test_lib::printChar(char toPrint){
  Wire.beginTransmission(0x20);
  Wire.write(toPrint);
  Wire.endTransmission();
  digitalWrite(10, LOW);
  delayMicroseconds(10);
  digitalWrite(10, HIGH);
  delay(1);
}

size_t test_lib::write(uint8_t c){
  Wire.beginTransmission(0x20);
  delayMicroseconds(10);
  Wire.write(c);
  delayMicroseconds(10);
  Wire.endTransmission();
  delayMicroseconds(10);
  digitalWrite(10, LOW);
  delayMicroseconds(10);
  digitalWrite(10, HIGH);
  delay(1);
  return 1;
}

void test_lib::printA(){
  // initialize the printer
  printChar((byte)0x1B);
  printChar((byte)0x40);
  //print the letter 'A'
  printChar('A');
  //line feed 8 lines
  printChar((byte)0x1B);
  printChar((byte)0x64);
  printChar(8);
  //do the cutting action
  printChar((byte)0x1D);
  printChar((byte)0x56);;
  printChar(49);
  delay(20000);
}

Any ideas?

mixographer:
I have tried to simplify my code so that I can understand it better and find out why it doesn’t work. Here I present my simplified version in case anyone can see my errors.

That is a good approach to get things debugged.

The problem is that my extending of Print class doesn’t do anything.

Does it compile?

void setup()
{
  Wire.begin(); // <<<< add this line ...
  printer.begin();
}

does the printer.begin() need
// initialize the printer
printChar((byte)0x1B);
printChar((byte)0x40);
?
these are in PrintA() but not in print(“B”); code path…

Thanks for looking Rob. I tried adding the initialize printer commands and it didn't change anything. It all compiles fine, but it just doesn't print.

Thanks,

Jimmy

some shortcut, can you try this one ?

size_t test_lib::write(uint8_t c)
{
  printChar(c);
  return 1;
}

Did you resolve your first problem ?

That "deprecated conversion" thing should not be an actual issue. The problem is that in the calling function, you have a specific string literal. But in the called function, you have declared it as char. This means that the called function could try to modify the contents of the array, which of course it should not, because the actual argument is an actual string.

One solution to this, may be to declare the function parameter as const, which mean you cannot attempt to change it.

But although it is "deprecated", it should still actually work.

But when I try to use the library, I cannot compile my ketch because I get the following error:

I am puzzled by this, because the message you say that you got was a warning, not an error.

Thanks michinyon for taking a look. I did get a little distracted by trying to extend ‘Print’ rather than solving my original question. I have a working example now. Part of the problem was in me getting confused and implementing test_lib::write() and then trying to call write() directly. I guess when you use print, you should implement write and call ‘print()’ or ‘println()’ if you are trying to print ascii chars?

so here is the basic library, in a working version. The sketch:

#include <test_lib.h>
#include <Wire.h>

test_lib printer;

void setup(){
  Wire.begin();
  printer.begin();
}

void loop(){
    
    delayMicroseconds(10);
    printer.print('B');      // <----- printer.print!
    printer.println("This is a test of the thermal printing library."); // <----- printer.println, I was using printer.write()
    delayMicroseconds(10); 
     
}

The header:

#ifndef test_lib_h
#define test_lib_h

#include "Arduino.h"
#include <Print.h>

class test_lib : public Print
{
    public:
        test_lib();
        void printChar(uint8_t toPrint);
        void printA();
        void begin();
        //size_t write(uint8_t); 
        size_t write(uint8_t); 
        byte count;
    private:
};

#endif

And the .cpp file:

//
//    FILE:  test_lib.cpp
//  AUTHOR:  Jimmy Patrick
// VERSION:  0.0.01
// PURPOSE:  Controls a Parallel Printer through a PFC8574
//    DATE:  2013-12-18
//     URL:
//
// Released to the public domain
//


#include "Arduino.h"
#include "test_lib.h"
#include "Wire.h"



test_lib::test_lib(){
    }
    
    
void test_lib::begin(){
    Wire.begin(0x20);
    pinMode(10, OUTPUT);
    pinMode(11, INPUT);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    printChar((byte)0x1B);
    printChar((byte)0x40);
    delay(200);
    }
    
void test_lib::printChar(uint8_t toPrint){
  Wire.beginTransmission(0x20);
  Wire.write(toPrint);
  Wire.endTransmission();
  digitalWrite(10, LOW);
  delayMicroseconds(10);
  digitalWrite(10, HIGH);
  delay(1);
}


size_t test_lib::write(uint8_t c){
    printChar(c);
    return 1; 
}

void test_lib::printA(){
  // initialize the printer
  printChar((byte)0x1B);
  printChar((byte)0x40);
  //print the letter 'A'
  printChar('A');
  //line feed 8 lines
  printChar((byte)0x1B);
  printChar((byte)0x64);
  printChar(8);
  //do the cutting action
  printChar((byte)0x1D);
  printChar((byte)0x56);;
  printChar(49);
  delay(20000);
}

Thanks so much Rob and michinyon for taking a look at this with me.

Now I’ll go back and add back in all the formatting options I started with and post this on my github. Here’s a note I printed.

(maybe I don’t know how to attach a photo. )

photo.JPG

Super!
You should now also be able to print bool, char, byte, int & long (BIN, HEX, DEC) and even float variables with n digits.

float PI = 3.14159265;
printer.print(PI, 6);

Now the basics work, you can add the bells and whistles (and optimizations) discussed above.
make printChar & write() one as they are essentially the same.
(and write a test sketch of course)