-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
modem: fixes and improvements #68651
modem: fixes and improvements #68651
Conversation
This makes the modem backends use the log level set for the modem modules instead of the default one. Signed-off-by: Tomi Fontanilles <[email protected]>
modem_pipe_attach() can send events before returning, which could provoke a crash as ppp->pipe, still NULL at that time, could be used either in receiving (if the pipe had some data pending) or in sending (if the PPP module had already been attached and had some data to send in its transmit buffer). ppp->pipe is now set before modem_pipe_attach(). Also, the ATTACHED_BIT is now set only after having actually attached. And finally, the send_work is now scheduled on PIPE_EVENT_OPENED so that data is flushed when the (closed) attached pipe is opened. Signed-off-by: Tomi Fontanilles <[email protected]>
655b22d
to
3d55ca6
Compare
Ping @bjarki-trackunit to make sure this does not fall into oblivion. |
|
||
if (was_open) { | ||
/* The UART is temporarily unavailable. Give it some time to recover. */ | ||
k_sleep(K_MSEC(100)); | ||
if (modem_backend_uart_async_is_open(backend)) { | ||
LOG_DBG("Re-enabling UART."); | ||
modem_pipe_open(&backend->pipe); | ||
} | ||
} |
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.
The intended behavior is that the user reacts to the PIPE_CLOSED event, and reopens the pipe is required. This allows the user to do any prerequisite work like resetting whatever the pipe was connected to, or ignoring the event if the closing is either expected or inconsequential (like the modem_cellular.c driver where the pipe is closed when the modem switches from AT to CMUX mode as the UART RX goes low for a period)
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 see. However in (at least) the case of the CMUX module being attached to the backend, it is the one to receive the pipe events. Currently it doesn't forward the events to the user nor react to the pipe closed event.
I currently see two different ways out of this:
- Let the user pass a callback so that events pertaining to the pipe the module is attached to can be received and reacted to.
- Make whether the pipe is automatically re-opened configurable (at build or run time).
What do you think?
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.
CMUX should disconnect if the pipe is closed, which will also close every DLCI channel, propagating the closed event :) So essentially option 1
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 did some more testing to reproduce the issue that I was fixing here, and turns out that I remembered wrong.
It can happen when using the PPP module directly plugged in the UART backend. No CMUX involved.
So it's the same story there, except there is no pipe shared between the PPP module and the user, so what you proposed doesn't apply.
Do you have an opinion on how it should be done there?
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.
Nope, I have no clear way to justify adding error handling to the PPP module that could not be applied to the CMUX module. I will review the addition of the auto recovery here:
We can not use
k_sleep(K_MSEC(100));
in a work item, as this blocks the work queue. We will need to add an additional delayable work item which waits for those 100ms.
When that work item is started, it must use modem_pipe_open_async() as modem_pipe_open() can block the system workqueue, which becomes a problem if the UART driver also uses it, as this will deadlock the workqueue until modem_pipe_open() times out
This will mean that we can end up in a race condition where the user wants to close the pipe, while we are waiting to try and reopen it, so make sure to cancel the work item in the modem_pipe_close implementation :)
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.
Of course, we also have the option op implementing the reopening in the modules using the pipes, so CMUX would reopen if it is connected, and L2 PPP would reopen if it is started, this would scale to all backends (UART ISR, TTY, UART ASYNC etc.)
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 the explanation regarding the work item and the synchronous opening.
I will leave the automatic recovery out of this PR so that the other changes can get in, but I am still planning to do something about it. Just have to agree on how exactly.
Nope, I have no clear way to justify adding error handling to the PPP module that could not be applied to the CMUX module.
I am not sure I quite understood this. Did you imply that the solution should apply to both the PPP and CMUX modules, so it shouldn't be specific to the PPP module? Although in what you propose further down, if I understand correctly each module would handle the reopening itself, so in that sense it would be specific to each module.
Of course, we also have the option op implementing the reopening in the modules using the pipes, so CMUX would reopen if it is connected, and L2 would reconnect if it is started, this would scale to all backends (UART ISR, TTY, UART ASYNC etc.)
Here what are you referring to exactly with L2
?
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.
If we extend the modem PPP (L2) module to always automatically reopen the pipe, we should extend the same logic to the modem CMUX as well.
We can make the backends "volatile", simply closing if they encounter an internal error, and make the user reopen it if that is desired. If this is all we are doing internally within the backend's anyway, we might as well just propagate the issue to the user with the closed event.
We can also make the backends "stronger", allowing them to do whatever they need internally to recover. This will be simpler from a user's perspective. The pipes would not close themselves, they would simply try to recover until it either succeeds or the pipe is closed due to some higher level timeout.
subsys/modem/modem_ppp.c
Outdated
if (byte == expected_byte) { | ||
ppp->receive_state++; | ||
return true; | ||
} |
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 would prefer this approach:
static bool modem_ppp_process_is_byte_expected(uint8_t byte, uint8_t expected_byte)
if (byte == expected_byte) {
return true;
}
LOG_DBG("Dropping byte 0x%2hhx because 0x%2hhx was expected.", byte, expected_byte);
return false;
}
...
{
switch (ppp->receive_state) {
case MODEM_PPP_RECEIVE_STATE_HDR_SOF:
if (modem_ppp_process_is_byte_expected(byte, MODEM_PPP_CODE_DELIMITER)) {
ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
}
break;
As this is easier to follow than hiding the new state within the helper, and using ++ instead of setting it directly. It will take up a few more bytes of ROM, but in this case the readability is more important IMO.
The SOF delimiter byte may be omitted when a frame follows another that just ended with that byte. The parsing used to expect that second delimiter anyway, which resulted in PPP frames going missing. As an additional improvement, dropped bytes as well as the length of received frames are now (debug) logged. Signed-off-by: Tomi Fontanilles <[email protected]>
Only log if the abort is not self-triggered, and also print the number of bytes sent. Signed-off-by: Tomi Fontanilles <[email protected]>
3d55ca6
to
c61a219
Compare
This allows to properly drop single CMUX frames that are too big to fit in the receive buffer, keeping track of where they end so that following frames are received correctly regardless of the data contents. Signed-off-by: Tomi Fontanilles <[email protected]>
Use the proper variable. Signed-off-by: Tomi Fontanilles <[email protected]>
This might be useful to those not familiar with how they work. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 This makes the modem backends use the log level set for the modem modules instead of the default one. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 modem_pipe_attach() can send events before returning, which could provoke a crash as ppp->pipe, still NULL at that time, could be used either in receiving (if the pipe had some data pending) or in sending (if the PPP module had already been attached and had some data to send in its transmit buffer). ppp->pipe is now set before modem_pipe_attach(). Also, the ATTACHED_BIT is now set only after having actually attached. And finally, the send_work is now scheduled on PIPE_EVENT_OPENED so that data is flushed when the (closed) attached pipe is opened. Signed-off-by: Tomi Fontanilles <[email protected]>
…e 0x7E is omitted Upstream PR: zephyrproject-rtos/zephyr#68651 The SOF delimiter byte may be omitted when a frame follows another that just ended with that byte. The parsing used to expect that second delimiter anyway, which resulted in PPP frames going missing. As an additional improvement, dropped bytes as well as the length of received frames are now (debug) logged. Signed-off-by: Tomi Fontanilles <[email protected]>
…_ABORTED Upstream PR: zephyrproject-rtos/zephyr#68651 Only log if the abort is not self-triggered, and also print the number of bytes sent. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 This allows to properly drop single CMUX frames that are too big to fit in the receive buffer, keeping track of where they end so that following frames are received correctly regardless of the data contents. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 Use the proper variable. Signed-off-by: Tomi Fontanilles <[email protected]>
…e functions Upstream PR: zephyrproject-rtos/zephyr#68651 This might be useful to those not familiar with how they work. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 This makes the modem backends use the log level set for the modem modules instead of the default one. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 modem_pipe_attach() can send events before returning, which could provoke a crash as ppp->pipe, still NULL at that time, could be used either in receiving (if the pipe had some data pending) or in sending (if the PPP module had already been attached and had some data to send in its transmit buffer). ppp->pipe is now set before modem_pipe_attach(). Also, the ATTACHED_BIT is now set only after having actually attached. And finally, the send_work is now scheduled on PIPE_EVENT_OPENED so that data is flushed when the (closed) attached pipe is opened. Signed-off-by: Tomi Fontanilles <[email protected]>
…e 0x7E is omitted Upstream PR: zephyrproject-rtos/zephyr#68651 The SOF delimiter byte may be omitted when a frame follows another that just ended with that byte. The parsing used to expect that second delimiter anyway, which resulted in PPP frames going missing. As an additional improvement, dropped bytes as well as the length of received frames are now (debug) logged. Signed-off-by: Tomi Fontanilles <[email protected]>
…_ABORTED Upstream PR: zephyrproject-rtos/zephyr#68651 Only log if the abort is not self-triggered, and also print the number of bytes sent. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 This allows to properly drop single CMUX frames that are too big to fit in the receive buffer, keeping track of where they end so that following frames are received correctly regardless of the data contents. Signed-off-by: Tomi Fontanilles <[email protected]>
Upstream PR: zephyrproject-rtos/zephyr#68651 Use the proper variable. Signed-off-by: Tomi Fontanilles <[email protected]>
…e functions Upstream PR: zephyrproject-rtos/zephyr#68651 This might be useful to those not familiar with how they work. Signed-off-by: Tomi Fontanilles <[email protected]>
ping @bjarki-trackunit @ycsin @rerickson1 @fabiobaltieri @bbilas |
Upstream PR: zephyrproject-rtos/zephyr#68651 This makes the modem backends use the log level set for the modem modules instead of the default one. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 8017cad)
Upstream PR: zephyrproject-rtos/zephyr#68651 modem_pipe_attach() can send events before returning, which could provoke a crash as ppp->pipe, still NULL at that time, could be used either in receiving (if the pipe had some data pending) or in sending (if the PPP module had already been attached and had some data to send in its transmit buffer). ppp->pipe is now set before modem_pipe_attach(). Also, the ATTACHED_BIT is now set only after having actually attached. And finally, the send_work is now scheduled on PIPE_EVENT_OPENED so that data is flushed when the (closed) attached pipe is opened. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 8b32ec3)
…e 0x7E is omitted Upstream PR: zephyrproject-rtos/zephyr#68651 The SOF delimiter byte may be omitted when a frame follows another that just ended with that byte. The parsing used to expect that second delimiter anyway, which resulted in PPP frames going missing. As an additional improvement, dropped bytes as well as the length of received frames are now (debug) logged. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 6fa0378)
…_ABORTED Upstream PR: zephyrproject-rtos/zephyr#68651 Only log if the abort is not self-triggered, and also print the number of bytes sent. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 6ae16aa)
Upstream PR: zephyrproject-rtos/zephyr#68651 This allows to properly drop single CMUX frames that are too big to fit in the receive buffer, keeping track of where they end so that following frames are received correctly regardless of the data contents. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 8b3d940)
Upstream PR: zephyrproject-rtos/zephyr#68651 Use the proper variable. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 6e0bea1)
…e functions Upstream PR: zephyrproject-rtos/zephyr#68651 This might be useful to those not familiar with how they work. Signed-off-by: Tomi Fontanilles <[email protected]> (cherry picked from commit 82f7e23)
See details in commit messages.