print same string to two different serial ports

paynterf

Well-known member
My current wall-following robot uses two different serial ports for telemetry reporting - Serial (the normal USB port), and Serial1 (a HC-05 BT module). I have to send the same telemetry to both ports, because either or both can be active.

In my code are lines like this:

Serial.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);
Serial1.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);

I would like to create a function like 'SendToBothPorts(??)' so that I don't have to keep writing (or copy/pasting) the same stuff twice every time I want to send to both ports.

I have tried playing around with strcpy and strcat, like so:

Code:
  char quotestr[] = "\"";
  char hellostr[] = "hello";
  char instr[] = "%s\n, hellostr";
  char deststr[40];
  memset(deststr, 0, sizeof(deststr));
  strcat(deststr, quotestr);
  strcat(deststr, instr);
  strcat(deststr, quotestr);
  Serial.printf("quotestr = %s\n", quotestr);
  Serial.printf("instr = %s\n", instr);
  Serial.printf("deststr = %s\n", deststr);
  Serial.printf(deststr);

but the '\n' construct gets interpreted even though it is within double-quotes, so the output looks like:

Code:
quotestr = "
instr = %s
, hellostr
deststr = "%s
, hellostr"
"
, hellostr"

I'm thinking there must be a better way to do this, but I can't figure it out - any ideas would be appreciated

TIA,

Frank
 
Code:
Serial.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);
Serial1.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);

Something like this?

Code:
void printTwice( char *s )
{
  Serial.printf( "%s", s );
  Serial1.printf( "%s", s );
}

void loop()
{
  char s[80];
  sprintf( s, "\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR );
  printTwice( s );
}
 
Maybe like this?

Code:
void setup() {
  Serial.begin(9600);
  Serial1.begin(115200);
  pinMode(13, OUTPUT);
}

void SendToBothPorts(const char *f, ...) {
  va_list args;
  char buf[80];
  va_start(args, f);
  vsnprintf(buf, sizeof(buf), f, args);
  va_end(args);
  Serial.write(buf);
  Serial1.write(buf);
}

void loop() {
  static unsigned int count = 0;
  SendToBothPorts("count = %u\r\n", count++);
  digitalToggle(13);
  delay(1000);
}
 
Hey, thanks for the pointers - I guess I had forgotten (or never really knew) about the 'sprintf' and 'vsnprintf' functions. Let me play with them for a while and see if I can make one or both ideas work for me.
 
OK, I set up a new Teensy 3.2 project to test this out, as follows:

Code:
/*
    Name:       SendToBothPorts.ino
    Created:	1/3/2022 9:30:52 PM
    Author:     NEWXPS15\paynt
*/


void setup()
{
    Serial.begin(115200);
    delay(2000); //10/06/21 - just use fixed delay instead

    Serial1.begin(115200); //used HC-05 'AT' commands to set this speed
    delay(2000); //11/20/21 use fixed delay instead of waiting

    //DEBUG!!
    if (Serial)
    {
      Serial.printf("Serial = %p, Serial1 = %p\n", &Serial, &Serial1);
    }
    //DEBUG!!
     
    //DEBUG!!
    if (Serial1)
    {
      Serial1.printf("Serial = %p, Serial1 = %p\n", &Serial, &Serial1);
    }
    //DEBUG!!

    SendToBothPorts("Serial = %p, Serial1 = %p\n", &Serial, &Serial1);
}

void loop()
{


}

void SendToBothPorts(const char* f, ...) //'...' means variable number of arguments
{
  va_list args;
  char buf[80];
  va_start(args, f);
  vsnprintf(buf, sizeof(buf), f, args);
  va_end(args);
  Serial.write(buf);
  Serial1.write(buf);
}


And the output was:


Code:
Opening port
Port open
Serial = 0x1fff8754, Serial1 = 0x1fff873c
Serial = 0x1fff8754, Serial1 = 0x1fff873c

So, for at least this case, everything works perfectly - thanks!

Frank
 
To wrap things up on this subject, I added 'TeePrint' functionality to my 'SendToBothPorts.ino' sketch as shown below:

Code:
/*
 /*
    Name:       SendToBothPorts.ino
    Created:	1/3/2022 9:30:52 PM
    Author:     NEWXPS15\paynt
*/

#include "TeePrint.h"

TeePrint myTeePrint(Serial, Serial1);

void setup()
{
    Serial.begin(115200);
    delay(2000); //10/06/21 - just use fixed delay instead

    Serial1.begin(115200); //used HC-05 'AT' commands to set this speed
    delay(2000); //11/20/21 use fixed delay instead of waiting

    //DEBUG!!
    if (Serial)
    {
      Serial.printf("Serial = %p, Serial1 = %p\n", &Serial, &Serial1);
    }
    //DEBUG!!
     
    //DEBUG!!
    if (Serial1)
    {
      Serial1.printf("Serial = %p, Serial1 = %p\n", &Serial, &Serial1);
    }
    //DEBUG!!

    SendToBothPorts("Using SendToBothPorts: Serial = %p, Serial1 = %p\n", &Serial, &Serial1);

    //now try same thing, except with TeePrint class object
    float myfloat = 1234.5678;

    Serial.printf("using just Serial: myfloat addr = %p, value =  %2.3f\n", &myfloat, myfloat);

    myTeePrint.printf("using TeePrint: myfloat addr = %p, value =  %2.3f\n", &myfloat, myfloat);

    myTeePrint.printf("using TeePrint: writing a singe byte with myTeePrint.write() = ");
    myTeePrint.write(0x23);
}

void loop()
{


}

void SendToBothPorts(const char* f, ...) //'...' means variable number of arguments
{
  va_list args;
  char buf[80];
  va_start(args, f);
  vsnprintf(buf, sizeof(buf), f, args);
  va_end(args);
  Serial.write(buf);
  Serial1.write(buf);
}

Where 'TeePrint.h' is:

Code:
/*    Name:       TeeClass.ino
    Created:	1/4/2022 10:10:24 AM
    Author:     NEWXPS15\paynt
    copied from Juraj's nice c++ proposal on Stackexchange: https://arduino.stackexchange.com/a/88255/66176
*/

class TeePrint : public Print 
{

  Print& out1;
  Print& out2;

public:

  //initializes 'out1' and 'out2' via base class (class Print) constructor
  TeePrint(Print& _out1, Print& _out2) : out1(_out1), out2(_out2) {}

  //at this point, 'out1', 'out2'have been initialized as Print class objects

  //virtual keyword allows this function to be overridden in derived classes
  virtual size_t write(uint8_t b) {
    out1.write(b);
    out2.write(b);
    return 1;
  }

};
Which produces the following output on Serial (haven't checked Serial1, but should be the same):

Code:
Opening port
Port open
Serial = 0x1fff8754, Serial1 = 0x1fff873c
Using SendToBothPorts: Serial = 0x1fff8754, Serial1 = 0x1fff873c
using just Serial: myfloat addr = 0x20007fd4, value =  1234.568
using TeePrint: myfloat addr = 0x20007fd4, value =  1234.568
using TeePrint: writing a singe byte with myTeePrint.write() = #

While both approaches get the job done, I think I prefer the TeePrint class, more from an esthetic perspective than anything else. Now telemetry output code might look like:

//output just to Serial or Serial1:

Code:
Serialx.printf("blah, blah blah");

//output to both Serial1 & Serial2:

Code:
myTeePrint.printf("blah, blah blah");

Thoughts?

Frank
 
Back
Top