0

I am trying to modify this class so that I can use both SoftwareSerial and HardwareSerial objects. I therefore added a constructor that takes in a Stream object, the superclass of both Software and HardwareSerial:

/**
 * Instantiates an SBUS object
 * @param Stream* A HardwareSerial or SoftwareSerial object pointer
 */
SBUS::SBUS(const Stream *serialPort){
    port = serialPort;
}

Unfortunately, in the SBUS::begin() method I must call port->begin(BAUDRATE), and although begin() exists as a method in both subclasses, because it is not in the Stream superclass, I cannot call it.

How can I call port->begin()? I have tried to call begin() on the Hardware or SoftwareSerial object externally in between SBUS construction and the SBUS::begin() method, but this does not seem to initialize the SBUS object properly. Is there a way to call begin() from inside the SBUS class?

I greatly appreciate any help. (FUTABA_SBUS was changed to SBUS for ease of programming)

abeta201
  • 233
  • 1
  • 14
  • What is the exact problem when you try to call `port->begin()` in `SBUS::begin()`? The `const` in the constructor looks fishy. –  Jan 20 '18 at 08:16
  • I didn't even notice the const! But unfortunately that's not the issue. Even when I remove it I get this error: `'class Stream' has no member named 'begin'`. – abeta201 Jan 20 '18 at 08:22
  • That compiler error is correct, since the `Stream` class [doesn't have such function](https://www.arduino.cc/reference/en/language/functions/communication/stream/), so why do you think you need it? –  Jan 20 '18 at 08:27
  • Exactly. I agree with the compiler here (In my original question: "it is not in the *Stream* superclass"). However, I need to initialize my *SoftwareSerial* and *HardwareSerial* objects with some baud rate inside the SBUS class, and I am unsure of how to do so, since I cannot initialize Stream objects. – abeta201 Jan 20 '18 at 08:31
  • Maybe set the baud rate before you construct the SBUS object? – john Jan 20 '18 at 08:34
  • Well, the answer is simple, add an according function to the class hierarchy, so you can call it. If that makes your design any better, I don't know, I have my doubts though. – Ulrich Eckhardt Jan 20 '18 at 08:37
  • @john In my situation I do not believe I can. The baud rate can only be set in the `setup()` or `loop()` functions in the Arduino script, but SBUS must be executed afterwards. I need a global SBUS scope, but this confines me to local scopes, in the `setup()` or `loop()` functions. – abeta201 Jan 20 '18 at 08:38
  • @Ulrich Eckhardt I guess I'm afraid of messing with the stock Arduino library, and unsure of how to implement a modified library in my program. I was hoping for a different way of doing this, but if that's my only option... – abeta201 Jan 20 '18 at 08:41

2 Answers2

2

static_cast because for dynamic_cast you have to enable RTTI

bool hwSerial;
Stream * port;
SBUS::SBUS(SoftwareSerial * serial)    {hwserial = false; port = serial;}
SBUS::SBUS(HardwareSerial * serial)          {swserial = true;  port = serial;}

Then you can do something like this: 
SBUS::portBegin(long baudrate) {
if(hwserial) {
  static_cast<HardwareSerial*>(port)->begin(baudrate);
} else {
  static_cast<SoftwareSerial*>(port)->begin(baudrate);
}
1

There are some possibilities:

  • Initialize the Serial before passing it by a pointer

  • You can add coresponding method to the Stream class and make it virtual

    virtual begin(long x) {}

so that the compiler stops complaining and uses the correct method for the object.

  • Pass a pointer to the correct begin(..) method to your constructor, save it and call it whenever you like
  • You can create multiple constructors(likely the best solution):

    bool hwSerial; Stream * port; SBUS::SBUS(SoftwareSerial * serial) {hwserial = false; port = serial;} SBUS::SBUS(HWSerial * serial) {swserial = true; port = serial;}

    Then you can do something like this: SBUS::portBegin(long baudrate) { if(hwserial) { static_cast<HWSerial*>(port)->begin(baudrate); } else { static_cast<SoftwareSerial*>(port)->begin(baudrate); } --EDIT-- Corrected, dynamic -> static cast

Martin
  • 333
  • 1
  • 8
  • 1
    You're right; creating multiple constructors is the best solution, although as @Oleg Moiseenko pointed out, a `static_cast` must be used, since the Arduino AVR compiler does not support `dynamic_cast` without enabling RTTI, which is probably a bad idea. – abeta201 Jun 23 '18 at 22:01