Quick way to get Serial.print(PSTR("...") to work

There have been a couple of posts on the forum concerning this already, but I couldn't find any truly explicit means of doing the following:

Serial.print(PSTR("Test!"));

Serial output:

Test!

I looked around at the PROGMEM documentation and found a couple of helpful tutorials around the net that resulted in a quick and dirty way to get something similar to the above example to work. It requires making a few simple changes to HardwareSerial.cpp and HardwareSerial.h. I'm sure this has been done before, but perhaps this will be beneficial to some.

Modify HardwareSerial.h to look like so (note, this just shows the class, not the entire .h file):

class HardwareSerial
{
  private:
    //uint8_t _uart;
    void printNumber(unsigned long, uint8_t);
  public:
    HardwareSerial(uint8_t);
    void begin(long);
    uint8_t available(void);
    int read(void);
    void flush(void);
    void print(char);
    void print(const char[]);
    void print(uint8_t);
    void print(int);
    void print(unsigned int);
    void print(long);
    void print(unsigned long);
    void print(long, int);
    void println(void);
    void println(char);
    void println(const char[]);
    void println(uint8_t);
    void println(int);
    void println(unsigned int);
    void println(long);
    void println(unsigned long);
    void println(long, int);
    void printp(const char*); //add this guy
};

Basically, just add the public member function: void printp(const char*)

now, add the following function to HardwareSerial.cpp:

void HardwareSerial::printp(const char *data)
{
   while(pgm_read_byte(data) != 0x00)
       print(pgm_read_byte(data++));
}

Also, in HardwareSerial.h make sure to add:

#include <avr/pgmspace.h>

Now, in the main body of your sketches, if you want to use PSTR() to print to the serial monitor (hence saving RAM), you can do it like so:

Serial.printp(PSTR("Test!"));

This is no catch-all, as any programmer can probably see. Currently, it works well with inline strings and such, which is what hogs up the RAM on a lot of my programs. I wouldn't recommend it for anything else, though (because I doubt it works!). So, there you go, a quick and dirty way to get those inline strings you've moved to flash memory to print to the serial monitor. I would ultimately like to see a Serial.print() that can recognize this without the need to create another member function. Perhaps this has been done and I just can't find it?

Unfortunately, I tried a similar approach with SoftwareSerial to no avail. This would benefit me at least, as I print to LCD screens and the like often in my programs. Does anyone have any suggestions for this?

Thanks,
EH

I like it, couple thoughts:

  1. should it be:
    print(prog_uchar *data) and
    println(prog_uchar data) ? (instead of printp(const char))

  2. how much extra space does it take?

I'm sure we could go on and on about progmem and how best to support it, for example I think all consts should be in flash by default, but you basically need a new language for that to happen.

I would however consider simple string support like this unit to be progress.

dcb--

I too like the general notion of adding a print(prog_char *) method, but there are technical problems. As you probably discovered, prog_char * isn't sufficiently different from char * is gcc, so you get a redefinition error when adding print(prog_char *). Adding print(prog_uchar *) is well and good, but when you do:

Serial.print(PSTR("Hi Mom"));

it will call the print(char *) version and not the print(prog_uchar *) one.

Sigh!

Mikal

Yup annoying..

Using your own definition of PSTR can "help", but plenty of caveats (have to use unsigned to differentiate):

#include <avr/pgmspace.h>

define PSTR2(s) (extension({static unsigned char __c[] PROGMEM = (s); &__c[0];}))

prog_uchar signMessage[] PROGMEM = {"Hello World"};

void setup(){
Serial.begin(9600);
print(signMessage);
print(PSTR2("Hi Mom"));
}

void loop(){}

void print(prog_uchar *data){
while(pgm_read_byte(data) != 0x00)
Serial.print(pgm_read_byte(data++));
}

  1. should it be:
    print(prog_uchar *data) and
    println(prog_uchar data) ? (instead of printp(const char))

So...like I mentioned this was a pretty quick and dirty process. I started with the const char* because from what I read I inferred that PSTR() returned a pointer to the location of the first byte used for the string in flash memory. I used that along with pgm_read_byte to use the built in print() function of HardwareSerial.

I can't comment much on your question except to say that I did it using const char * and it worked. I'm so busy with coursework at the moment (this even, was done to quickly get HardwareSerial to work so I could carry on with a robot project I'm working on for a course. ) I didn't have time to sample a lot of alternatives. I tried something, it worked, so I moved on.

However, I would like to go back and rewrite it per your suggestion to see what differences arises (it seems like your suggestion should work, no problem, though...). I will probably investigate this during the upcoming winter break in a couple of weeks. I'll let you know what I discover if you haven't tried it for yourself by then.

  1. how much extra space does it take?

Seeing as the whole point of doing this was to use PSTR() for the purpose of conserving resources, I should know the answer to this question. Unfortunately, I don't....I'm pretty much coming down to the wire on this, so if something works I usually move on without much in-depth analysis. This is terrible practice, but when it's down to the wire, quick and dirty usually wins the race.

This is something I'll definitely look into when my winter break comes up.

Thanks for the comments, guys. If anyone knows a way to get similar results using SoftwareSerial, let me know. This is something I'll end up trying soon...especially if I find that I'm running out of RAM otherwise!

EH