-
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
sys/stdio_nimble: Remove periodic callout and update documentation #21206
base: master
Are you sure you want to change the base?
Conversation
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.
Thanks for investigating! I haven't tested it locally yet, but some first comments below.
I would've liked to add a
_send_stdout()
call to the subscription event, but that will cause a crash which I can't really trace (the STDOUT goes to BLE...). I assume that NimBLE needs some time after the SUBSCRIBE event before it can actually accept data.
Couldn't you trace it with the debug module over uart? I agree that this would be the proper place to call _send_stdout
.
Is it correct that _send_stdout
is currently on master
and with this PR only called after a new call to _write
and not as soon as the BLE device subscribes?
sys/stdio_nimble/stdio_nimble.c
Outdated
if (tsrb_avail(&_tsrb_stdout) > 0 && _status == STDIO_NIMBLE_SUBSCRIBED) { | ||
/* retry sending data for anything left in the ringbuffer */ | ||
_send_stdout(); | ||
} |
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.
Not sure if the compiler would be smart enough to notice this is a tail-recursive function and not actually increase the stack frame for each recursive call. Maybe this could be a while-loop around the whole function content instead?
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.
Yes, a while loop would be a good option. I thought about that but didn't follow through.
The
Yes, that's currently how it's implemented. It doesn't really have any bad effect because the STDOUT buffer is cleared by default on connect. RIOT/sys/include/stdio_nimble.h Lines 44 to 48 in 7027fd3
Since the time between a connect and a subscription is usually short, not a lot of data should accumulate in the buffer. I'm undecided whether I like that default clearing in general and the subscription behavior (or non-behavior). I'll dig a little bit deeper to see if there's a good solution (like a ready to send flag or perhaps a time delay again). |
Would probably be nice to have, if not too hacky (and only enabled when
At least its different to the stdio over serial output on other boards that keep the output in a buffer up to a certain length. I think I'd prefer that here, too. |
Sorry for "flooding" you with e-mails and fixup commits, I'm currently a bit slow and distracted... The default behavior of Edit: If you want to, I can squash the commits at this point, it's starting to get a bit fragmented I guess. |
No worries, just ping me when I should have another look :)
Yes, please squash already, I'll have a look at the combined changes again anyways. |
2a4fa64
to
9e891c0
Compare
9e891c0
to
6fab309
Compare
I think it was too late when I wrote that. In fact, everything already is sent out via UART 🤣 The "crash" that happens when the stack of the |
@crasbe If that's the only remaining thing and you don't come to do it now, I'd say it could also be postponed to a second PR. Just give me a thumbs up and I'll have a look at it as is now. |
I implemented that yesterday too, but couldn't test it, so I did not commit it yet. There's one other thing to consider: The behavior of |
This is not exactly true either. At the moment it blocking and non-blocking. The first call is blocking because it will call the I think the best way going forward is doing it totally non-blocking with ztimer and add a blocking mode with a mutex in a separate PR. Sending the This is how it looks like when I sent a So yeah, it seems like there is not enough time and not all the descriptors are exchanged yet and then the indication hits. Maybe I'll do something like a 200ms delay before triggering the |
I think the stack keeps on giving. Adding Unfortunately that idea only came to my head after I left the office and I left the devboard there... so I earliest I can test that hypothesis it is Monday. |
Well... this was (partly) my own stupidity 🤣 I called However the ISR stack will still overflow with and without the debug messages enabled. For this example I just added
Adding it to
Could this be an issue where the But on a positive note: With some delay, the "send everything that's still in the buffer after the SUBSCRIBE event" feature works now. 500ms is very conservative, 200ms worked as well. I'm not sure which value to choose yet. |
I think that is expected behavior, if you want to set something for the whole build you would need to do so in |
The only other example I could find which requires increasing the RIOT/pkg/openwsn/Makefile.include Lines 62 to 66 in 88f2e45
Ideally we would get away without increasing the ISR stack at all and I'm not really sure why that's necessary in the first place. The previous version with the periodic callouts essentially came down to A non-invasive solution would be to re-add the |
I learned that This might explain why the ISR stack overflows.
I added a commit which introduces a |
Contribution description
Following the issue in #21192, I experimented with the
stdio_nimble
module and essentially I think that the original periodic callout was not required at all.I would've liked to add a
_send_stdout()
call to the subscription event, but that will cause a crash which I can't really trace (the STDOUT goes to BLE...). I assume that NimBLE needs some time after the SUBSCRIBE event before it can actually accept data.Also I put the interrupt disable and enable functions in the
_write
function into the#ifdef DEBUG
block, so that they are only executed when they are actually needed. I'm not sure if the compiler would optimize them away, but the less interrupt interruption, the better.Speaking of which: At the moment there are multiple places that access the
_status
variable which is not really nice. It is possible that some race conditions occur, but so far I haven't noticed any.stdio_nimble
is still classified as experimental and the potential for race conditions was present before as well, so I don't think this is the place to fix it.Also I had to increase the stack size when debugging is enabled, otherwise the debug messages would sometimes corrupt the threadsafe ringbuffer and it would start to spill out memory content on the BLE shell 😅I added an in the preprocessor conditional when the stack size is too small. This is open for debate, that's why I didn't squash it yet.
The stack size of the
periodic
thread intests/sys/shell[_ble]
got increased conditionally whenstdio_nimble_debug
is used, since theprintf
consumes more stack and led to a stack overflow and_send_stdout
printing out memory.Task List
periodic
command oftests/sys/shell
._send_stdout
instead of recursive call._status
to avoid race conditions. (Set a temporary_status
, get mutex and check if global_status
still has the right value and set it, release mutex).event->notify_tx.status
.stdout
buffer on connect by default, make it optional.stdio_nimble_debug
pseudomodule.In debug mode: Redirectstdout
to UART when BLE connection is disconnected. Otherwise crash information won't be readable.stdio_nimble.h
header.Testing procedure
You can test this with a board that is supported by NimBLE, for example a
nrf52dk
ornrf52840dk
. Some ESP boards should work too, but I don't have any. Thenrf52840dongle
will not work because it lacks a real serial console (or you have to be dedicated enough to connect your usb to serial adapter :D )Essentially you can follow this guide to test it: https://doc.riot-os.org/group__sys__stdio__nimble.html
This PR shouldn't cause any noticeable differences.
If you want to see the effect you can add
_debug_printf("Status: %d\n, _status);
to the first line of_send_stdout
in bothmaster
and this PR.You have to connect to the Devboard via serial console to the PC and you'll receive the following debug output. I typed the
help
command.Before applying this PR:
With this PR applied:
Issues/PRs references
Fixes #21192.