Support a third serial port (#21784)

This commit is contained in:
ellensp
2021-05-07 17:31:45 +12:00
committed by Scott Lahteine
parent 4518506559
commit 9fa9eebe51
20 changed files with 212 additions and 47 deletions

View File

@@ -44,6 +44,9 @@ PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMST
#if ENABLED(MEATPACK_ON_SERIAL_PORT_2)
SerialLeafT2 mpSerial2(false, _SERIAL_LEAF_2);
#endif
#if ENABLED(MEATPACK_ON_SERIAL_PORT_3)
SerialLeafT3 mpSerial3(false, _SERIAL_LEAF_3);
#endif
// Step 2: For multiserial, handle the second serial port as well
#if HAS_MULTI_SERIAL
@@ -52,7 +55,14 @@ PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMST
SerialLeafT2 msSerial2(ethernet.have_telnet_client, MYSERIAL2, false);
#endif
SerialOutputT multiSerial(SERIAL_LEAF_1, SERIAL_LEAF_2);
#define __S_LEAF(N) ,SERIAL_LEAF_##N
#define _S_LEAF(N) __S_LEAF(N)
SerialOutputT multiSerial( SERIAL_LEAF_1 REPEAT_S(2, INCREMENT(NUM_SERIAL), _S_LEAF) );
#undef __S_LEAF
#undef _S_LEAF
#endif
void serialprintPGM(PGM_P str) {

View File

@@ -95,6 +95,9 @@ extern uint8_t marlin_debug_flags;
#define _SERIAL_LEAF_2 MYSERIAL2 // Don't create a useless instance here, directly use the existing instance
#endif
// Nothing complicated here
#define _SERIAL_LEAF_3 MYSERIAL3
// Hook Meatpack if it's enabled on the second leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_2)
typedef MeatpackSerial<decltype(_SERIAL_LEAF_2)> SerialLeafT2;
@@ -104,7 +107,23 @@ extern uint8_t marlin_debug_flags;
#define SERIAL_LEAF_2 _SERIAL_LEAF_2
#endif
typedef MultiSerial<decltype(SERIAL_LEAF_1), decltype(SERIAL_LEAF_2), 0> SerialOutputT;
// Hook Meatpack if it's enabled on the third leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_3)
typedef MeatpackSerial<decltype(_SERIAL_LEAF_3)> SerialLeafT3;
extern SerialLeafT3 mpSerial3;
#define SERIAL_LEAF_3 mpSerial3
#else
#define SERIAL_LEAF_3 _SERIAL_LEAF_3
#endif
#define __S_MULTI(N) decltype(SERIAL_LEAF_##N),
#define _S_MULTI(N) __S_MULTI(N)
typedef MultiSerial< REPEAT_S(1, INCREMENT(NUM_SERIAL), _S_MULTI) 0> SerialOutputT;
#undef __S_MULTI
#undef _S_MULTI
extern SerialOutputT multiSerial;
#define SERIAL_IMPL multiSerial
#else

View File

@@ -195,54 +195,71 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public Seria
RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...), writeHook(0), eofHook(0), userPointer(0) {}
};
// A class that duplicates its output conditionally to 2 serial interfaces
template <class Serial0T, class Serial1T, const uint8_t offset = 0, const uint8_t step = 1>
struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset, step> > {
typedef SerialBase< MultiSerial<Serial0T, Serial1T, offset, step> > BaseClassT;
#define _S_CLASS(N) class Serial##N##T,
#define _S_NAME(N) Serial##N##T,
template < REPEAT(NUM_SERIAL, _S_CLASS) const uint8_t offset=0, const uint8_t step=1 >
struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > {
typedef SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > BaseClassT;
#undef _S_CLASS
#undef _S_NAME
SerialMask portMask;
Serial0T & serial0;
Serial1T & serial1;
static constexpr uint8_t Usage = ((1 << step) - 1); // A bit mask containing as many bits as step
static constexpr uint8_t FirstOutput = (Usage << offset);
static constexpr uint8_t SecondOutput = (Usage << (offset + step));
static constexpr uint8_t Both = FirstOutput | SecondOutput;
#define _S_DECLARE(N) Serial##N##T & serial##N;
REPEAT(NUM_SERIAL, _S_DECLARE);
#undef _S_DECLARE
static constexpr uint8_t Usage = _BV(step) - 1; // A bit mask containing 'step' bits
#define _OUT_PORT(N) (Usage << (offset + (step * N))),
static constexpr uint8_t output[] = { REPEAT(NUM_SERIAL, _OUT_PORT) };
#undef _OUT_PORT
#define _OUT_MASK(N) | output[N]
static constexpr uint8_t ALL = 0 REPEAT(NUM_SERIAL, _OUT_MASK);
#undef _OUT_MASK
NO_INLINE void write(uint8_t c) {
if (portMask.enabled(FirstOutput)) serial0.write(c);
if (portMask.enabled(SecondOutput)) serial1.write(c);
#define _S_WRITE(N) if (portMask.enabled(output[N])) serial##N.write(c);
REPEAT(NUM_SERIAL, _S_WRITE);
#undef _S_WRITE
}
NO_INLINE void msgDone() {
if (portMask.enabled(FirstOutput)) serial0.msgDone();
if (portMask.enabled(SecondOutput)) serial1.msgDone();
#define _S_DONE(N) if (portMask.enabled(output[N])) serial##N.msgDone();
REPEAT(NUM_SERIAL, _S_DONE);
#undef _S_DONE
}
int available(serial_index_t index) {
if (index.within(0 + offset, step + offset - 1))
return serial0.available(index);
else if (index.within(step + offset, 2 * step + offset - 1))
return serial1.available(index);
uint8_t pos = offset;
#define _S_AVAILABLE(N) if (index.within(pos, pos + step - 1)) return serial##N.available(index); else pos += step;
REPEAT(NUM_SERIAL, _S_AVAILABLE);
#undef _S_AVAILABLE
return false;
}
int read(serial_index_t index) {
if (index.within(0 + offset, step + offset - 1))
return serial0.read(index);
else if (index.within(step + offset, 2 * step + offset - 1))
return serial1.read(index);
uint8_t pos = offset;
#define _S_READ(N) if (index.within(pos, pos + step - 1)) return serial##N.read(index); else pos += step;
REPEAT(NUM_SERIAL, _S_READ);
#undef _S_READ
return -1;
}
void begin(const long br) {
if (portMask.enabled(FirstOutput)) serial0.begin(br);
if (portMask.enabled(SecondOutput)) serial1.begin(br);
#define _S_BEGIN(N) if (portMask.enabled(output[N])) serial##N.begin(br);
REPEAT(NUM_SERIAL, _S_BEGIN);
#undef _S_BEGIN
}
void end() {
if (portMask.enabled(FirstOutput)) serial0.end();
if (portMask.enabled(SecondOutput)) serial1.end();
#define _S_END(N) if (portMask.enabled(output[N])) serial##N.end();
REPEAT(NUM_SERIAL, _S_END);
#undef _S_END
}
bool connected() {
bool ret = true;
if (portMask.enabled(FirstOutput)) ret = CALL_IF_EXISTS(bool, &serial0, connected);
if (portMask.enabled(SecondOutput)) ret = ret && CALL_IF_EXISTS(bool, &serial1, connected);
#define _S_CONNECTED(N) if (portMask.enabled(output[N]) && !CALL_IF_EXISTS(bool, &serial##N, connected)) ret = false;
REPEAT(NUM_SERIAL, _S_CONNECTED);
#undef _S_CONNECTED
return ret;
}
@@ -250,27 +267,32 @@ struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset,
using BaseClassT::read;
// Redirect flush
NO_INLINE void flush() {
if (portMask.enabled(FirstOutput)) serial0.flush();
if (portMask.enabled(SecondOutput)) serial1.flush();
NO_INLINE void flush() {
#define _S_FLUSH(N) if (portMask.enabled(output[N])) serial##N.flush();
REPEAT(NUM_SERIAL, _S_FLUSH);
#undef _S_FLUSH
}
NO_INLINE void flushTX() {
if (portMask.enabled(FirstOutput)) CALL_IF_EXISTS(void, &serial0, flushTX);
if (portMask.enabled(SecondOutput)) CALL_IF_EXISTS(void, &serial1, flushTX);
NO_INLINE void flushTX() {
#define _S_FLUSHTX(N) if (portMask.enabled(output[N])) CALL_IF_EXISTS(void, &serial0, flushTX);
REPEAT(NUM_SERIAL, _S_FLUSHTX);
#undef _S_FLUSHTX
}
// Forward feature queries
SerialFeature features(serial_index_t index) const {
if (index.within(0 + offset, step + offset - 1))
return serial0.features(index);
else if (index.within(step + offset, 2 * step + offset - 1))
return serial1.features(index);
SerialFeature features(serial_index_t index) const {
uint8_t pos = offset;
#define _S_FEATURES(N) if (index.within(pos, pos + step - 1)) return serial##N.features(index); else pos += step;
REPEAT(NUM_SERIAL, _S_FEATURES);
#undef _S_FEATURES
return SerialFeature::None;
}
MultiSerial(Serial0T & serial0, Serial1T & serial1, const SerialMask mask = Both, const bool e = false) :
BaseClassT(e),
portMask(mask), serial0(serial0), serial1(serial1) {}
#define _S_REFS(N) Serial##N##T & serial##N,
#define _S_INIT(N) ,serial##N (serial##N)
MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask = ALL, const bool e = false)
: BaseClassT(e), portMask(mask) REPEAT(NUM_SERIAL, _S_INIT) {}
};
// Build the actual serial object depending on current configuration
@@ -278,4 +300,7 @@ struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset,
#define ForwardSerial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial)
#ifdef HAS_MULTI_SERIAL
#define Serial2Class ConditionalSerial
#if NUM_SERIAL >= 3
#define Serial3Class ConditionalSerial
#endif
#endif