Minor serial code cleanup
This commit is contained in:
parent
92b5f06bf9
commit
8bca8e5ba0
@ -566,7 +566,7 @@ ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
|
|||||||
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
|
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because of the template definition above, it's required to instantiate the template to have all method generated
|
// Because of the template definition above, it's required to instantiate the template to have all methods generated
|
||||||
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
|
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
|
||||||
MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
|
MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ typedef int8_t serial_index_t;
|
|||||||
#define SERIAL_ALL 0x7F
|
#define SERIAL_ALL 0x7F
|
||||||
#if HAS_MULTI_SERIAL
|
#if HAS_MULTI_SERIAL
|
||||||
#define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
|
#define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
|
||||||
|
#define _PORT_RESTORE(n,p) RESTORE(n)
|
||||||
#define SERIAL_ASSERT(P) if(multiSerial.portMask!=(P)){ debugger(); }
|
#define SERIAL_ASSERT(P) if(multiSerial.portMask!=(P)){ debugger(); }
|
||||||
#ifdef SERIAL_CATCHALL
|
#ifdef SERIAL_CATCHALL
|
||||||
typedef MultiSerial<decltype(MYSERIAL), decltype(SERIAL_CATCHALL), 0> SerialOutputT;
|
typedef MultiSerial<decltype(MYSERIAL), decltype(SERIAL_CATCHALL), 0> SerialOutputT;
|
||||||
@ -72,6 +73,7 @@ typedef int8_t serial_index_t;
|
|||||||
#define SERIAL_IMPL multiSerial
|
#define SERIAL_IMPL multiSerial
|
||||||
#else
|
#else
|
||||||
#define _PORT_REDIRECT(n,p) NOOP
|
#define _PORT_REDIRECT(n,p) NOOP
|
||||||
|
#define _PORT_RESTORE(n) NOOP
|
||||||
#define SERIAL_ASSERT(P) NOOP
|
#define SERIAL_ASSERT(P) NOOP
|
||||||
#define SERIAL_IMPL MYSERIAL0
|
#define SERIAL_IMPL MYSERIAL0
|
||||||
#endif
|
#endif
|
||||||
@ -79,6 +81,7 @@ typedef int8_t serial_index_t;
|
|||||||
#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V)
|
#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V)
|
||||||
|
|
||||||
#define PORT_REDIRECT(p) _PORT_REDIRECT(1,p)
|
#define PORT_REDIRECT(p) _PORT_REDIRECT(1,p)
|
||||||
|
#define PORT_RESTORE() _PORT_RESTORE(1)
|
||||||
#define SERIAL_PORTMASK(P) _BV(P)
|
#define SERIAL_PORTMASK(P) _BV(P)
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
|
// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
|
||||||
CALL_IF_EXISTS_IMPL(void, flushTX );
|
CALL_IF_EXISTS_IMPL(void, flushTX);
|
||||||
CALL_IF_EXISTS_IMPL(bool, connected, true);
|
CALL_IF_EXISTS_IMPL(bool, connected, true);
|
||||||
|
|
||||||
// In order to catch usage errors in code, we make the base to encode number explicit
|
// In order to catch usage errors in code, we make the base to encode number explicit
|
||||||
@ -42,14 +42,14 @@ enum class PrintBase {
|
|||||||
Bin = 2
|
Bin = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
// A simple forward struct that prevent the compiler to select print(double, int) as a default overload for any type different than
|
// A simple forward struct that prevent the compiler to select print(double, int) as a default overload for any type different than
|
||||||
// double or float. For double or float, a conversion exists so the call will be transparent
|
// double or float. For double or float, a conversion exists so the call will be transparent
|
||||||
struct EnsureDouble {
|
struct EnsureDouble {
|
||||||
double a;
|
double a;
|
||||||
FORCE_INLINE operator double() { return a; }
|
FORCE_INLINE operator double() { return a; }
|
||||||
// If the compiler breaks on ambiguity here, it's likely because you're calling print(X, base) with X not a double or a float, and a
|
// If the compiler breaks on ambiguity here, it's likely because you're calling print(X, base) with X not a double or a float, and a
|
||||||
// base that's not one of PrintBase's value. This exact code is made to detect such error, you NEED to set a base explicitely like this:
|
// base that's not one of PrintBase's value. This exact code is made to detect such error, you NEED to set a base explicitely like this:
|
||||||
// SERIAL_PRINT(v, PrintBase::Hex)
|
// SERIAL_PRINT(v, PrintBase::Hex)
|
||||||
FORCE_INLINE EnsureDouble(double a) : a(a) {}
|
FORCE_INLINE EnsureDouble(double a) : a(a) {}
|
||||||
FORCE_INLINE EnsureDouble(float a) : a(a) {}
|
FORCE_INLINE EnsureDouble(float a) : a(a) {}
|
||||||
};
|
};
|
||||||
@ -147,13 +147,13 @@ struct SerialBase {
|
|||||||
else write('0');
|
else write('0');
|
||||||
}
|
}
|
||||||
void printNumber(signed long n, const uint8_t base) {
|
void printNumber(signed long n, const uint8_t base) {
|
||||||
if (base == 10 && n < 0) {
|
if (base == 10 && n < 0) {
|
||||||
n = -n; // This works because all platforms Marlin's builds on are using 2-complement encoding for negative number
|
n = -n; // This works because all platforms Marlin's builds on are using 2-complement encoding for negative number
|
||||||
// On such CPU, changing the sign of a number is done by inverting the bits and adding one, so if n = 0x80000000 = -2147483648 then
|
// On such CPU, changing the sign of a number is done by inverting the bits and adding one, so if n = 0x80000000 = -2147483648 then
|
||||||
// -n = 0x7FFFFFFF + 1 => 0x80000000 = 2147483648 (if interpreted as unsigned) or -2147483648 if interpreted as signed.
|
// -n = 0x7FFFFFFF + 1 => 0x80000000 = 2147483648 (if interpreted as unsigned) or -2147483648 if interpreted as signed.
|
||||||
// On non 2-complement CPU, there would be no possible representation for 2147483648.
|
// On non 2-complement CPU, there would be no possible representation for 2147483648.
|
||||||
write('-');
|
write('-');
|
||||||
}
|
}
|
||||||
printNumber((unsigned long)n , base);
|
printNumber((unsigned long)n , base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +53,10 @@ void GcodeSuite::M118() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAS_MULTI_SERIAL
|
#if HAS_MULTI_SERIAL
|
||||||
const int8_t old_serial = multiSerial.portMask;
|
PORT_REDIRECT(WITHIN(port, 0, NUM_SERIAL) ? (port ? _BV(port - 1) : SERIAL_ALL) : multiSerial.portMask);
|
||||||
if (WITHIN(port, 0, NUM_SERIAL))
|
|
||||||
multiSerial.portMask = port ? _BV(port - 1) : SERIAL_ALL;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (hasE) SERIAL_ECHO_START();
|
if (hasE) SERIAL_ECHO_START();
|
||||||
if (hasA) SERIAL_ECHOPGM("//");
|
if (hasA) SERIAL_ECHOPGM("//");
|
||||||
SERIAL_ECHOLN(p);
|
SERIAL_ECHOLN(p);
|
||||||
|
|
||||||
TERN_(HAS_MULTI_SERIAL, multiSerial.portMask = old_serial);
|
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,9 @@ struct AutoReporter {
|
|||||||
const millis_t ms = millis();
|
const millis_t ms = millis();
|
||||||
if (ELAPSED(ms, next_report_ms)) {
|
if (ELAPSED(ms, next_report_ms)) {
|
||||||
next_report_ms = ms + SEC_TO_MS(report_interval);
|
next_report_ms = ms + SEC_TO_MS(report_interval);
|
||||||
TERN_(HAS_MULTI_SERIAL, PORT_REDIRECT(report_port_mask));
|
PORT_REDIRECT(report_port_mask);
|
||||||
Helper::report();
|
Helper::report();
|
||||||
|
//PORT_RESTORE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
# Serial port architecture in Marlin
|
# Serial port architecture in Marlin
|
||||||
|
|
||||||
Marlin is targeting a pletora of different CPU architecture and platforms. Each of these platforms has its own serial interface.
|
Marlin is targeting a plethora of different CPU architecture and platforms. Each of these platforms has its own serial interface.
|
||||||
While many provide a Arduino-like Serial class, it's not all of them, and the differences in the existing API create a very complex brain teaser for writing code that works more or less on each platform.
|
While many provide a Arduino-like Serial class, it's not all of them, and the differences in the existing API create a very complex brain teaser for writing code that works more or less on each platform.
|
||||||
|
|
||||||
Moreover, many platform have intrinsic needs about serial port (like forwarding the output on multiple serial port, providing a *serial-like* telnet server, mixing USB-based serial port with SD card emulation) that are difficult to handle cleanly in the other platform serial logic.
|
Moreover, many platform have intrinsic needs about serial port (like forwarding the output on multiple serial port, providing a *serial-like* telnet server, mixing USB-based serial port with SD card emulation) that are difficult to handle cleanly in the other platform serial logic.
|
||||||
|
|
||||||
|
|
||||||
Starting with version `2.0.9`, Marlin provides a common interface for its serial needs.
|
Starting with version `2.0.9`, Marlin provides a common interface for its serial needs.
|
||||||
|
|
||||||
## Common interface
|
## Common interface
|
||||||
@ -16,7 +15,7 @@ Any implementation will need to follow this interface for being used transparent
|
|||||||
The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.
|
The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.
|
||||||
Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost.
|
Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost.
|
||||||
|
|
||||||
Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for the documentation of this technic.
|
Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See the `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for documentation of this technique.
|
||||||
|
|
||||||
## Composing the desired feature
|
## Composing the desired feature
|
||||||
The different specificities for each architecture are provided by composing the serial type based on desired functionality.
|
The different specificities for each architecture are provided by composing the serial type based on desired functionality.
|
||||||
@ -32,7 +31,7 @@ Since all the types above are using CRTP, it's possible to combine them to get t
|
|||||||
This is easily done via type definition of the feature.
|
This is easily done via type definition of the feature.
|
||||||
|
|
||||||
For example, to present a serial interface that's outputting to 2 serial port, the first one being hooked at runtime and the second one connected to a runtime switchable telnet client, you'll declare the type to use as:
|
For example, to present a serial interface that's outputting to 2 serial port, the first one being hooked at runtime and the second one connected to a runtime switchable telnet client, you'll declare the type to use as:
|
||||||
```
|
```cpp
|
||||||
typedef MultiSerial< RuntimeSerial<Serial>, ConditionalSerial<TelnetClient> > Serial0Type;
|
typedef MultiSerial< RuntimeSerial<Serial>, ConditionalSerial<TelnetClient> > Serial0Type;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user