Sending Serial output to dev/null on a uController? WOT?

I'm testing some 3.3v pro-mini/433 mhz Lora boards out in the field.

Its proving jolly useful to be able to get serial feedback over a HC-06 Bluetooth serial. After much hunting around I found out how to do this:

//auto& serial = Serial;            // comment to switch output to BT conn to phone

  #include <SoftwareSerial.h>   // uncomment ditto
  SoftwareSerial serial(4, 5);     // uncomment ditto

... then later ....
serial.begin(BAUD);

Which allows me to simply set my desired Serial output at the top of the sketch, and then leave my code peppered with statements such as :

 serial.println("RSSI :");

That's all fine and dandy (and I hope it helps anyone else browsing around here).

But now I want a THIRD option, to simply ignore the serial output. Yes, I know I could comment it out, or start adding conditional statements :

if(DEBUG) 
serial.print("ugly");

But here is the background, I will be moving to using the excellent lowpower lib and from experience I know that by merely invoking the Serial port in a sketch which uses that library will start burning power.

So hence i want to be able to do something similar I used to do in my OOP days, which is to invoke a null object - i.e. something that mimics the Serial API but just sends the output to hell or to the equivalent of whatever dev/null is on a uC.

So to summarise I'd like to do the equivalent of :

/* OPTION 1 - usb serial */

//auto& serial = Serial;            // comment to switch output to BT conn to phone

/* OPTION 2 - s/w serial */

  #include <SoftwareSerial.h>   // uncomment ditto
  SoftwareSerial serial(4, 5);     // uncomment ditto

/* OPTION 3 - NO ACTUAL serial */
  NullSerial = serial;

serial.begin(BAUD);

The point of this being I can leave all my print statements where they are and turn on serial output if I need to debug in the future, AND have lowpower do its stuff without forking code.

I've searched over a few days for an example of this, and of course I guess I could just write my own implementation - but I bet a solution exists somewhere, 'you seen one?

if you are fine using some custom "functions" when writing your code you could do something like this

#define outputStream Serial

#ifdef outputStream
#define serialbegin(...)    outputStream.begin(__VA_ARGS__)
#define serialprint(...)    outputStream.print(__VA_ARGS__)
#define serialwrite(...)    outputStream.print(__VA_ARGS__)
#define serialprintln(...)  outputStream.println(__VA_ARGS__)
#else
#define serialbegin(...)
#define serialprint(...)
#define serialwrite(...)
#define serialprintln(...)
#endif

void setup()
{
  serialbegin(115200);
  serialprintln("HELLO");
  serialprintln(F("F HELLO"));
  serialprintln(123.456, 2);
  serialprintln(3735928559UL, HEX);
}

void loop() {}

You define outputStream to be the Serial or SoftwareSerial you want or simply comment out the #define outputStream if you don't want to see anything at all

Only constraint is that you use serialbegin(), serialprint(), serialwrite() or serialprintln() instead of the usual Serial.begin() etc

since even the begin() is defined you won't invoke at all any Serial code this way if you comment out the outputStream's #define, all the code automagically goes away at compile time and you won't use any memory (try compiling the example above with and without the #define outputStream and you'll see code size changes)

Hey, @J-L-M

That seems to work fine. Thank you.

I've elaborated and built upon your example to include an example of using it with SW Serial, for e.g. BT connections with a say, a phone.

// CASE 1 - all below commented out, no serial output at all - 444 bytes

//#define outputStream Serial  /* uncomment - CASE 2 this means output via serial  1844 bytes*/

//#define outputStream SoftwareSerial /* uncomment  CASE 3 (these 3 lines, plus that above)  */
//#include <SoftwareSerial.h>            /* - means divert serial to SW serial  - 2660 bytes */
//SoftwareSerial outputStream(4, 5);  // uncomment ditto

#ifdef outputStream
#define serialbegin(...)          outputStream.begin(__VA_ARGS__)
#define serialprint(...)          outputStream.print(__VA_ARGS__)
#define serialwrite(...)          outputStream.print(__VA_ARGS__)
#define serialprintln(...)        outputStream.println(__VA_ARGS__)
#define serialavailable(...)      outputStream.available(__VA_ARGS__)
#define serialreadBytesUntil(...) outputStream.readBytesUntil(__VA_ARGS__)
#define serialend(...)            outputStream.end(__VA_ARGS__)

#else
#define serialbegin(...)
#define serialprint(...)
#define serialwrite(...)
#define serialprintln(...)
#define serialavailable(...)
#define serialreadBytesUntil(...)
#define serialend(...)

#endif

If my use case is unclear FTW, let me explain:

1 In straight development mode - via, say, usb, you want all output to appear in Serial Monitor
2 In the field, or on battery you want all output diverted to appear via SW serial, for say viewing on a phone
3 You want to test lowpower output, you want nothing invoking any serial output at all
4 finally, you deploy - so likely strip out all serial calls anyway

This trick allows you to do all except 4 without nasty debug forks in your code.

Almost - the idea would be to define

#include <SoftwareSerial.h> 
SoftwareSerial softserial(4, 5);
#define outputStream softserial

Ah, so!

Lovely.

And I learned about variadic macros (...) something I have never come across before in C, cheers!

Have fun!