how to alias to Serial, or to redeclare with another name?

I want to ultimately be using hardware serial to talk to my bluetooth transceiver. In the meantime, though, I have mostly nanos around, and it's clear that they will not be able to attach to the UART pins with the USB circuitry on board.

So to make my design flexible and code readable, I want to be able to have simple statements like

btSerial.println("Some random message")

rather than

#ifdef useBtHarwdwareSerial
serial.println("Some Random Message
#else
btSerial.println("Some random message")
#endif

so I would have btSerial and monSerial for the bluetooth and the serial monitor line (if used).

I've tried but failed so far to use a pointer to Serial:

//sort out the consequences ofthat choice

#ifdef useSoftwareSerial

#include <SoftwareSerial.h>
//we want an softserial. Use the rx=D8 and TX=D9 for hardware ease
#define usingSoftSer
const srlTyps btTyp = SOFTSERIAL, dbgTyp = HARDWARE;
SoftwareSerial btSerial (8, 9);

#elif defined(useAltSoftSerial)
//we want an altsoftserial. On nano, rx=D8 and TX=D9
#include <AltSoftSerial.h>
AltSoftSerial btSerial;
#define usingSoftSer
const srlTyps btTyp = ALTSOFTSERIAL, dbgTyp = HARDWARE;


#else                                                                                 //  <- this is the branch taken
//we wll use the hardware serial for AT-09
#define useHardSer
//make btSerial an alias for Serial, so that we don't have t fll the code with ifDefs

 const  HardwareSerial * btSerial = &Serial;                            //  <- this is my attempt to define


// HardwareSerial  * btSerial = &Serial; this declares,but btSerial doesn't get a 'begin' type

const srlTyps btTyp = HARDWARE;

. . .

#endif

That section compiles, but the I hit the line

//set up the bluetooth serial.  this should work for all three
  btSerial.begin(9600);

the err is

In function 'void setup()':
at09_8:120: error: request for member 'begin' in 'btSerial', which is of pointer type 'const HardwareSerial*' (maybe you meant to use '->' ?)
   btSerial.begin(9600);

Is this my lack of experience/understandng with C++, or am I trying something impossible?

As I understand it, the declaration of Serial as an instance of HardwareSerial must come in some automatically included headers. Is there a way to override or "re declare" this?

I've tried

In function 'void setup()':
at09_8:120: error: request for member 'begin' in 'btSerial', which is of pointer type 'const HardwareSerial*' (maybe you meant to use '->' ?)
   btSerial.begin(9600);

but get

t09_8:46: error: no matching function for call to 'HardwareSerial::HardwareSerial()'
 HardwareSerial btSerial;
                ^
In file included from /Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/Arduino.h:232:0,
                 from /var/folders/zw/80mmg8352gqb2ldt_d0k9qhr0000gn/T/arduino_build_918460/sketch/at09_8.ino.cpp:1:
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:117:12: note: candidate: HardwareSerial::HardwareSerial(volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*)
     inline HardwareSerial(
            ^
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:117:12: note:   candidate expects 6 arguments, 0 provided
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:93:7: note: candidate: constexpr HardwareSerial::HardwareSerial(const HardwareSerial&)
 class HardwareSerial : public Stream
       ^
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:93:7: note:   candidate expects 1 argument, 0 provided
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:93:7: note: candidate: constexpr HardwareSerial::HardwareSerial(HardwareSerial&&)
/Users/hawk/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/HardwareSerial.h:93:7: note:   candidate expects 1 argument, 0 provided
exit status 1
no matching function for call to 'HardwareSerial::HardwareSerial()'

hawk

I use this a lot:

#define MON     Serial.print
#define MONln   Serial.println

But I'm a big fan of short cryptic mnemonics from assy language days.

As the error message said:

maybe you meant to use '->' ?

(Can you make a global xxx a "reference" in C++, like you can do with function parameters?

HardwareSerial  &btSerial = Serial;  //or something

Although, as the other old guy said, this is a time when preprocessor macros are likely to work better than a C/C++ construct:

#ifdef useSoftwareSerial
// :
SoftwareSerial btSerial (8, 9);
#define realSerial btSerial
#elif defined(useAltSS)
// :
#define realSerial btSerial
#else
// HardwareSerial
#define realSerial Serial
#endif

Thank you.

Those arrows always bothered me :slight_smile: I'll mumble something incoherent now about c++ being nothing but a preprocess to the c compiler the first time I dealt with it, and hope no-one realizes what that says about my age . . .

And with that, the pre-processing seems to be easily the cleanest.

And now I'll take another look at my settings. I thought it was supposed to be defaulting to notifying me, but I'm still having to manually turn them on (and in one or two cases, I think I've had to do it twice!)

Unless I'm missing something (which is probably the case; I can never remember much more c than the scoping rules [which I want in all other languages] after I stop using it, and I've lost track of the number of times I've learned c or c++ again . . .) , that doesn't work.

As written, this compiles and executes, noting "usHardSerialDebug" in the monitor.

//if neither of these is defined, assume hardware fo bluetooth serial
//#define useSoftwareSerialBt
#define useAltSoftSerialBt
#if (!defined(useAltSoftSerialBt)) & (!defined(useSoftwareSerialBt))
#define useHardwareSerialBt
#endif

#if (!defined(useAltSoftDebug) ) && !defined(useSoftSerDebug)  && !defined(noDebugLine)
#define useHardSerialDebug
#endif

//types we'll need

enum srlTyps {
  NONE, HARDWARE, SOFTSERIAL, ALTSOFTSERIAL
};


void setup() {
  Serial.begin(9600);
  Serial.println("starting setup");

#if (!defined(useAltSoftDebug)  && !defined(useSoftSerDebug)  && !defined(noDebugLine))
  Serial.println("hardserial section");
#define useHardSerialDebug
#endif

  //now for the hardware serial assignment
#if defined( useHardwareSerialBt) || defined(useHardSerialDebug)
  //using hardware serial for something

  //flag that we're using a hardserial

#define usingHardwareSerial
  Serial.println("defining usingHardwareSerial ");


  //now alias it
#ifdef useHardwareSerialBt
  const srlTyps btTyp = HARDWARE;
#define btSerial= Serial;
#else
  const srlTyps monTyp = HARDWARE;

  Serial.println("defining monserial ");
#define monSerial Serial;
#endif


#endif   //altsoftserial aliases




#ifdef useHardSerialDebug
  Serial.println("useHardSerialDebug");
  //monSerial.println("this line causes compile eror");
#endif
}

void loop() {}

But if I uncomment the fourth line from the bottom, it fails.

Getting back to my minimal c, shouldn't that line become

Serial.println("this line causes compile eror");

when preprocessor is done with it and before the compiler sees it?

Or does it rather sea "monSerial.println" as a potential target, rather than the two words of the expression as separate targets for replacement?

edit: this seems to work

// now a device to send monitor messages

#if dbgTyp==HARDWARE
HardwareSerial &monSerial = Serial;
#elif dbgTyp==ALTSOFTSERIAL
AltSoftSerial monSerial;
#elif dbgTyp==SOFTSERIAL
SoftwareSerial monSerial;
#else dbgTyp==NONE
//there is no monitor, so make an empty class for it
//   all the calls shoudl get optimized out by the compiler

class nullSerial {
    void begin(void);
    void printn(void);
    void print(void);
    int available();
    void read(void);
    void write(void);
    void end(void);
}
nullSerial monSerial;
#endif
  Serial.println("defining monserial ");

#define monSerial Serial;

This looks like a misunderstanding in when the #define takes effect. Anything beginning with # is a preprocessor directive. That means it is executed by the preprocessor BEFORE the program is compiled BEFORE the program runs. So "defining monserial" is printed days or years after monSerial was defined.

The preprocessor doesn't follow the C scope rules either. It's more like a simple text processor. It has no idea that { and } have special meaning. So you can #define something in one function and it's available everywhere below that in the code.

I've used this kind of thing before. It doesn't need to be as complex as you made it. Just #define OUTPORT Serial3 (or whatever) and use OUTPORT wherever. If you instantiate a SoftwareSerial instance called mySerial then... #define OUTPORT mySerial

my misunderstanding the preprocessor is a given :slight_smile:

That particular line, though, was a status hack to make sure I was even reaching that branch for inclusion . . . .

thanks

IMO, you should be using C++ polymorphism. This allows you to assign to a base class pointer the address of a derived class and then use it in calls to functions that expect the former. And, virtual functions in the base class can be overridden by ones in the derived class.

Just about any "serial" interface you'd want to use (hardware serial, software serial, usb serial, etc) all inherit from the "Stream" class. So, all you have to do is define a single variable that is a pointer to Stream. Then assign to it the address of the actual interface you want to use and you're golden:

#include "Arduino.h"
#include "SoftwareSerial.h"

SoftwareSerial mySwSerial(5, 7);

Stream *streamPtr;

void setup()
{
 Serial.begin(9600);
 mySwSerial.begin(9600);

 streamPtr = &Serial;
 streamPtr->println("Hello World");

 streamPtr = &mySwSerial;
 streamPtr->println("Hello World");
}


void loop()
{
}

I seem to have bashed it into submission.

I had the block

#if btTyp==HARDWARE
HardwareSerial &btSerial = Serial;
#elif btTyp==ALTSOFTSERIAL
AltSoftSerial btSerial;
#else
SoftwareSerial btSerial;
#endif  //#btTyp if

But in spite of the definition above that btTyp==ALTSOFTSERIAL (and I tested at the beginning of setup, it still used the first branch and pointed at Serial.

I switched the order, and they speak properly.

You didn't show the whole code. For that to work, you need to define HARDWARE and ALTSOFTSERIAL with different values. You can't just do #define HARDWARE. You must do #define HARDWARE 1 (or any number) and the other one must have a different value.

Show the code with the definitions. (We don't need setup() and loop() in this case.)

I've left out the led and button stuff, but here's the rest that leads unto this.

And it certainly seems to work at the moment, with the above caveat

//types we'll need

enum srlTyps {
  NONE, HARDWARE, SOFTSERIAL, ALTSOFTSERIAL
};


//sort out the consequences the definitions


#ifdef useSoftwareSerialBt


//we want an softserial. Use the rx=D8 and TX=D9 for hardware ease
#define usingSoftSer
const srlTyps btTyp = SOFTSERIAL
const srlTyps dbgTyp = HARDWARE;
//SoftwareSerial btSerial (8, 9);

#elif defined(useAltSoftSerialBt)
#define usingAltSoftSer
//we want an altsoftserial for bt. On nano, rx=D8 and TX=D9


//AltSoftSerial btSerial;
#define usingAltSoftSer
const srlTyps btTyp = ALTSOFTSERIAL;
const srlTyps  dbgTyp = HARDWARE;


#else
//we wll use the hardware serial for AT-09
#define useingHardSer
//make btSerial an alias for Serial, so that we don't have t fll the code with ifDefs
//const  HardwareSerial * btSerial = &Serial;
// HardwareSerial  * btSerial = &Serial; this declares,but btSerial doesn't get a 'begin' type

//HardwareSerial btSerial;

const srlTyps btTyp = HARDWARE;

////in case the debugger was asked for
#ifdef useAltSoftDebug
const srlTyps dbgTyp = ALTSOFTSERIAL;
#ifndef usingAltSoftSer
#define usingAltSoftSer
#endif
#else
const srlTyps dbgTyp = NONE;
#endif
#endif//


#ifdef usingAltSoftSer
#include <AltSoftSerial.h>
#endif

#ifdef usingSoftSer
#include <SoftwareSerial.h>
#endif

//for the AT-09.  THis shoud probably go in a #ifdef, but . . .
//the pin to power the AT-09
const byte btSerialPowerPin = A0; // A0/D14
//and to read its status
const byte btSerialStatusPin = 15;

//possible status for the bt device
enum btStatStates {
  BTOFF, BTON, BTPOWERED, BTPENDING, BTAT
};

byte btSerialStatus = BTOFF;


// now a device to send monitor messages
#if dbgTyp==HARDWARE
HardwareSerial &monSerial = Serial;
#elif dbgTyp==ALTSOFTSERIAL
AltSoftSerial monSerial;
#elif dbgTyp==SOFTSERIAL
SoftwareSerial monSerial;
#else dbgTyp==NONE
//there is no monitor, so make an empty class for it
//   all the calls shoudl get optimized out by the compiler

class nullSerial {
    void begin(void);
    void println(void);
    void print(void);
    int available();
    void read(void);
    void write(void);
    void end(void);
}
nullSerial monSerial;
#endif  //monitor hardware #if




//HardwareSerial &monSerial = Serial;


//and again for bt

#if btTyp==ALTSOFTSERIAL
AltSoftSerial btSerial;
#elif btTyp==HARDWARE
HardwareSerial &btSerial = Serial;
#el
#else
SoftwareSerial btSerial;
#endif  //#btTyp if