Code Help - Serial Port & Passing by Ref

I am building a Library for a serial device, but I want to rely on the “serialEvent” callback.

So basically I want to move all the serial code to its own object. I have seen libraries that pass by value the serial port upon instancing it in the main cpp file. But I haven’t seen how I can pass to my objet the “Serial” object and the “serialEvent” from the main cpp file to my file (Object).

Can someone point me in the right direction and if you think this is appropriate.

If you only need to print to the port, make the parameter to your library a Stream&. You can pass Serial, Serial1, etc. and it will be cast to a Stream and you can call println, printlnf, etc. on it.

If you need change settings like baud rate, use USARTSerial&. Note, however, that you can’t pass Serial (the USB serial port) because that’s a USBSerial&. Both have Stream as a base class.

I wouldn’t try to use serialEvent from a library. I’d just make a loop method in your library and call it from your actual loop and check the serial port from your library using available().

1 Like

Thank you so much.

I need to read and write from the library.

How will the loop not make it blocking to the rest of the firmware ?

You need to return from your library loop as quickly as possible, presumably after you’ve read all of the serial data. It would work just like the real loop function.

Take a look at this, which has a class member that is continuously looking for new serial data:

ino

#include "SerialMessenger.h"

template <class T> inline Print& operator <<(Print& obj, T arg)
{
  obj.print(arg);
  return obj;
}

void parseMessage(const char* mssg);

SerialMessenger myDevice(Serial, 16, '\n');

void setup()
{
  Serial.begin(9600);
  myDevice.begin(parseMessage);
  //myDevice.begin([](const char* mssg){Serial.println(mssg);});
  //myDevice.begin();
  Serial << ("Let's Go!\n");
}

void loop()
{
  myDevice.process();
}

void parseMessage(const char* mssg)
{
  Serial << mssg;
}

header:

#ifndef SERIALMESSENGER_H
#define SERIALMESSENGER_H

#include "Application.h"

class SerialMessenger {
  public:
    SerialMessenger(Stream& strm, size_t bufferSize, char endMarker) : stream(strm), bufSize(bufferSize), marker(endMarker) {}

    ~SerialMessenger(void);
    void begin(void);
    void begin(void(*action)(const char*));
    const char* process(void);
    char* checkForMessages(void);
  private:
    Stream& stream;
    size_t bufSize;
    char* incomingMessage;
    char marker;
    byte idx;
    void(*callback)(const char*);
};

#endif

implementation:

// SerialMessenger

#include "Application.h"
#include "SerialMessenger.h"

SerialMessenger::~SerialMessenger() {
  delete[] incomingMessage;
}
void SerialMessenger::begin()
{
  incomingMessage = new char[bufSize];
  incomingMessage[0] = '\0';
}

void SerialMessenger::begin(void(*action)(const char*))
{
  callback = action;
  begin();
}

const char* SerialMessenger::process()
{
  if (const char* newMessage = checkForMessages())
  {
    if (callback)
    {
      callback(newMessage);
      return nullptr;
    }
    else
    {
      return newMessage;
    }
  }
  return nullptr;
}

char* SerialMessenger::checkForMessages()
{
  if (stream.available()) {
    incomingMessage[idx] = (char)stream.read();
    if (incomingMessage[idx] == marker) {
      incomingMessage[idx] = '\0';
      idx = 0;
      return incomingMessage;
    }
    else {
      idx++;
      if (idx > bufSize - 1) {
        //stream.print(F("{\"error\":\"message too long\"}\n"));  //you can send an error to sender here
        idx = 0;
        incomingMessage[idx] = '\0';
      }
    }
  }
  return nullptr;
}
1 Like

I have a long way to learn! :slight_smile: