Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
39bcca3
[nrf fromtree] modem: at_shell: extract user pipe handling
JordanYates Sep 18, 2025
4165e0d
[nrf fromtree] modem: modem_cellular: Allow PPP interface to wake up …
SeppoTakalo Sep 24, 2025
4f83b20
[nrf fromtree] modem: cmux: Clean debugging a bit
SeppoTakalo Aug 26, 2025
6cf3119
[nrf fromtree] modem: cmux: Rework the drop handling
SeppoTakalo Aug 28, 2025
2e7bcc2
[nrf fromtree] modem: cmux: auto calculate work buffer sizes
JordanYates Oct 2, 2025
effa8e4
[nrf fromtree] drivers: modem: cellular: nRF91: Remove periodic chat …
SeppoTakalo Sep 24, 2025
b449959
[nrf fromtree] modem: cmux: Implement DM and NSC responses
SeppoTakalo Aug 26, 2025
5d9b691
[nrf fromtree] modem: cmux: Define macros for header size
SeppoTakalo Oct 10, 2025
7fb70e6
[nrf fromtree] modem: cmux: Handle C/R bit from address field
SeppoTakalo Aug 26, 2025
9191c78
[nrf fromtree] modem: modem_ppp: optimise frame wrapping
JordanYates Oct 4, 2025
e09b724
[nrf fromtree] modem: cmux: Combine state and event
SeppoTakalo Oct 10, 2025
3bb9abd
[nrf fromtree] modem: cmux: Handle CLD response
SeppoTakalo Oct 14, 2025
68760ce
[nrf fromtree] modem: cmux: Send disconnect event only after respondi…
SeppoTakalo Sep 25, 2025
90fa7e6
[nrf fromtree] drivers: modem: cellular: Close down CMUX before shut …
SeppoTakalo Sep 25, 2025
f521395
[nrf fromtree] modem: cmux: Implement Modem Status Command
SeppoTakalo Aug 26, 2025
61dcdb3
[nrf fromtree] drivers: modem: Extract common dts bindings
SeppoTakalo Sep 24, 2025
b757c1a
[nrf fromtree] doc: release-notes-4.3: Mention the backlog support fo…
rlubos Sep 16, 2025
6597eea
[nrf fromtree] modem: optional dedicated workqueue
JordanYates Oct 2, 2025
79c2008
[nrf fromlist] modem: cmux: Define encoding and decoding functions fo…
SeppoTakalo Oct 21, 2025
e2c075b
[nrf fromlist] drivers: modem: Implement support for DTR signal
SeppoTakalo Oct 23, 2025
d82765f
[nrf fromlist] modem: cmux: Implement Power Saving Control message
SeppoTakalo Oct 14, 2025
acfc210
[nrf fromlist] drivers: modem: Implement runtime power management for…
SeppoTakalo Oct 10, 2025
988e7d5
[nrf fromlist] drivers: modem: cellular: Use k_pipe instead of ringbu…
SeppoTakalo Oct 9, 2025
5b8dd84
[nrf fromlist] drivers: modem: Implement support for RING indicator
SeppoTakalo Sep 10, 2025
d2a6268
[nrf fromlist] modem: pipe: Don't return EPERM on closed pipe
SeppoTakalo Oct 13, 2025
4982b01
[nrf fromlist] modem: cmux: Add struct cmux_config into struct cmux
SeppoTakalo Oct 13, 2025
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
7 changes: 7 additions & 0 deletions doc/releases/migration-guide-4.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ Networking

.. zephyr-keep-sorted-stop

Modem
*****

* ``CONFIG_MODEM_AT_SHELL_USER_PIPE`` has been renamed to :kconfig:option:`CONFIG_MODEM_AT_USER_PIPE`.
* ``CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE`` has been updated to :kconfig:option:`CONFIG_MODEM_CMUX_WORK_BUFFER_SIZE_EXTRA`,
which only takes the number of extra bytes desired over the default of (:kconfig:option:`CONFIG_MODEM_CMUX_MTU` + 7).

Display
*******

Expand Down
11 changes: 11 additions & 0 deletions doc/releases/release-notes-4.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ New APIs and options

* :kconfig:option:`CONFIG_HAWKBIT_REBOOT_NONE`

* Modem

* :kconfig:option:`CONFIG_MODEM_DEDICATED_WORKQUEUE`

* Networking

* Sockets

* :c:func:`zsock_listen` now implements the ``backlog`` parameter support. The TCP server
socket will limit the number of pending incoming connections to that value.

* Power management

* :c:func:`pm_device_driver_deinit`
Expand Down
1 change: 1 addition & 0 deletions drivers/modem/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ if (CONFIG_MODEM_SIM7080)
endif()

zephyr_library_sources_ifdef(CONFIG_MODEM_CELLULAR modem_cellular.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_AT_USER_PIPE modem_at_user_pipe.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_AT_SHELL modem_at_shell.c)
24 changes: 16 additions & 8 deletions drivers/modem/Kconfig.at_shell
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
# Copyright (c) 2024 Trackunit Corporation
# SPDX-License-Identifier: Apache-2.0

config MODEM_AT_SHELL
bool "AT command shell based on modem modules"
select MODEM_MODULES
config MODEM_AT_USER_PIPE
bool "Modem AT command user pipe helpers"
depends on $(dt_alias_enabled,modem)
select MODEM_CHAT
select MODEM_PIPE
select MODEM_PIPELINK
help
Utility functions for managing access to user pipes
for arbitrary AT commands

config MODEM_AT_USER_PIPE_IDX
int "User pipe number to use"
depends on MODEM_AT_USER_PIPE
default 0

config MODEM_AT_SHELL
bool "AT command shell based on modem modules"
select MODEM_MODULES
select MODEM_AT_USER_PIPE
depends on !MODEM_SHELL
depends on !SHELL_WILDCARD
depends on $(dt_alias_enabled,modem)

if MODEM_AT_SHELL

config MODEM_AT_SHELL_USER_PIPE
int "User pipe number to use"
default 0

config MODEM_AT_SHELL_RESPONSE_TIMEOUT_S
int "Timeout waiting for response to AT command in seconds"
default 5
Expand Down
126 changes: 17 additions & 109 deletions drivers/modem/modem_at_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,14 @@

#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>
#include <zephyr/modem/at/user_pipe.h>
#include <zephyr/modem/chat.h>
#include <zephyr/modem/pipelink.h>
#include <zephyr/sys/atomic.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(modem_at_shell, CONFIG_MODEM_LOG_LEVEL);

#define AT_SHELL_MODEM_NODE DT_ALIAS(modem)
#define AT_SHELL_PIPELINK_NAME _CONCAT(user_pipe_, CONFIG_MODEM_AT_SHELL_USER_PIPE)

#define AT_SHELL_STATE_ATTACHED_BIT 0
#define AT_SHELL_STATE_SCRIPT_RUNNING_BIT 1

MODEM_PIPELINK_DT_DECLARE(AT_SHELL_MODEM_NODE, AT_SHELL_PIPELINK_NAME);

static struct modem_pipelink *at_shell_pipelink =
MODEM_PIPELINK_DT_GET(AT_SHELL_MODEM_NODE, AT_SHELL_PIPELINK_NAME);

static struct modem_chat at_shell_chat;
static uint8_t at_shell_chat_receive_buf[CONFIG_MODEM_AT_SHELL_CHAT_RECEIVE_BUF_SIZE];
static uint8_t *at_shell_chat_argv_buf[2];
Expand All @@ -32,10 +22,6 @@ static struct modem_chat_script_chat at_shell_script_chat[1];
static struct modem_chat_match at_shell_script_chat_matches[2];
static uint8_t at_shell_match_buf[CONFIG_MODEM_AT_SHELL_RESPONSE_MAX_SIZE];
static const struct shell *at_shell_active_shell;
static struct k_work at_shell_open_pipe_work;
static struct k_work at_shell_attach_chat_work;
static struct k_work at_shell_release_chat_work;
static atomic_t at_shell_state;

