[SOLVED] Leonardo - selecting Serial or Serial1 at runtime ?

I have a program that will usually run without connection to a PC in which case the serial output should all go to Serial1 where I can read it with an FTDI cable. However some of the time I will need to connect to the PC using the USB port and then all the output should appear on Serial.

Is there some way to create an object that can represent either Serial or Serial1 and which can be selected in setup based on an if (Serial).

I have not found anything helpful with Google - perhaps because I don't know what to search for.

This short program (which will not compile) illustrates the sort of thing I would like to be able to do.

// simple test program for Leonardo to see if I can 
//   select Serial or Serial1 depending on whether Serial is connected

HardwareSerial * aSerial;

void setup() {
 delay(4000); // allow time for rebooting
 Serial.begin(9600);
 Serial1.begin(9600);
 if (! Serial) {
 aSerial = &Serial1;
 aSerial.begin(9600);
 aSerial.println("Hello From Serial1");
 }
 else {
 aSerial = &Serial;
 aSerial.begin(9600);
 aSerial.println("Hello From Serial");
 }
}

void loop() {
 aSerial.println(millis());
 delay(500);
}

While the above code fails to compile for another reason (which I also don't understand) one of the problems seems to be that Serial on a Leonardo is an instance of Serial_ rather than of HardwareSerial.

...R

When a pointer would be used, you might need aSerial->println
It is possible to create an array of them and have aSerial[0].println
However, this would all be good for the Arduino Mega 2560, which has four true hardware serial ports.
For the Leonardo only Serial1 is a hardware serial port. The Serial is not a HardwareSerial object.

I did some hard thinking, but I don't know how to solve this. I think it should be possible.
Creating a new class that selects runtime which one to use for every function would be silly.

Thanks for that. Changing to aSerial->begin() solved the immediate problem.

There still remains the question of getting Serial and Serial1 into the same variable (on different occasions, obviously).

This is the revised code using ->

// simple test program for Leonardo to see if I can 
//   select Serial or Serial1 depending on whether Serial is connected

HardwareSerial * aSerial;

void setup() {
 delay(4000); // allow time for rebooting
 Serial.begin(9600);
 Serial1.begin(9600);
 if (! Serial) {
 aSerial = &Serial1;
 aSerial->begin(9600);
 aSerial->println("Hello From Serial1");
 }
 else {
 aSerial = &Serial;
 aSerial->begin(9600);
 aSerial->println("Hello From Serial");
 }
}

void loop() {
 aSerial->println(millis());
 delay(500);
}

Now the error message is

SerialTest.ino: In function ‘void setup()’:
SerialTest:16: error: cannot convert ‘Serial_*’ to ‘HardwareSerial*’ in assignment

...R

Do it like this:

Stream *mySerialPort;
...
mySerialPort = Serial;
Serial.println("Hellp, world!\n);  // Prints to Serial
mySerialPort = Serial1;
Serial.println("Hellp, world!\n);  // Prints to Serial1

If you're using only Serial ports, and not other kinds of devices, you can use HardwareSerial instead of Stream. Print will also work.

Regards,
Ray L.

If you're using only Serial ports, and not other kinds of devices, you can use HardwareSerial instead of Stream. Print will also work.

Except that on the Leonardo, Serial1 is not an instance of HardwareSerial. It is an instance of Serial_, which derives from Stream, the same as HardwareSerial does.

PaulS:
Except that on the Leonardo, Serial1 is not an instance of HardwareSerial. It is an instance of Serial_, which derives from Stream, the same as HardwareSerial does.

No, Serial is an instance of Serial_, Serial1 is HardwareSerial.

Why, oh why, isn't there a base class for all serial classes?

As you have discovered, you can use a pointer, but it will have to be of a more primitive type, Stream. Stream does not know about begin et al, so you could downcast if you remember which derived class you're using. Then you've got noisy tests and conditional casting. :frowning:

Instead, you could use a wrapper class that provides the polymorphism you seek: AnySerial.

Cheers,
/dev

Why, oh why, isn't there a base class for all serial classes?

There is. It's Stream. I know, I know, that's not what you meant...

RayLivingston:
Do it like this:

Thanks Ray,

With a minor modifcation your suggestion works. I needed to change it to
mySerialPort = &Serial;

Here is the working demo

// simple test program for Leonardo to see if I can 
//   select Serial or Serial1 depending on whether Serial is connected

Stream * aSerial;

void setup() {
	delay(4000); // allow time for rebooting
	Serial.begin(9600);
	Serial1.begin(9600);
	if (! Serial) {
		aSerial = &Serial1;
		aSerial->println("Hello From Serial1");
	}
	else {
		aSerial = &Serial;
		aSerial->println("Hello From Serial");
	}
}

void loop() {
	aSerial->println(millis());
	delay(500);
}

...R

I think it is possible to have a template for a reference with a object with a pointer inside (something like that) that would allow aSerial.println instead of aSerial->println

The AnySerial is an object that can pass calls on to any of the serial libraries, but it can not do that for all types in the same sketch ?

Koepel:
I think it is possible to have a template ...

I suspect I would be out of my depth. I prefer to swim in the shallow end of the C/C++ pool. :slight_smile: :slight_smile:

...R

but it can not do that for all types in the same sketch ?

Is that a question? It can "do that" for all types included before AnySerial.h.

It was a question. Okay, now I see, everything can be included. That was not obvious to me at the first glance. The "port_type" selects runtime the library to which the function call is passed on to. I'm afraid I called that "silly" in my Reply #1, but someone has made it.

PaulS:
There is. It's Stream. I know, I know, that's not what you meant...

Nick Offerman glare.jpg