Skip to content
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 cmux DCE #65955

Merged
merged 3 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 99 additions & 9 deletions subsys/modem/modem_cmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,11 @@ static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
}
}

static void modem_cmux_on_msc_command(struct modem_cmux *cmux)
static void modem_cmux_on_msc_command(struct modem_cmux *cmux, struct modem_cmux_command *command)
{
modem_cmux_acknowledge_received_frame(cmux);
if (command->type.cr) {
modem_cmux_acknowledge_received_frame(cmux);
}
}

static void modem_cmux_on_fcon_command(struct modem_cmux *cmux)
Expand All @@ -361,17 +363,27 @@ static void modem_cmux_on_fcoff_command(struct modem_cmux *cmux)
modem_cmux_acknowledge_received_frame(cmux);
}

static void modem_cmux_on_cld_command(struct modem_cmux *cmux)
static void modem_cmux_on_cld_command(struct modem_cmux *cmux, struct modem_cmux_command *command)
{
if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING) {
if (command->type.cr) {
modem_cmux_acknowledge_received_frame(cmux);
}

if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING &&
cmux->state != MODEM_CMUX_STATE_CONNECTED) {
LOG_WRN("Unexpected close down");
return;
}

if (cmux->state == MODEM_CMUX_STATE_DISCONNECTING) {
k_work_cancel_delayable(&cmux->disconnect_work);
}

cmux->state = MODEM_CMUX_STATE_DISCONNECTED;
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
cmux->flow_control_on = false;
k_mutex_unlock(&cmux->transmit_rb_lock);
k_work_cancel_delayable(&cmux->disconnect_work);

modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_DISCONNECTED);
k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
Expand All @@ -381,7 +393,6 @@ static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux)
{
if (cmux->state != MODEM_CMUX_STATE_CONNECTING) {
LOG_DBG("Unexpected UA frame");

return;
}

Expand Down Expand Up @@ -414,11 +425,11 @@ static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)

switch (command->type.value) {
case MODEM_CMUX_COMMAND_CLD:
modem_cmux_on_cld_command(cmux);
modem_cmux_on_cld_command(cmux, command);
break;

case MODEM_CMUX_COMMAND_MSC:
modem_cmux_on_msc_command(cmux);
modem_cmux_on_msc_command(cmux, command);
break;

case MODEM_CMUX_COMMAND_FCON:
Expand All @@ -435,6 +446,40 @@ static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)
}
}

static void modem_cmux_connect_response_transmit(struct modem_cmux *cmux)
{
struct modem_cmux_frame frame = {
.dlci_address = cmux->frame.dlci_address,
.cr = cmux->frame.cr,
.pf = cmux->frame.pf,
.type = MODEM_CMUX_FRAME_TYPE_UA,
.data = NULL,
.data_len = 0,
};

LOG_DBG("SABM/DISC request state send ack");
modem_cmux_transmit_cmd_frame(cmux, &frame);
}

static void modem_cmux_on_control_frame_sabm(struct modem_cmux *cmux)
{
modem_cmux_connect_response_transmit(cmux);

if ((cmux->state == MODEM_CMUX_STATE_CONNECTED) ||
(cmux->state == MODEM_CMUX_STATE_DISCONNECTING)) {
LOG_DBG("Connect request not accepted");
return;
}

cmux->state = MODEM_CMUX_STATE_CONNECTED;
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
cmux->flow_control_on = true;
k_mutex_unlock(&cmux->transmit_rb_lock);
modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_CONNECTED);
k_event_clear(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
k_event_post(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
}

static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
{
modem_cmux_log_received_frame(&cmux->frame);
Expand All @@ -448,6 +493,10 @@ static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
modem_cmux_on_control_frame_uih(cmux);
break;

case MODEM_CMUX_FRAME_TYPE_SABM:
modem_cmux_on_control_frame_sabm(cmux);
break;

default:
LOG_WRN("Unknown %s frame type", "control");
break;
Expand Down Expand Up @@ -509,6 +558,39 @@ static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci)
modem_pipe_notify_receive_ready(&dlci->pipe);
}