static void at_shell_print_any_match(struct modem_chat *chat, char **argv, uint16_t argc,
void *user_data)
Expand Down Expand Up @@ -74,7 +60,7 @@ static void at_shell_script_callback(struct modem_chat *chat,
enum modem_chat_script_result result,
void *user_data)
{
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT);
modem_at_user_pipe_release();
}

MODEM_CHAT_SCRIPT_DEFINE(
Expand All @@ -85,83 +71,6 @@ MODEM_CHAT_SCRIPT_DEFINE(
CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_S
);

static void at_shell_pipe_callback(struct modem_pipe *pipe,
enum modem_pipe_event event,
void *user_data)
{
ARG_UNUSED(user_data);

switch (event) {
case MODEM_PIPE_EVENT_OPENED:
LOG_INF("pipe opened");
k_work_submit(&at_shell_attach_chat_work);
break;

default:
break;
}
}

void at_shell_pipelink_callback(struct modem_pipelink *link,
enum modem_pipelink_event event,
void *user_data)
{
ARG_UNUSED(user_data);

switch (event) {
case MODEM_PIPELINK_EVENT_CONNECTED:
LOG_INF("pipe connected");
k_work_submit(&at_shell_open_pipe_work);
break;

case MODEM_PIPELINK_EVENT_DISCONNECTED:
LOG_INF("pipe disconnected");
k_work_submit(&at_shell_release_chat_work);
break;

default:
break;
}
}

static void at_shell_open_pipe_handler(struct k_work *work)
{
ARG_UNUSED(work);

LOG_INF("opening pipe");

modem_pipe_attach(modem_pipelink_get_pipe(at_shell_pipelink),
at_shell_pipe_callback,
NULL);

modem_pipe_open_async(modem_pipelink_get_pipe(at_shell_pipelink));
}

static void at_shell_attach_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);

modem_chat_attach(&at_shell_chat, modem_pipelink_get_pipe(at_shell_pipelink));
atomic_set_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT);
LOG_INF("chat attached");
}

static void at_shell_release_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);

modem_chat_release(&at_shell_chat);
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT);
LOG_INF("chat released");
}

static void at_shell_init_work(void)
{
k_work_init(&at_shell_open_pipe_work, at_shell_open_pipe_handler);
k_work_init(&at_shell_attach_chat_work, at_shell_attach_chat_handler);
k_work_init(&at_shell_release_chat_work, at_shell_release_chat_handler);
}

static void at_shell_init_chat(void)
{
const struct modem_chat_config at_shell_chat_config = {
Expand Down Expand Up @@ -204,17 +113,11 @@ static void at_shell_init_script_chat(void)
CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_S);
}

static void at_shell_init_pipelink(void)
{
modem_pipelink_attach(at_shell_pipelink, at_shell_pipelink_callback, NULL);
}

static int at_shell_init(void)
{
at_shell_init_work();
at_shell_init_chat();
at_shell_init_script_chat();
at_shell_init_pipelink();
modem_at_user_pipe_init(&at_shell_chat);
return 0;
}

Expand All @@ -228,14 +131,19 @@ static int at_shell_cmd_handler(const struct shell *sh, size_t argc, char **argv
return -EINVAL;
}

if (!atomic_test_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT)) {
shell_error(sh, "modem is not ready");
return -EPERM;
}

if (atomic_test_and_set_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT)) {
shell_error(sh, "script is already running");
return -EBUSY;
ret = modem_at_user_pipe_claim();
if (ret < 0) {
switch (ret) {
case -EPERM:
shell_error(sh, "modem is not ready");
break;
case -EBUSY:
shell_error(sh, "script is already running");
break;
default:
shell_error(sh, "unknown");
}
return ret;
}

strncpy(at_shell_request_buf, argv[1], sizeof(at_shell_request_buf) - 1);
Expand All @@ -260,7 +168,7 @@ static int at_shell_cmd_handler(const struct shell *sh, size_t argc, char **argv
ret = modem_chat_run_script_async(&at_shell_chat, &at_shell_script);
if (ret < 0) {
shell_error(sh, "failed to start script");
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT);
modem_at_user_pipe_release();
}

return ret;
Expand Down
124 changes: 124 additions & 0 deletions drivers/modem/modem_at_user_pipe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright (c) 2025 Embeint Holdings Pty Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/modem/at/user_pipe.h>
#include <zephyr/modem/pipelink.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/logging/log.h>

#define AT_UTIL_MODEM_NODE DT_ALIAS(modem)
#define AT_UTIL_PIPELINK_NAME _CONCAT(user_pipe_, CONFIG_MODEM_AT_USER_PIPE_IDX)

#define AT_UTIL_STATE_ATTACHED_BIT 0
#define AT_UTIL_STATE_SCRIPT_RUNNING_BIT 1

MODEM_PIPELINK_DT_DECLARE(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);

static struct modem_pipelink *at_util_pipelink =
MODEM_PIPELINK_DT_GET(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);

static struct k_work at_util_open_pipe_work;
static struct k_work at_util_attach_chat_work;
static struct k_work at_util_release_chat_work;
static struct modem_chat *at_util_chat;
static atomic_t at_util_state;

LOG_MODULE_REGISTER(modem_at_user_pipe, CONFIG_MODEM_LOG_LEVEL);

static void at_util_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
void *user_data)
{
ARG_UNUSED(user_data);

switch (event) {
case MODEM_PIPE_EVENT_OPENED:
LOG_INF("pipe opened");
k_work_submit(&at_util_attach_chat_work);
break;

default:
break;
}
}

void at_util_pipelink_callback(struct modem_pipelink *link, enum modem_pipelink_event event,
void *user_data)
{
ARG_UNUSED(user_data);

switch (event) {
case MODEM_PIPELINK_EVENT_CONNECTED:
LOG_INF("pipe connected");
k_work_submit(&at_util_open_pipe_work);
break;

case MODEM_PIPELINK_EVENT_DISCONNECTED:
LOG_INF("pipe disconnected");
k_work_submit(&at_util_release_chat_work);
break;

default:
break;
}
}

static void at_util_open_pipe_handler(struct k_work *work)
{
ARG_UNUSED(work);

LOG_INF("opening pipe");

modem_pipe_attach(modem_pipelink_get_pipe(at_util_pipelink), at_util_pipe_callback, NULL);

modem_pipe_open_async(modem_pipelink_get_pipe(at_util_pipelink));
}

static void at_util_attach_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);

modem_chat_attach(at_util_chat, modem_pipelink_get_pipe(at_util_pipelink));
atomic_set_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
LOG_INF("chat attached");
}

static void at_util_release_chat_handler(struct k_work *work)
{
ARG_UNUSED(work);

modem_chat_release(at_util_chat);
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
LOG_INF("chat released");
}

void modem_at_user_pipe_init(struct modem_chat *chat)
{
at_util_chat = chat;
/* Initialise workers and setup callbacks */
k_work_init(&at_util_open_pipe_work, at_util_open_pipe_handler);
k_work_init(&at_util_attach_chat_work, at_util_attach_chat_handler);
k_work_init(&at_util_release_chat_work, at_util_release_chat_handler);
modem_pipelink_attach(at_util_pipelink, at_util_pipelink_callback, NULL);
}

int modem_at_user_pipe_claim(void)
{
if (!atomic_test_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT)) {
return -EPERM;
}

if (atomic_test_and_set_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT)) {
return -EBUSY;
}

return 0;
}

void modem_at_user_pipe_release(void)
{
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT);
}
Loading
Loading