-
-
Notifications
You must be signed in to change notification settings - Fork 19.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor serial class with templates #20783
Conversation
This is currently not finished. The idea is to have the compiler optimize all the hook functions when none are being used without relying on a preprocessor configuration hell. All of this code will be optimized away when built so it should not impact the binary size nor the runtime speed. Once finished, it should just work as expected while simplifying the current serial.h file. This will allow to have as many serial port as desired, and, hopefully, should also permit to remove many redundant code in the different HAL, while hooking any serial port (for GUI console or telnet or whatever).
…h interface so it's easier to compound behaviors with typedef instead of a bunch of define
On a very fast read I just see, on the samd side, that Serial and Serial1 are missing from this change. They are defined inside framework |
Indeed, the same applies for Teensy. One need to extract the definition of the missing type from the relative framework to hook them. |
Just a side note, is it possible to have the CI tools not cancel all task when it fails ? It'll be faster to fix all bug if they are all reported at once, instead of one after the other. |
No. Apparently GitHub doesn't want to burn any more trees than it has to. To do testing on your local system use the included At this time the linker step is not succeeding because it can't find any compiled instances of serial objects with the expected signatures. Once you've got this compiling for a few platforms, then push your updates and we'll see whether the rest of them also pass CI. |
I think that overall it is a good idea to merge implementations, so that we will have more consistency between HALs. As already mentioned, this touches core code, and is pretty high risk. I suggest the following approach to move forward, once this is passing all build tests:
|
Now the implementation should be more or less final. Changes should be related to bug fixing the actual implementation (can't do that until next week). Please review the code and ask if anything seems wrong or confuse. |
@DrumClock your problem has been probably introduced by #20913 not by this PR |
@GMagician is right here. The remaining compilation issues are due to #20913. We'll fix those first. |
@X-Ryl669 I traced down issue to: static void serial_echo_column_labels(const uint8_t sp) {
SERIAL_ECHO_SP(7);
LOOP_L_N(i, GRID_MAX_POINTS_X) {
if (i < 10) SERIAL_CHAR(' ');
SERIAL_ECHO(i);
SERIAL_ECHO_SP(sp);
} what hangs the printer is |
@X-Ryl669 & @rhapsodyv I think I got it. It's a divide by 0 issue. I'll post a fix soon |
Yes, since there is a |
Ok, the problem here is: First fast fix may be: void print(long c, int base = DEC) { if (base) { write((const uint8_t*)"-", c < 0); printNumber(c < 0 ? -c : c, base); } else write(c); }
void print(unsigned long c, int base = DEC) { if (base) printNumber(c, base); else write(c); } this will prevent divide by 0 but will not act as meant. I don't know if marlin print chars as chars with print calls so I can't propone a correct solution |
ok, I changed 'unsigned char' with default 'base=DEC' and 'char' with 'base=0'. |
On your platform |
My fault, uint8_t is unsigned char, chars are signed as they should be |
I just saw now that some environments use: -fsigned-char, I also read now that c/c++ on arm default chars to unsigned (as you stated), I was used to x86 c/c++ where chars were always signed I confirm that samd51 is signed char by default (assertion doesn't break compilation) even if no argument is passed to compiler (but I think that such argument should be set by default on all platforms since Marlin need it) |
First: I got this compilation is errors:
Can i fix this ? |
@schimmi70 this may be not related to this PR. |
@schimmi70 Indeed you're right. I made a mistake here. Please fix it in your code, I'm preparing a new PR with other fix, I'll include this one too. |
@GMagician SerialX is the platform defined serial class. On some platform, it's being used directly in IRQ's functions in the platform, and in this case, the instance is wrapped in a Because of so many difference between platform, I've created a So on your platform, you might have a SerialX instance because it's declared in the platform, but it's not used directly, the MSerialTX instance is used instead. |
@GMagician because on all other places it is namend MSerialT3 or MSerialTX @X-Ryl669 I fixed in the Code, but i can't find why I get the compiler errors. |
@X-Ryl669 I missed such typedef in your PR |
@schimmi70 You've probably missed this line in MarlinSerial.cpp:598
Alternatively, you can try #20985 as it contains the fix. |
Description
In relation to #20755, this tries to improve the current serial class in Marlin so that G-Code console code is less hacky. It's touching a core feature, so care must be taken and I'm requesting for comments here.
I've tried to escape preprocessor's hell in serial.h, replacing it by template's hell.
More seriously, this merge all the different version of serial interface there are in Marlin (for USB, for Maple's Hardware, for STSTM32 Hardware, Linux, ESP3,2 etc...) into a single interface so that all platform will have EXACT same formatted output on the serial.
This interface is declared in
src/core/serial_base.h
.I wanted to avoid virtual table here since the serial code is a core feature of Marlin and adding calling cost here would reduce the performance of the firmware. So I've used CRTP pattern, the serial base is using the interface of the given
Child
class via static dispatch that compiles to a direct code to the Child's class, so in effect, it's a zero cost solution.I've added all the common serial interface here (a bunch of print/println/write method here) so I can remove them from all HAL (since they are different in the different HAL).
I've also added multiple
Child
implementation (insrc/core/serial_hook.h
):BaseSerial
is simply a redirect 1:1 to the underlying original code. In effect, this is the default implementation with 0 cost to use.RuntimeSerial
is a redirect with runtime modifiable hook functions. I'm interested in this for the G-Code console's PR above, but it can be used for many many usage (see below)ConditionalSerial
is a redirect with runtime checking a boolean variable before using the output. It's used to implement the ethernet's not-always-connected telnet, but it can be used for anything where the serial output can be maskedMultiSerial
is a tee serial output that's redirecting its writed char to 2 templated output serial. It's using a mask to activate the output and input.With this toolset, the mess of the serial output is largely simplified, since creating a serial output consist of writing the correct line of the desired type (like
SerialBase<MultiSerial<MarlinSerial, ConditionalSerial<TelnetSerial>>>
) and the compiler will compile this to a single class that's 0 overhead and multi-functionnal.I've mapped all the existing serial configuration to the right type in
serial.h
andserial.cpp
so it should be transparent; but any combination can now be written easily.Requirements
Currently, I've modified almost all HAL.
Benefits
In the future, I think it'll allow to simplify the WIFI code in the MKS's branch so that instead of having 2 GCode parser (Marlin and MKS's Wifi), we could have only one and hook the output of Marlin's processing to WIFI. This will create a true wireless serial console to Marlin.
Configurations
None, nothing changed here.
Related Issues
Please review and feel free to ask questions.