Console Redirection - Serial or Ethernet

I have a "console" application for which I would like to be able to switch the console port between Serial and Ethernet. For debugging, it is easier to use a Serial connection, while the final application will use Ethernet. I would like to just have a run-time switch to select which interface is active. Since both are based on Stream and Print classes, I thought I could get away with using a pointer to the device, along the lines of:

Stream *pConsole;

setup() { .... if (UseEthernet) pConsole = EthernetServer(23); else pConsole = Serial; .... }

loop() { .... pConsole.println("Hello"); .... }

This, of course, does not work, since Stream and Print are both virtual classes. What is the right way to accomplish this?

Regards, Ray L.

This, of course, does not work, since Stream and Print are both virtual classes. What is the right way to accomplish this?

The right way is to post ALL of your code, any error messages, and an explanation of what "this does not work" means.

Paul,

I don't HAVE code. That is why I am asking HOW to do it. I can't do what I suggested in the bit of code I posted, because Stream is a virtual class, so I can't create an instance of a Stream class object without getting the error "cannot declare variable 'fred' to be of abstract type 'Stream'".

Here is a more explicit example of what I'd like to do, but don't know how to do:

Assume a class named Shape. Assume a class named Square, which is derived from Shape Assume a class name Circle, which is derived from Shape

I want to be able to do something like this:

Shape *SomeShape;

SomeShape = new Square(); SomeShape->Draw(); SomeShape = new Circle(); SomeShape->Draw();

Now replace Square with Serial, and replace Circle with EthernetServer.

I want to be able to reference EITHER the Serial0 object, or an EthernetServer object via a common reference, so I can decide, at run-time whether I will be communicating via RS232 or some Ethernet protocol. Simple enough if both are derived from some common physical base class, but not so simple when both appear to be derived from a common virtual base class.

Regards, Ray L.

Assume a class named Shape.
Assume a class named Square, which is derived from Shape
Assume a class name Circle, which is derived from Shape

I want to be able to do something like this:

Shape *SomeShape;

SomeShape = new Square();
SomeShape->Draw();
SomeShape = new Circle();
SomeShape->Draw();

You should be able to do:

Square *s = new Square();
s->Draw();
Circle *c = new Circle();
c->Draw();

SomeShape *blob = c;
blob->Draw();

Try that when Shape is a virtual class. You'll get the error "cannot declare variable 'SomeShape' to be of abstract type 'Shape'" when you try to compile it. This is the whole problem I'm having. I cannot create a pointer or reference to an object of class Stream, or Print, or any other common base class of Serial and EthernetServer that gives me access to the methods I need (print println, etc.).

Regards, Ray L.

Serial and EthernetServer are both descended from the Stream class. All descendants have type equivalency with their base. So, you can assign an instance of a descendant, to a pointer to type base, then call the virtual methods of the base class which the descendant has implemented.

This is off the top of my head but hopefully it will point you in the right direction. You might need to add an ampersand or two.

Stream* pConsole;

setup() {
    if (UseEthernet)
        pConsole = (Stream*) EthernetServer(23);
    else
        pConsole = (Stream*) Serial;
}

loop()
{
    ....
    pConsole->write("Hello\r\n");
    ....
}

This at least compiles:

#include <Arduino.h>
#include <EthernetServer.h>
#include <Server.h>
#include <Stream.h>
#include <SPI.h>

EthernetServer server(80);

Print *s;

int a = 3;

void setup()
{
  if(a == 3)
    s = &Serial;
  else
    s = &server;
}

void loop()
{
  s->print("something");
}

PaulS:
This at least compiles:

Why dit take u so long :smiley:

Thanks, guys. I have a test program that mostly works.... The piece I was missing was the explicit cast to (Stream *) when assigning to the pointer.

I've got something that mostly works, but it's not as clean as I'd hoped due to the fact that available() for Stream returns the number of characters waiting, while for EthernetServer it returns an EthernetClient object, and you then do a read() from the client. So, I can't just do, for example, Console->read(). print and println work fine.

Regards, Ray L.