One-to-many Serial object (bidirectional proxy, muiltiplexer, splitter)

I’m looking to create a new Stream object Debug that acts as a proxy for two other streams: Serial and DebugSerial. The Debug object should:

  • Redirect everything written to it to both Serial and DebugSerial.
  • Read operations on Debug should automatically read from both Serial and DebugSerial.

Example:

#include <RemoteDebug.h>
RemoteDebug DebugSerial;

// Magic code that creates the `Debug` Serial proxy

Debug.println("Hello, World!"); // Sends "Hello, World!" to both Serial and DebugSerial.

if (Debug.available()) {
    char c = Debug.read(); // Reads from either Serial or DebugSerial.
    Debug.print(c); // Echoes `c` to both streams.
}

Does a library or existing solution exist for this? I would like to manually override every single Stream method in order to achieve this behavior.

You only need to implement these methods from Stream:

  public:
    virtual int available() = 0;
    virtual int read() = 0;
    virtual int peek() = 0;

And this one from Print (from which Stream inherits):

    virtual size_t write(uint8_t) = 0;

Outputting from your new class will to two different Streams(s) will be trivial. You may have to think about how you would interleave data coming from two different Stream(s) into a single (composite) one.

This sounds similar to semihosting on ARM processors but I don't know if there's any arduino support on e.g., the Bluepill/Blackpill devices.

@gfvalvo Like this?

MultiStream.h

#ifndef MULTISTREAM_H
#define MULTISTREAM_H

#include <Arduino.h>

class MultiStream : public Stream {
  public:
    MultiStream(Stream &stream1, Stream &stream2);
    virtual int available() override;
    virtual int read() override;
    virtual int peek() override;
    virtual size_t write(uint8_t c) override;

  private:
    Stream &_stream1;
    Stream &_stream2;
};

#endif // MULTISTREAM_H

MultiStream.cpp

#include "MultiStream.h"

MultiStream::MultiStream(Stream &stream1, Stream &stream2)
    : _stream1(stream1), _stream2(stream2) {}

int MultiStream::available() {
    return _stream1.available() + _stream2.available();
}

int MultiStream::read() {
    if (_stream1.available()) {
        return _stream1.read();
    }
    if (_stream2.available()) {
        return _stream2.read();
    }
    return -1;
}

int MultiStream::peek() {
    if (_stream1.available()) {
        return _stream1.peek();
    }
    if (_stream2.available()) {
        return _stream2.peek();
    }
    return -1;
}

size_t MultiStream::write(uint8_t c) {
    size_t bytesWritten = 0;
    bytesWritten += _stream1.write(c);
    bytesWritten += _stream2.write(c);
    return bytesWritten;
}

main:

#include "MultiStream.h"
#include <RemoteDebug.h>

RemoteDebug DebugSerial;

MultiStream Debug(Serial, DebugSerial);

Looks reasonable.

I think you only want to return 1 from your write() function because that's the number of bytes written to your new Stream by the calling function.

Also (I haven't thought about this too much), it seems that your read() function my favor _stream1 because you test it first.

int MultiStream::read() {
    if (_stream1.available()) {
        return _stream1.read();
    }
    if (_stream2.available()) {
        return _stream2.read();
    }
    return -1;
}

Oh, I see what you mean. It took me a second to understand. Yeah summing up both writes doesn't really make too much sense I guess.

Regarding the read I'm not really sure how else to implement this.

The write method actually turns out to be a big problem!

I created this simplified class that just inherits from Print:

#include "DynamicMultiPrint.h"

DynamicMultiPrint::DynamicMultiPrint()
    : _print1(nullptr), _print2(nullptr) {}

void DynamicMultiPrint::setPrint1(Print* print) {
    _print1 = print;
}

void DynamicMultiPrint::setPrint2(Print* print) {
    _print2 = print;
}

size_t DynamicMultiPrint::write(uint8_t c) {
    size_t count1 = 0, count2 = 0;

    if (_print1 != nullptr) {
        count1 = _print1->write(c);
    }

    if (_print2 != nullptr) {
        count2 = _print2->write(c);
    }

    return (count1 > count2) ? count1 : count2;
}

The issue is that in some cases _print1->write(c) and _print2->write(x) do not return the same result:

Any ideas how to address this issue?

What is the actual Print-based class whose write() function returned 0? Look at the source code for that class. Under what circumstances does it return 0?

It's this RemoteDebug library. I think it's supposed to return the amount of bytes actually written.

Edit: Nevermind, I think it was just mistake on my side that has nothing to do with the code I shared. After fixing that, it prints correctly to both Print objects. Although I suppose there still is a small chance of misbehavior if that case of different return values for those write methods would actually happen.