Rewrite function to use F() macro

Hi there!

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. :smiley:

Any hints and/or ideas? Thanks in advance! :slight_smile:

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)
{
    ...

You will then have to read the data out of flash PROGMEM - Arduino Reference

1 Like

First hit on a Google search coulda answered the question:

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?
}

Thanks!

Unfortunately I get this error :frowning:


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);

Maybe try this

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?
}

Dumb question time.

Doesn't strcpy_P just end up using RAM anyway - which OP was trying to avoid?

And only one string at a time.

Thanks boys and girls!

Works like a charm with (const char*) :slight_smile: !

1 Like

Please try (PSTR) also.

I tried PSTR but it seems to be not defined?!

SCNokia5110\SCNokia5110.cpp:358:23: error: 'PSTR' was not declared in this scope

  char text2[strlen_P((PSTR) text)+1]; 

I included <arv/pgmspace.h>

:frowning:

Hopefully @Delta_G knows how to fix that.

OK, because text2 only exists while in SCNokia5110::drawString ?

1 Like

PSTR is a macro, not a type you can cast to:

# define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))

I didn't know. But I thought, since you had suggested it, we should try it.

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?
}

dynamic_cast. At a rudimentary level.

There's also const_cast.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.