-
Notifications
You must be signed in to change notification settings - Fork 2k
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
stdio_uart: add stdio_uart_onlcr option to convert LF -> CRLF on output #15619
base: master
Are you sure you want to change the base?
Conversation
Add USE_MODULE += "stdio_uart_onlcr" to enable it. This is named after the "onlcr" stty flag, which does the same thing.
Updated to fix whitespace |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
Any feedback? |
Any updates? |
Sorry for having to wait so long for getting a review. Given that the effort to enable the conversion of To me, the trade-off looks like this:
If you insist that this will be useful to you, I can review it. But to me the alternative of configuring the receiver side to except |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have comment inline regarding the implementation.
If you say that this indeed is a better solution than receiver side conversion for your use case, we can push this forward.
#ifdef MODULE_STDIO_UART_ONLCR | ||
const uint8_t *buf = (const uint8_t *)buffer; | ||
const uint8_t cr = '\r'; | ||
size_t rem = len; | ||
while (rem--) { | ||
if (*buf == '\n') | ||
uart_write(STDIO_UART_DEV, &cr, 1); | ||
uart_write(STDIO_UART_DEV, buf, 1); | ||
buf++; | ||
} | ||
#else | ||
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, len); | ||
#endif | ||
#endif | ||
return len; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifdef MODULE_STDIO_UART_ONLCR | |
const uint8_t *buf = (const uint8_t *)buffer; | |
const uint8_t cr = '\r'; | |
size_t rem = len; | |
while (rem--) { | |
if (*buf == '\n') | |
uart_write(STDIO_UART_DEV, &cr, 1); | |
uart_write(STDIO_UART_DEV, buf, 1); | |
buf++; | |
} | |
#else | |
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, len); | |
#endif | |
#endif | |
return len; | |
ssize_t result = len; | |
if (IS_USED(MODULE_STDIO_UART_CRLF)) { | |
static const uint8_t crlf[2] = { (uint8_t)'\r', (uint8_t)'\n' }; | |
while (len) { | |
size_t chunk_len = 0; | |
const uint8_t *buf = buffer; | |
while ((chunk_len < len) && (buf[chunk_len] != (uint8_t)'\n')) { | |
chunk_len++; | |
} | |
uart_write(STDIO_UART_DEV, buf, chunk_len); | |
buf += chunk_len; | |
len -= chunk_len; | |
if (chunk_len) { | |
uart_write(STDIO_UART_DEV, crlf, sizeof(crlf)); | |
buf++; | |
len--; | |
} | |
} | |
} | |
else { | |
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, len); | |
} | |
return result; |
Three things:
- The current implementation that writes one char at a time. However, some UART drivers do support DMA. In that case this would keep the CPU busy all the time, while without CRLF conversion the CPU would only need to setup the DMA transfer to the UART peripheral (and like attend to an IRQ once it is done). The suggested change will be more efficient, as it will result in two DMA transfers per line rather than in one DMA transfer per character
- There is no need for preprocessor conditionals here, you can just use a C level
if
. That way, the compile tests will check syntactical correctness for both branches. And with any optimization level better than-O0
the compiler will eliminate the dead branch, so that there is no overhead to pay - I am personally not super happy with name
stdio_uart_onlcr
, as it is not immediately clear to me what onlcr stands for. How about something likestdio_uart_crlf
instead?
Hacking the terminal emulator to do the wrong thing is ... just that... the wrong thing. If you are worried about efficiency of looking for \n and sending \r\n, then maybe serial communications is not for you. |
This is not technically correct. UART is a different thing than the old terminal interfaces. We have particulate matter sensors, MP3 players, GPS receivers etc. interfacing via UART. These devices use a binary request-response protocol using UART as physical layer. There is no such thing "plug and play" for terminals with an UART interface. In addition to symbol rate, parity, and stop bits one needs to agree on that the interface is actually used as serial console. Yes, you can use UART for a serial console, but this doesn't make UART a "terminal interface". One can also use USB (e.g. via CDC ACM), SPI, I2C, or any network interface as a transport for a serial console as well.
With e.g. telnet it is actually specified that the line endings are But in any case it doesn't IMO matter to engage in a theoretical discussion here. It seems there are people that do have a use case for (Still, rebasing and addressing the review comments is still needed to merge this.) |
I haven't looked at the details of this pull request yet, but I don't want to put the fix in the UART code for all the reasons above. |
I have argued that your fix is right, and I've rebased it against master. |
@jimparis would you like to continue with this PR? there's consensus now that we want this. Or should we go with @mcr's rebased version? |
I'm not able to work on this currently, and so I'm happy to go with @mcr 's version (thanks for picking this up!) |
OK, let's get this in for the next release. With the feature freeze kicking in at the end of today, I picked this up and addressed the remaining issues: #18731 |
This adds an option, enabled by
USE_MODULE += "stdio_uart_onlcr"
, to automatically convert LF to CRLF on stdio UART output. (\n
to\r\n
). This is named after the "onlcr" stty flag, which does the same thing on a Unix system.It's an easy global fix for something which has come up a lot before, e.g.:
Wiki
PR #4899
Issue #3040
Issue #12540
This approach of converting on output is used by many other embedded OSes and lets RIOT output work without needing specific configuration on the other end's terminal software, or any changes to strings throughout the OS and application.