StreamHandler - an OOP example

Continuing the discussion from StreamHandler - an OOP example:

Haven't look through all your code's details, but ...

Make your life easy, go with a C++ alias and avoid the syntactic jumble of C-style function pointer defintions:

    //void (*func)(char*);
    using functPtr = void (*)(char *);
    const functPtr func;

That's straightforward, there's only one type of C++ reference ... a reference to a "thing". That "thing" can be const or non-const. But once bound to the "thing", the reference variable itself can never be changed during its lifetime to bind to different "thing". So it's const by definition. So:

template <typename T>
class theClass {
  public:
    theClass(const T &v) : var(v) {}

  private:
    const T &var;
};

It's for the parameter, so it would be like void (*func)(const char*);

if the intended use is to allow for strtok() then of course don't use const.

My remark was coming from the fact that some libraries accept have functions like
bool parse(char * message) {...}
and don't modify the message and when you try to call them with parse("x=42"); then on AVR it does not care too much and you get a warning that a const char * (the string literal) cannot be transformed into a char * but it still compiles whilst on the ESP32 the compiler will complain and handle the warning as a bug and fail to compile. This forces you to declare your string in a buffer which eats up RAM when it could happily have been into the flash memory.

The original question was ambiguous as to which pointer was intended not to be changed. I read it as he didn't want the function pointer's value itself to be changed.

Hence, my answer:

Yes - unsure what @Delta_G meant

OK got it. Then const is not such a good idea in the end :slight_smile:

Seems the comment is wrong there

What about adding error detection? Using strtol() would be better than atoi() to catch a mismatch

Ok

As parsing various formats is frequent I could foresee an option to have the equivalent of sscanf() where you pass the format and the pointers to storage and have this part of the “library”

Sounds like a good idea

1 Like

Just missing the wokwi :slight_smile: for easy testing

yeah just an arduino and your code.

I uploaded your code into wokwi there

the Serial monitor is super chatty though

**** Starting StreamHandler.ino **** 


<Time is 1000
><ZCUSTOM - 4!><#60><#54><#51><#50><#49><#47><#49><#46><#48><#52><#50><#46><#44><#43><#42><#39><#36><#33><#34><#40><#41><#47><#44><#45><#47><#43><#48><#43><#40><#45><#47><#49><#45><#50><#54><#58><#61><#65><#64><#68><#69><#71><#69><#71><#65><#61><#59><#58><#59><#60><#56><#58><#55><#50><#48><#45><#43><#44><#45><#51><#49><#52><#49><#54><#58><#57><#52><#48><#49><#44><#48><#50><#47><#52><#51><#55><#50><#51><#48><#49><#47><#42><#46><#43><#48><#52><#49><#45><#42><#44><#49><#45><#47><#45><#49><#54>...

so it's hard to enter anything and see the outcome

:wink:

may be separate examples focusing on one feature would be better

kind of you :slight_smile:

I think the word Stream and Parse in the same sentence would scare them away :slight_smile:

understood

wokwi can't do 2 arduinos - so the human and Serial monitor would play the other Arduino

it's pretty nice when you want to validate code with a few simple components and share that (it's not an electronic simulator)

yes it's pretty easy. adding components and wires is easy too. What' more involved is created your own new components.

it does not work for me.

did you click save and then copied the URL from the share button ?

adding a few Serial.print() in your callbacks could also help confirm what's going on.


PS/ in the diagram.json tab there is a field

  "author": "Anonymous maker",

you might want to add Delta_G there

what exact text do you provide in the Serial monitor?

ah - I did not realize your needed the markers <xxx>

it does work!

Add shared GND too.

1 Like

Have you considered to make STREAM_HANDLER_BUFFER_SIZE be a template argument of class StreamHandler? That would allow for more flexibility when instantiating the StreamHandler(s) to match the needs on the platform. (#define are not so great as you basically need to modify the library if you want to change the size. Also I would make all those #define typed constexpr just to give more hint to the compiler).

for these parsers

template<> int Parser<int>::parse(char* str)                     {return strtol(str, NULL, base);}
template<> unsigned int Parser<unsigned int>::parse(char* str)   {return strtoul(str, NULL, base);}
template<> long Parser<long>::parse(char* str)                   {return strtol(str, NULL, base);}
template<> unsigned long Parser<unsigned long>::parse(char* str) {return strtoul(str, NULL, base);}
template<> float Parser<float>::parse(char* str)                 {return atof(str);}
template<> double Parser<double>::parse(char* str)               {return atof(str);}

as they don't modify the str parameter you should consider making them const and instead of atof() which does not allow for catching errors you could use strtod()