static void modem_cmux_on_dlci_frame_sabm(struct modem_cmux_dlci *dlci)
{
struct modem_cmux *cmux = dlci->cmux;

modem_cmux_connect_response_transmit(cmux);

if (dlci->state == MODEM_CMUX_DLCI_STATE_OPEN) {
LOG_DBG("Unexpected SABM frame");
return;
}

dlci->state = MODEM_CMUX_DLCI_STATE_OPEN;
modem_pipe_notify_opened(&dlci->pipe);
k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
ring_buf_reset(&dlci->receive_rb);
k_mutex_unlock(&dlci->receive_rb_lock);
}

static void modem_cmux_on_dlci_frame_disc(struct modem_cmux_dlci *dlci)
{
struct modem_cmux *cmux = dlci->cmux;

modem_cmux_connect_response_transmit(cmux);

if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) {
LOG_DBG("Unexpected Disc frame");
return;
}

dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
modem_pipe_notify_closed(&dlci->pipe);
}

static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
{
struct modem_cmux_dlci *dlci;
Expand All @@ -532,6 +614,14 @@ static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
modem_cmux_on_dlci_frame_uih(dlci);
break;

case MODEM_CMUX_FRAME_TYPE_SABM:
modem_cmux_on_dlci_frame_sabm(dlci);
break;

case MODEM_CMUX_FRAME_TYPE_DISC:
modem_cmux_on_dlci_frame_disc(dlci);
break;

default:
LOG_WRN("Unknown %s frame type", "DLCI");
break;
Expand Down Expand Up @@ -996,6 +1086,7 @@ void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *co
k_work_init_delayable(&cmux->connect_work, modem_cmux_connect_handler);
k_work_init_delayable(&cmux->disconnect_work, modem_cmux_disconnect_handler);
k_event_init(&cmux->event);
k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
}

Expand Down Expand Up @@ -1071,7 +1162,6 @@ int modem_cmux_disconnect(struct modem_cmux *cmux)
if (ret < 0) {
return ret;
}

if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT, false,
MODEM_CMUX_T2_TIMEOUT) == 0) {
return -EAGAIN;
Expand Down
15 changes: 15 additions & 0 deletions tests/subsys/modem/mock/modem_backend_mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ static int modem_backend_mock_transmit(void *data, const uint8_t *buf, size_t si
int ret;

size = (mock->limit < size) ? mock->limit : size;

if (mock->bridge) {
struct modem_backend_mock *t_mock = mock->bridge;

ret = ring_buf_put(&t_mock->rx_rb, buf, size);
k_work_submit(&t_mock->received_work_item.work);
return ret;
}

ret = ring_buf_put(&mock->tx_rb, buf, size);
if (modem_backend_mock_update(mock, buf, size)) {
modem_backend_mock_put(mock, mock->transaction->put,
Expand Down Expand Up @@ -130,3 +139,9 @@ void modem_backend_mock_prime(struct modem_backend_mock *mock,
mock->transaction = transaction;
mock->transaction_match_cnt = 0;
}

void modem_backend_mock_bridge(struct modem_backend_mock *mock_a, struct modem_backend_mock *mock_b)
{
mock_a->bridge = mock_b;
mock_b->bridge = mock_a;
}
5 changes: 5 additions & 0 deletions tests/subsys/modem/mock/modem_backend_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ struct modem_backend_mock {

/* Max allowed read/write size */
size_t limit;
/* Mock Brige pair */
struct modem_backend_mock *bridge;
};

struct modem_backend_mock_config {
Expand All @@ -63,4 +65,7 @@ void modem_backend_mock_put(struct modem_backend_mock *mock, const uint8_t *buf,
void modem_backend_mock_prime(struct modem_backend_mock *mock,
const struct modem_backend_mock_transaction *transaction);

void modem_backend_mock_bridge(struct modem_backend_mock *mock_a,
struct modem_backend_mock *mock_b);

#endif /* ZEPHYR_DRIVERS_MODEM_MODEM_PIPE_MOCK */
9 changes: 9 additions & 0 deletions tests/subsys/modem/modem_cmux_pair/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(modem_cmux_pair_test)

target_sources(app PRIVATE src/main.c ../mock/modem_backend_mock.c)
target_include_directories(app PRIVATE ../mock)
9 changes: 9 additions & 0 deletions tests/subsys/modem/modem_cmux_pair/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

CONFIG_NO_OPTIMIZATIONS=y

CONFIG_MODEM_MODULES=y
CONFIG_MODEM_CMUX=y

CONFIG_ZTEST=y
Loading