Logging to serial USB or SDCard using one function.

Hello,

At the moment I use the hardware serial or the file function print & println to log data.
But I want a custom function such as;

writeLog(data);

Inside writeLog I want to either log to the sdcard, usb serial or both, based on some conditions.
This way in my code I only have one line for each log.

The issue I have is how should I define the writeLog function so it can handle all parameters types, as print and println also do.

Thank you.

I figured to do it with function overloading, however still wondering if there is a shorter way.

if you show us how you did it, then we can comment on it.

Some macros could do the trick too for example.

Hi J-M-L,

Sorry for that, see below code, I'm sure there is a nicer way.

bool USBSerialAvaliable()
{
    return true;
}


bool SDCardAvaliable()
{
    if(logFile) {
      
      return true;
    } else {
      return false;
    }
}

void loggerPrintln(char data)
{
    if(SDCardAvaliable()) {
        logFile.println(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.println(data);
    }
}

void loggerPrintln(char * data)
{
    if(SDCardAvaliable()) {
        logFile.println(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.println(data);
    }
}

void loggerPrintln(int data)
{
    if(SDCardAvaliable()) {
        logFile.println(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.println(data);
    }
}

void loggerPrintln(float data)
{
    if(SDCardAvaliable()) {
        logFile.println(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.println(data);
    }
}

void loggerPrint(char data)
{
    if(SDCardAvaliable()) {
        logFile.print(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.print(data);
    }
}

void loggerPrint(char * data)
{
    if(SDCardAvaliable()) {
        logFile.print(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.print(data);
    }
}

void loggerPrint(int data)
{
    if(SDCardAvaliable()) {
        logFile.print(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.print(data);
    }
}

void loggerPrint(float data)
{
    if(SDCardAvaliable()) {
        logFile.print(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.print(data);
    }
}

void loggerPrint(time_t data)
{
    if(SDCardAvaliable()) {
        logFile.print(data);
        logFile.flush();
    }
    if(USBSerialAvaliable()) {
        debug.print(data);
    }
}

ah that’s painful indeed, and you don’t even capture all the possibilities

With a couple macro you coud do the following:

#include <SPI.h>
//#include <SD.h>
#include <SdFat.h>

File logFile;
HardwareSerial& debug = Serial;

// Multi-line macro --> mind the '\' at the end of the line to say "to be continued on next line"
#define d_println(...) {            \
    if (SDCardAvaliable()) {        \
      logFile.println(__VA_ARGS__); \
      logFile.flush();              \
    }                               \
    if (USBSerialAvaliable()) {     \
      debug.println(__VA_ARGS__);   \
    }                               \
  }

#define d_print(...) {              \
    if (SDCardAvaliable()) {        \
      logFile.print(__VA_ARGS__);   \
      logFile.flush();              \
    }                               \
    if (USBSerialAvaliable()) {     \
      debug.print(__VA_ARGS__);     \
    }                               \
  }

bool USBSerialAvaliable()
{
  return true;
}


bool SDCardAvaliable()
{
  return logFile;
}


void setup() {
  int foo = 100;
  float bar = 12.3456;
  debug.begin(115200);
  d_print("Hello World, followed by ");
  d_println(F("F(Hello World)"));
  d_print("foo = ");   d_println(foo, DEC); // Decimal representation
  d_print("foo = 0x"); d_println(foo, HEX); // Hexadecimal representation
  d_print("foo = 0b"); d_println(foo, BIN); // binary representation
  d_print("bar = "); d_println(bar, 2);     // 2 digits after the decimal point
  d_print("bar = "); d_println(bar, 6);     // 6 digits after the decimal point
}

void loop() {}

careful though as parameters will be copied verbatim into the print statements and thus if you are passing operations with side effects and printing to both the SD card and the debug channel, then the side effects will happen twice.

Serial Monitor (@ 115200 bauds) will show

[color=purple]
Hello World, followed by F(Hello World)
foo = 100
foo = 0x64
foo = 0b1100100
bar = 12.35
bar = 12.345601
[/color]