variable for "xxx".available()?

I have a program that will read from 2 different serial ports. The receive() function is almost identical for both of them, the only difference is really the serial port to read from and to check. Is there a way to make this serial port a variable so I don't have to duplicate code? Using define and macros maybe? This is my code:

bool Data::receive(){
  static byte const syncByte = 204;              // actual value of sync byte
  static byte msgLen;                            // length of message
  static byte cmdByte;                           // command byte
  static byte recvdSyncByte = 0;                 // first byte read from fuze setter
  
  static bool receivedString = false;            // check received full string
  static bool recvMsgLen = false;                // check received message length

  // if the at least 3 bytes are available in the serial buffer
  
  if (teensy.available() >= 3 && !recvMsgLen) {

    recvdSyncByte = teensy.read();           // read possible sync byte

    if (recvdSyncByte == syncByte) {             // does recvdSyncByte equal 0xCC?
      teensyBuffer[0] = recvdSyncByte;           // save sync byte to buffer
      for (int i = 1; i < 3; i++)                // save command and msglen bytes to buffer
        teensyBuffer[i] = teensy.read();

      cmdByte = teensyBuffer[1];                 // save command byte
      msgLen = teensyBuffer[2];                  // save length of message
      recvMsgLen = true;                         // set received to true so this code only executes once
    }
  }


  // read rest of hexstring if there was a message
  if (recvMsgLen && msgLen > 0 && !receivedString && (teensy.available() >= msgLen + 1)) {

    for (int i = 1; i <= msgLen + 2; i++)       // save the message and CRC bytes to buffer
      teensyBuffer[i + 2] = teensy.read();      // read until last CRC bit, calculated from msgLen -byte

    teensyBufferSize = msgLen + 4;              // saves the length of the message
    receivedString = true;                      // received message
  }
 
  /*
  // timeout if no message received
  if ( recvMsgLen && !receivedString && timeoutTimer.current() >= timeoutTimer.period() ) 
    emptyBuffer();
  */

  if(receivedString)                    // return true if data has been received
  {    
    receivedString = false;
    recvMsgLen = false;               
    return true;
  }
  else
    return false;
}

So if you look at the "if(teensy.available() >= 3 && !recvMsgLen)" statement, you will see that the only thing I need to do is make "teensy" be a variable so that I could make it equal something else. I know this doesn't work, but is there any thing I can do in a good way here so I don't duplicate code?

thanks.

Which board are we talking about? If we talk about something like a Mega you can use HardwareSerial as a type.

But I guess it's a Teensy variant. Not to familiar with Teensy so not sure if it applies to all of them, but they use different types of serial for the different serial ports. Which makes it a bit harder.

Do want it to compile for different serial ports or do you want to switch on runtime / have multiple objects for different serial ports?

I see, thanks for answering!

septillion:
Do want it to compile for different serial ports or do you want to switch on runtime / have multiple objects for different serial ports?

I'm using a Teensy 3.6. It has access to it's serial ports using Serial1, Serial2 ... etc. I want to have multiple objects that will have different serial ports, but running basicly the same code.

Yeah, I see. That is the hardest thing.

Only way I can think of is something like (example for a class supporting HardwareSerial and SoftwareSerial):

#include <SoftwareSerial.h>

class Test{
  protected:
    HardwareSerial *_HWSerialP;
    SoftwareSerial *_SSerialP;
  public:
    Test(HardwareSerial &p):
      _HWSerialP(&p),
      _SSerialP(nullptr)
    {
      ;
    }
    Test(SoftwareSerial &p):
      _HWSerialP(nullptr),
      _SSerialP(&p)
    {
      ;
    }
    int available(){
      if(_HWSerialP){
        return _HWSerialP->available();
      }
      else if(_SSerialP){
        return _SSerialP->available();
      }
      else{
        return -2;
      }
    }
};

SoftwareSerial mySerial(10, 11); // RX, 

Test HWTest(Serial);
Test STest(mySerial);


void setup() {
  // put your setup code here, to run once:
  HWTest.available();
  STest.available();

}

void loop() {
  // put your main code here, to run repeatedly:

}

Other way would be to use template classes but that's another can of worms.

I have a feeling you can just pass a pointer (or reference) to a stream class object. But, you didn't bother to post your full code so I can't see how your variables are defined. Post your code properly, PER THE FORUM GUIDELINES, and you'll get a more complete answer.

Uhm, yeah... I was under the impressing available() wasn't part of Stream... Must be confusing it with begin()...

For an AVR Uno:

class Stream : public Print
{
  protected:
    unsigned long _timeout;      // number of milliseconds to wait for the next char before aborting timed read
    unsigned long _startMillis;  // used for timeout measurement
    int timedRead();    // read stream with timeout
    int timedPeek();    // peek stream with timeout
    int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout

  public:
    virtual int available() = 0;   // <------------------------------------
.
.
.

And on a Teensy platform:

class Stream : public Print
{
  public:
 constexpr Stream() : _timeout(1000), read_error(0) {}
 virtual int available() = 0;  // <----------------------------------------------
.
.
.

Yeah, noticed :frowning:

Aka, just make a pointer/reference to a Stream object.

class BetterTest{
  protected:
    Stream &_port;
  public:
    BetterTest(Stream &p):
      _port(p)
    {
      ;
    }
    int available(){
      return _port.available();
    }
};