sys/stdio_nimble: Remove periodic callout and update documentation#21206
sys/stdio_nimble: Remove periodic callout and update documentation#21206crasbe wants to merge 11 commits intoRIOT-OS:masterfrom
Conversation
mguetschow
left a comment
There was a problem hiding this comment.
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.
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.
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. |
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 |
da17c24 to
8916396
Compare
c285409 to
317a1c3
Compare
|
I decided to add a commit to replace the deprecated functions, as mentioned in #21234 too. Surprisingly it did not give a merge conflict in the rebase :D |
Co-authored-by: mguetschow <[email protected]>
7def676 to
def204a
Compare
|
Inspired by #22149, I've wondered if it would make sense to use an Event Queue instead of the |


Contribution description
Following the issue in #21192, I experimented with the
stdio_nimblemodule 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
_writefunction into the#ifdef DEBUGblock, 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
_statusvariable which is not really nice. It is possible that some race conditions occur, but so far I haven't noticed any.stdio_nimbleis 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
periodicthread intests/sys/shell[_ble]got increased conditionally whenstdio_nimble_debugis used, since theprintfconsumes more stack and led to a stack overflow and_send_stdoutprinting out memory.Task List
periodiccommand oftests/sys/shell._send_stdoutinstead of recursive call._statusto avoid race conditions. (Set a temporary_status, get mutex and check if global_statusstill has the right value and set it, release mutex).event->notify_tx.status.stdoutbuffer on connect by default, make it optional.stdio_nimble_debugpseudomodule.In debug mode: Redirectstdoutto UART when BLE connection is disconnected. Otherwise crash information won't be readable.stdio_nimble.hheader.Testing procedure
You can test this with a board that is supported by NimBLE, for example a
nrf52dkornrf52840dk. Some ESP boards should work too, but I don't have any. Thenrf52840donglewill 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_stdoutin bothmasterand 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
helpcommand.Before applying this PR:
With this PR applied:
Issues/PRs references
Fixes #21192.
Fixes #21234.
~~Depends on #21832.~~Merged.