modem: pipe: Add TRANSMIT_IDLE event

Add transmit idle event to modem_pipe_event enum. This will
allow modules to await transmit idle before trying to transmit
more data, instead of blindly calling modem_pipe_transmit in
a loop until all data has been accepted.

This will reduce the time spent trying to transmit data while
the backend is blocked.

Similarly to the RECEIVE_READY event, backends will call
modem_pipe_notify_transmit_idle() to indicate that transmit
is idle, and the TRANSMIT_IDLE event will be reinvoked when
the modem pipe is attached to synchronize the state of the
pipe with the user of it.

Additionally, the TRANSMIT_IDLE event is also invoked when the
modem is opened to further help synchronization with the user
of the pipe.

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
Bjarki Arge Andreasen 2023-11-22 06:59:44 +01:00 committed by Fabio Baltieri
parent 0f95b6fbb0
commit 516af3cb84
2 changed files with 33 additions and 1 deletions

View file

@ -25,6 +25,7 @@ extern "C" {
enum modem_pipe_event {
MODEM_PIPE_EVENT_OPENED = 0,
MODEM_PIPE_EVENT_RECEIVE_READY,
MODEM_PIPE_EVENT_TRANSMIT_IDLE,
MODEM_PIPE_EVENT_CLOSED,
};
@ -73,7 +74,8 @@ struct modem_pipe {
enum modem_pipe_state state;
struct k_mutex lock;
struct k_condvar condvar;
bool receive_ready_pending;
uint8_t receive_ready_pending : 1;
uint8_t transmit_idle_pending : 1;
};
/**
@ -213,6 +215,15 @@ void modem_pipe_notify_closed(struct modem_pipe *pipe);
*/
void modem_pipe_notify_receive_ready(struct modem_pipe *pipe);
/**
* @brief Notify user of pipe that pipe has no more data to transmit
*
* @param pipe Pipe instance
*
* @note Invoked from instance which initialized the pipe instance
*/
void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe);
/**
* @endcond
*/

View file

@ -21,6 +21,7 @@ void modem_pipe_init(struct modem_pipe *pipe, void *data, struct modem_pipe_api
pipe->user_data = NULL;
pipe->state = MODEM_PIPE_STATE_CLOSED;
pipe->receive_ready_pending = false;
pipe->transmit_idle_pending = true;
k_mutex_init(&pipe->lock);
k_condvar_init(&pipe->condvar);
@ -82,6 +83,10 @@ void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback
pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data);
}
if (pipe->transmit_idle_pending && (pipe->callback != NULL)) {
pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data);
}
k_mutex_unlock(&pipe->lock);
}
@ -97,6 +102,7 @@ int modem_pipe_transmit(struct modem_pipe *pipe, const uint8_t *buf, size_t size
}
ret = pipe->api->transmit(pipe->data, buf, size);
pipe->transmit_idle_pending = false;
k_mutex_unlock(&pipe->lock);
return ret;
}
@ -179,6 +185,7 @@ void modem_pipe_notify_opened(struct modem_pipe *pipe)
if (pipe->callback != NULL) {
pipe->callback(pipe, MODEM_PIPE_EVENT_OPENED, pipe->user_data);
pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data);
}
k_condvar_signal(&pipe->condvar);
@ -190,6 +197,7 @@ void modem_pipe_notify_closed(struct modem_pipe *pipe)
k_mutex_lock(&pipe->lock, K_FOREVER);
pipe->state = MODEM_PIPE_STATE_CLOSED;
pipe->receive_ready_pending = false;
pipe->transmit_idle_pending = true;
if (pipe->callback != NULL) {
pipe->callback(pipe, MODEM_PIPE_EVENT_CLOSED, pipe->user_data);
@ -211,3 +219,16 @@ void modem_pipe_notify_receive_ready(struct modem_pipe *pipe)
k_mutex_unlock(&pipe->lock);
}
void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe)
{
k_mutex_lock(&pipe->lock, K_FOREVER);
pipe->transmit_idle_pending = true;
if (pipe->callback != NULL) {
pipe->callback(pipe, MODEM_PIPE_EVENT_TRANSMIT_IDLE, pipe->user_data);
}
k_mutex_unlock(&pipe->lock);
}