modem: pipe: Reinvoke receive ready on attach

This PR makes the modem_pipe instances track if they have
data ready to receive, and invoke the RECEIVE_READY event
every time they are attached if the backend implementing
the pipe has notified that receive is ready.

This mechanism ensures that modules attaching to a pipe
get the async RECEIVE_READY event immediately after
attaching to a pipe if there is data ready, instead of
having to poll the pipe, or worse, wait until newer data
becomes available.

The addition revealed a timing issue in the cmux test
suite. Specifically the CMUX instance now immediately
receives the response to a command which the CMUX
instance has not sent yet, causing it to drop the
response.

The CMUX test suite now uses the transaction
mechanism of the mock_pipe to wait for the command
before sending the response.

Signed-off-by: Bjarki Arge Andreasen <bjarkix123@gmail.com>
This commit is contained in:
Bjarki Arge Andreasen 2023-09-13 20:03:27 +02:00 committed by Maureen Helm
parent 8cb9d76553
commit 40b9f51ee5
3 changed files with 20 additions and 15 deletions

View file

@ -53,6 +53,7 @@ struct modem_pipe {
enum modem_pipe_state state;
struct k_mutex lock;
struct k_condvar condvar;
bool receive_ready_pending;
};
/**

View file

@ -20,6 +20,7 @@ void modem_pipe_init(struct modem_pipe *pipe, void *data, struct modem_pipe_api
pipe->callback = NULL;
pipe->user_data = NULL;
pipe->state = MODEM_PIPE_STATE_CLOSED;
pipe->receive_ready_pending = false;
k_mutex_init(&pipe->lock);
k_condvar_init(&pipe->condvar);
@ -63,6 +64,11 @@ void modem_pipe_attach(struct modem_pipe *pipe, modem_pipe_api_callback callback
k_mutex_lock(&pipe->lock, K_FOREVER);
pipe->callback = callback;
pipe->user_data = user_data;
if (pipe->receive_ready_pending && (pipe->callback != NULL)) {
pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data);
}
k_mutex_unlock(&pipe->lock);
}
@ -94,6 +100,7 @@ int modem_pipe_receive(struct modem_pipe *pipe, uint8_t *buf, size_t size)
}
ret = pipe->api->receive(pipe->data, buf, size);
pipe->receive_ready_pending = false;
k_mutex_unlock(&pipe->lock);
return ret;
}
@ -155,6 +162,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;
if (pipe->callback != NULL) {
pipe->callback(pipe, MODEM_PIPE_EVENT_CLOSED, pipe->user_data);
@ -168,6 +176,8 @@ void modem_pipe_notify_receive_ready(struct modem_pipe *pipe)
{
k_mutex_lock(&pipe->lock, K_FOREVER);
pipe->receive_ready_pending = true;
if (pipe->callback != NULL) {
pipe->callback(pipe, MODEM_PIPE_EVENT_RECEIVE_READY, pipe->user_data);
}

View file

@ -265,32 +265,26 @@ static void *test_modem_cmux_setup(void)
};
bus_mock_pipe = modem_backend_mock_init(&bus_mock, &bus_mock_config);
__ASSERT_NO_MSG(modem_pipe_open_async(bus_mock_pipe) == 0);
__ASSERT_NO_MSG(modem_pipe_open(bus_mock_pipe) == 0);
/* Connect CMUX */
__ASSERT_NO_MSG(modem_cmux_attach(&cmux, bus_mock_pipe) == 0);
modem_backend_mock_prime(&bus_mock, &transaction_control_sabm);
__ASSERT_NO_MSG(modem_cmux_connect_async(&cmux) == 0);
modem_backend_mock_put(&bus_mock, cmux_frame_control_sabm_ack,
sizeof(cmux_frame_control_sabm_ack));
events = k_event_wait(&cmux_event, EVENT_CMUX_CONNECTED, false, K_MSEC(100));
__ASSERT_NO_MSG(events == EVENT_CMUX_CONNECTED);
/* Open DLCI channels */
modem_pipe_attach(dlci1_pipe, test_modem_dlci1_pipe_callback, NULL);
modem_pipe_attach(dlci2_pipe, test_modem_dlci2_pipe_callback, NULL);
modem_backend_mock_prime(&bus_mock, &transaction_dlci1_sabm);
__ASSERT_NO_MSG(modem_pipe_open_async(dlci1_pipe) == 0);
__ASSERT_NO_MSG(modem_pipe_open_async(dlci2_pipe) == 0);
modem_backend_mock_put(&bus_mock, cmux_frame_dlci1_sabm_ack,
sizeof(cmux_frame_dlci1_sabm_ack));
modem_backend_mock_put(&bus_mock, cmux_frame_dlci2_sabm_ack,
sizeof(cmux_frame_dlci2_sabm_ack));
events = k_event_wait_all(&cmux_event, (EVENT_CMUX_DLCI1_OPEN | EVENT_CMUX_DLCI2_OPEN),
false, K_MSEC(100));
events = k_event_wait(&cmux_event, EVENT_CMUX_DLCI1_OPEN, false, K_MSEC(100));
__ASSERT_NO_MSG((events & EVENT_CMUX_DLCI1_OPEN));
modem_pipe_attach(dlci2_pipe, test_modem_dlci2_pipe_callback, NULL);
modem_backend_mock_prime(&bus_mock, &transaction_dlci2_sabm);
__ASSERT_NO_MSG(modem_pipe_open_async(dlci2_pipe) == 0);
events = k_event_wait(&cmux_event, EVENT_CMUX_DLCI2_OPEN, false, K_MSEC(100));
__ASSERT_NO_MSG((events & EVENT_CMUX_DLCI2_OPEN));
return NULL;