I got this function from my custom 5110 LCD library which works absolutly fine:
void SCNokia5110::drawString(char *text, int x, int y, bool linebreak)
{
int xi = x;
int yi = y;
int heightBytes = getHeightBytes(activeFont.height);
while(*text)
{
char character = *text++;
byte bitBuffer[20];
for(int i = 0; i < activeFont.width*heightBytes; i++)
{
if(activeFont.fontname == "font_5x3")
{
bitBuffer[i] = pgm_read_byte(&font_5x3[character - activeFont.tableOffset][i]);
}
if(activeFont.fontname == "font_7x5")
{
bitBuffer[i] = pgm_read_byte(&font_7x5[character - activeFont.tableOffset][i]);
}
}
byte *charBitmap = bitBuffer;
drawBitmap(xi,yi,charBitmap,activeFont.height,activeFont.width);
xi += activeFont.width+activeFont.letterSpacing;
if(xi > 83)
{
if(!linebreak)
{
break;
}
yi += activeFont.height+activeFont.lineSpacing;
xi = x;
}
}
}
BUT: to save some RAM I want to provide also an alternative which takes the "F()" macro as an argument instead of "char * text" to save the char array in PROGMEM.
I do not any clue how to rewrite the function starting with how to declare the F() macro as argument etc.
You don't rewrite your existing function, you write a new function that has the same name, but a different parameter list. The compiler is smart enough to figure out which one gets called based on the parameters you pass
The F() macro will give you a const __FlashStringHelper * type for your first parameter
void SCNokia5110::drawString(const __FlashStringHelper *text, int x, int y, bool linebreak)
{
...
I think maybe you don't want to rewrite the function to use an F() parameter, because that would just be duplicated code. I think you want to reuse the function. In other words, make a second function/method which takes a "flash string", turns it into a regular string and then calls the original function.
I've not done this, but I think it would be useful.
I'm going to guess how I think this can be done, hopefully others will correct any errors I make!
void SCNokia5110::drawString(const __FlashStringHelper *text, int x, int y, bool linebreak)
{
char text2[strlen_P(text)+1];
strcpy_P(text2, text);
this->drawString(text2, x, y, linebreak); //correct way to refer to the same SCNokia5110 object?
}
SCNokia5110\SCNokia5110.cpp:358:26: error: cannot convert 'const __FlashStringHelper*' to 'const char*' for argument '1' to 'size_t strlen_P(const char*)'
char text2[strlen_P(text)+1];
^
SCNokia5110.cpp:359:11: error: 'text2' was not declared in this scope
strcpy_P(text2, text);
void SCNokia5110::drawString(const __FlashStringHelper *text, int x, int y, bool linebreak)
{
char text2[strlen_P((const char*) text)+1];
strcpy_P(text2, (const char*) text);
this->drawString(text2, x, y, linebreak); //correct way to refer to the same SCNokia5110 object?
}
F() is also just a (convenience) macro. It casts the result of PSTR into a ‘const __FlashStringHelper *’ so the correct function overloads will pick it up. But the underlying type is ‘const char *’ which is what all the “_P” functions take.
So, your first code in Post #7 is correct.
Personal preference here, but the language is actually C++, I’d use a C++ style cast. And the ‘this->’ notation is superfluous.
void SCNokia5110::drawString(const __FlashStringHelper *text, int x, int y, bool linebreak) {
const char *ptr = reinterpret_cast<const char*> (text);
char text2[strlen_P(ptr) + 1];
strcpy_P(text2, ptr);
drawString(text2, x, y, linebreak); //correct way to refer to the same SCNokia5110 object?
}