|
@@ -195,54 +195,71 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public Seria
|
195
|
195
|
RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...), writeHook(0), eofHook(0), userPointer(0) {}
|
196
|
196
|
};
|
197
|
197
|
|
198
|
|
-// A class that duplicates its output conditionally to 2 serial interfaces
|
199
|
|
-template <class Serial0T, class Serial1T, const uint8_t offset = 0, const uint8_t step = 1>
|
200
|
|
-struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset, step> > {
|
201
|
|
- typedef SerialBase< MultiSerial<Serial0T, Serial1T, offset, step> > BaseClassT;
|
|
198
|
+#define _S_CLASS(N) class Serial##N##T,
|
|
199
|
+#define _S_NAME(N) Serial##N##T,
|
|
200
|
+
|
|
201
|
+template < REPEAT(NUM_SERIAL, _S_CLASS) const uint8_t offset=0, const uint8_t step=1 >
|
|
202
|
+struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > {
|
|
203
|
+ typedef SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > BaseClassT;
|
|
204
|
+
|
|
205
|
+ #undef _S_CLASS
|
|
206
|
+ #undef _S_NAME
|
202
|
207
|
|
203
|
208
|
SerialMask portMask;
|
204
|
|
- Serial0T & serial0;
|
205
|
|
- Serial1T & serial1;
|
206
|
209
|
|
207
|
|
- static constexpr uint8_t Usage = ((1 << step) - 1); // A bit mask containing as many bits as step
|
208
|
|
- static constexpr uint8_t FirstOutput = (Usage << offset);
|
209
|
|
- static constexpr uint8_t SecondOutput = (Usage << (offset + step));
|
210
|
|
- static constexpr uint8_t Both = FirstOutput | SecondOutput;
|
|
210
|
+ #define _S_DECLARE(N) Serial##N##T & serial##N;
|
|
211
|
+ REPEAT(NUM_SERIAL, _S_DECLARE);
|
|
212
|
+ #undef _S_DECLARE
|
|
213
|
+
|
|
214
|
+ static constexpr uint8_t Usage = _BV(step) - 1; // A bit mask containing 'step' bits
|
|
215
|
+
|
|
216
|
+ #define _OUT_PORT(N) (Usage << (offset + (step * N))),
|
|
217
|
+ static constexpr uint8_t output[] = { REPEAT(NUM_SERIAL, _OUT_PORT) };
|
|
218
|
+ #undef _OUT_PORT
|
|
219
|
+
|
|
220
|
+ #define _OUT_MASK(N) | output[N]
|
|
221
|
+ static constexpr uint8_t ALL = 0 REPEAT(NUM_SERIAL, _OUT_MASK);
|
|
222
|
+ #undef _OUT_MASK
|
211
|
223
|
|
212
|
224
|
NO_INLINE void write(uint8_t c) {
|
213
|
|
- if (portMask.enabled(FirstOutput)) serial0.write(c);
|
214
|
|
- if (portMask.enabled(SecondOutput)) serial1.write(c);
|
|
225
|
+ #define _S_WRITE(N) if (portMask.enabled(output[N])) serial##N.write(c);
|
|
226
|
+ REPEAT(NUM_SERIAL, _S_WRITE);
|
|
227
|
+ #undef _S_WRITE
|
215
|
228
|
}
|
216
|
229
|
NO_INLINE void msgDone() {
|
217
|
|
- if (portMask.enabled(FirstOutput)) serial0.msgDone();
|
218
|
|
- if (portMask.enabled(SecondOutput)) serial1.msgDone();
|
|
230
|
+ #define _S_DONE(N) if (portMask.enabled(output[N])) serial##N.msgDone();
|
|
231
|
+ REPEAT(NUM_SERIAL, _S_DONE);
|
|
232
|
+ #undef _S_DONE
|
219
|
233
|
}
|
220
|
234
|
int available(serial_index_t index) {
|
221
|
|
- if (index.within(0 + offset, step + offset - 1))
|
222
|
|
- return serial0.available(index);
|
223
|
|
- else if (index.within(step + offset, 2 * step + offset - 1))
|
224
|
|
- return serial1.available(index);
|
|
235
|
+ uint8_t pos = offset;
|
|
236
|
+ #define _S_AVAILABLE(N) if (index.within(pos, pos + step - 1)) return serial##N.available(index); else pos += step;
|
|
237
|
+ REPEAT(NUM_SERIAL, _S_AVAILABLE);
|
|
238
|
+ #undef _S_AVAILABLE
|
225
|
239
|
return false;
|
226
|
240
|
}
|
227
|
241
|
int read(serial_index_t index) {
|
228
|
|
- if (index.within(0 + offset, step + offset - 1))
|
229
|
|
- return serial0.read(index);
|
230
|
|
- else if (index.within(step + offset, 2 * step + offset - 1))
|
231
|
|
- return serial1.read(index);
|
|
242
|
+ uint8_t pos = offset;
|
|
243
|
+ #define _S_READ(N) if (index.within(pos, pos + step - 1)) return serial##N.read(index); else pos += step;
|
|
244
|
+ REPEAT(NUM_SERIAL, _S_READ);
|
|
245
|
+ #undef _S_READ
|
232
|
246
|
return -1;
|
233
|
247
|
}
|
234
|
248
|
void begin(const long br) {
|
235
|
|
- if (portMask.enabled(FirstOutput)) serial0.begin(br);
|
236
|
|
- if (portMask.enabled(SecondOutput)) serial1.begin(br);
|
|
249
|
+ #define _S_BEGIN(N) if (portMask.enabled(output[N])) serial##N.begin(br);
|
|
250
|
+ REPEAT(NUM_SERIAL, _S_BEGIN);
|
|
251
|
+ #undef _S_BEGIN
|
237
|
252
|
}
|
238
|
253
|
void end() {
|
239
|
|
- if (portMask.enabled(FirstOutput)) serial0.end();
|
240
|
|
- if (portMask.enabled(SecondOutput)) serial1.end();
|
|
254
|
+ #define _S_END(N) if (portMask.enabled(output[N])) serial##N.end();
|
|
255
|
+ REPEAT(NUM_SERIAL, _S_END);
|
|
256
|
+ #undef _S_END
|
241
|
257
|
}
|
242
|
258
|
bool connected() {
|
243
|
259
|
bool ret = true;
|
244
|
|
- if (portMask.enabled(FirstOutput)) ret = CALL_IF_EXISTS(bool, &serial0, connected);
|
245
|
|
- if (portMask.enabled(SecondOutput)) ret = ret && CALL_IF_EXISTS(bool, &serial1, connected);
|
|
260
|
+ #define _S_CONNECTED(N) if (portMask.enabled(output[N]) && !CALL_IF_EXISTS(bool, &serial##N, connected)) ret = false;
|
|
261
|
+ REPEAT(NUM_SERIAL, _S_CONNECTED);
|
|
262
|
+ #undef _S_CONNECTED
|
246
|
263
|
return ret;
|
247
|
264
|
}
|
248
|
265
|
|
|
@@ -250,27 +267,32 @@ struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset,
|
250
|
267
|
using BaseClassT::read;
|
251
|
268
|
|
252
|
269
|
// Redirect flush
|
253
|
|
- NO_INLINE void flush() {
|
254
|
|
- if (portMask.enabled(FirstOutput)) serial0.flush();
|
255
|
|
- if (portMask.enabled(SecondOutput)) serial1.flush();
|
|
270
|
+ NO_INLINE void flush() {
|
|
271
|
+ #define _S_FLUSH(N) if (portMask.enabled(output[N])) serial##N.flush();
|
|
272
|
+ REPEAT(NUM_SERIAL, _S_FLUSH);
|
|
273
|
+ #undef _S_FLUSH
|
256
|
274
|
}
|
257
|
|
- NO_INLINE void flushTX() {
|
258
|
|
- if (portMask.enabled(FirstOutput)) CALL_IF_EXISTS(void, &serial0, flushTX);
|
259
|
|
- if (portMask.enabled(SecondOutput)) CALL_IF_EXISTS(void, &serial1, flushTX);
|
|
275
|
+ NO_INLINE void flushTX() {
|
|
276
|
+ #define _S_FLUSHTX(N) if (portMask.enabled(output[N])) CALL_IF_EXISTS(void, &serial0, flushTX);
|
|
277
|
+ REPEAT(NUM_SERIAL, _S_FLUSHTX);
|
|
278
|
+ #undef _S_FLUSHTX
|
260
|
279
|
}
|
261
|
280
|
|
262
|
281
|
// Forward feature queries
|
263
|
|
- SerialFeature features(serial_index_t index) const {
|
264
|
|
- if (index.within(0 + offset, step + offset - 1))
|
265
|
|
- return serial0.features(index);
|
266
|
|
- else if (index.within(step + offset, 2 * step + offset - 1))
|
267
|
|
- return serial1.features(index);
|
|
282
|
+ SerialFeature features(serial_index_t index) const {
|
|
283
|
+ uint8_t pos = offset;
|
|
284
|
+ #define _S_FEATURES(N) if (index.within(pos, pos + step - 1)) return serial##N.features(index); else pos += step;
|
|
285
|
+ REPEAT(NUM_SERIAL, _S_FEATURES);
|
|
286
|
+ #undef _S_FEATURES
|
268
|
287
|
return SerialFeature::None;
|
269
|
288
|
}
|
270
|
289
|
|
271
|
|
- MultiSerial(Serial0T & serial0, Serial1T & serial1, const SerialMask mask = Both, const bool e = false) :
|
272
|
|
- BaseClassT(e),
|
273
|
|
- portMask(mask), serial0(serial0), serial1(serial1) {}
|
|
290
|
+ #define _S_REFS(N) Serial##N##T & serial##N,
|
|
291
|
+ #define _S_INIT(N) ,serial##N (serial##N)
|
|
292
|
+
|
|
293
|
+ MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask = ALL, const bool e = false)
|
|
294
|
+ : BaseClassT(e), portMask(mask) REPEAT(NUM_SERIAL, _S_INIT) {}
|
|
295
|
+
|
274
|
296
|
};
|
275
|
297
|
|
276
|
298
|
// Build the actual serial object depending on current configuration
|
|
@@ -278,4 +300,7 @@ struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset,
|
278
|
300
|
#define ForwardSerial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial)
|
279
|
301
|
#ifdef HAS_MULTI_SERIAL
|
280
|
302
|
#define Serial2Class ConditionalSerial
|
|
303
|
+ #if NUM_SERIAL >= 3
|
|
304
|
+ #define Serial3Class ConditionalSerial
|
|
305
|
+ #endif
|
281
|
306
|
#endif
|