Skip to content

Commit c0a2928

Browse files
JordanYateshenrikbrixandersen
authored andcommitted
modem: at_shell: extract user pipe handling
Extract the user pipe setup and claim/release logic so that it can be re-used by other software modules, if the AT shell is not used. Ideally the chat instance would live within the `modem_at_user_pipe.c` and be handed out by `modem_at_user_pipe_claim`, but the current chat API doesn't make this possible. Signed-off-by: Jordan Yates <[email protected]>
1 parent 9432e6c commit c0a2928

File tree

6 files changed

+200
-117
lines changed

6 files changed

+200
-117
lines changed

doc/releases/migration-guide-4.3.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ Networking
163163
164164
.. zephyr-keep-sorted-stop
165165
166+
Modem
167+
*****
168+
169+
* ``CONFIG_MODEM_AT_SHELL_USER_PIPE`` has been renamed to :kconfig:option:`CONFIG_MODEM_AT_USER_PIPE`.
170+
166171
Display
167172
*******
168173

drivers/modem/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ if (CONFIG_MODEM_SIM7080)
3636
endif()
3737

3838
zephyr_library_sources_ifdef(CONFIG_MODEM_CELLULAR modem_cellular.c)
39+
zephyr_library_sources_ifdef(CONFIG_MODEM_AT_USER_PIPE modem_at_user_pipe.c)
3940
zephyr_library_sources_ifdef(CONFIG_MODEM_AT_SHELL modem_at_shell.c)

drivers/modem/Kconfig.at_shell

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
# Copyright (c) 2024 Trackunit Corporation
22
# SPDX-License-Identifier: Apache-2.0
33

4-
config MODEM_AT_SHELL
5-
bool "AT command shell based on modem modules"
6-
select MODEM_MODULES
4+
config MODEM_AT_USER_PIPE
5+
bool "Modem AT command user pipe helpers"
6+
depends on $(dt_alias_enabled,modem)
77
select MODEM_CHAT
88
select MODEM_PIPE
99
select MODEM_PIPELINK
10+
help
11+
Utility functions for managing access to user pipes
12+
for arbitrary AT commands
13+
14+
config MODEM_AT_USER_PIPE_IDX
15+
int "User pipe number to use"
16+
depends on MODEM_AT_USER_PIPE
17+
default 0
18+
19+
config MODEM_AT_SHELL
20+
bool "AT command shell based on modem modules"
21+
select MODEM_MODULES
22+
select MODEM_AT_USER_PIPE
1023
depends on !MODEM_SHELL
1124
depends on !SHELL_WILDCARD
12-
depends on $(dt_alias_enabled,modem)
1325

1426
if MODEM_AT_SHELL
1527

16-
config MODEM_AT_SHELL_USER_PIPE
17-
int "User pipe number to use"
18-
default 0
19-
2028
config MODEM_AT_SHELL_RESPONSE_TIMEOUT_S
2129
int "Timeout waiting for response to AT command in seconds"
2230
default 5

drivers/modem/modem_at_shell.c

Lines changed: 17 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,14 @@
66

77
#include <zephyr/kernel.h>
88
#include <zephyr/shell/shell.h>
9+
#include <zephyr/modem/at/user_pipe.h>
910
#include <zephyr/modem/chat.h>
1011
#include <zephyr/modem/pipelink.h>
1112
#include <zephyr/sys/atomic.h>
1213

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

16-
#define AT_SHELL_MODEM_NODE DT_ALIAS(modem)
17-
#define AT_SHELL_PIPELINK_NAME _CONCAT(user_pipe_, CONFIG_MODEM_AT_SHELL_USER_PIPE)
18-
19-
#define AT_SHELL_STATE_ATTACHED_BIT 0
20-
#define AT_SHELL_STATE_SCRIPT_RUNNING_BIT 1
21-
22-
MODEM_PIPELINK_DT_DECLARE(AT_SHELL_MODEM_NODE, AT_SHELL_PIPELINK_NAME);
23-
24-
static struct modem_pipelink *at_shell_pipelink =
25-
MODEM_PIPELINK_DT_GET(AT_SHELL_MODEM_NODE, AT_SHELL_PIPELINK_NAME);
26-
2717
static struct modem_chat at_shell_chat;
2818
static uint8_t at_shell_chat_receive_buf[CONFIG_MODEM_AT_SHELL_CHAT_RECEIVE_BUF_SIZE];
2919
static uint8_t *at_shell_chat_argv_buf[2];
@@ -32,10 +22,6 @@ static struct modem_chat_script_chat at_shell_script_chat[1];
3222
static struct modem_chat_match at_shell_script_chat_matches[2];
3323
static uint8_t at_shell_match_buf[CONFIG_MODEM_AT_SHELL_RESPONSE_MAX_SIZE];
3424
static const struct shell *at_shell_active_shell;
35-
static struct k_work at_shell_open_pipe_work;
36-
static struct k_work at_shell_attach_chat_work;
37-
static struct k_work at_shell_release_chat_work;
38-
static atomic_t at_shell_state;
3925

4026
static void at_shell_print_any_match(struct modem_chat *chat, char **argv, uint16_t argc,
4127
void *user_data)
@@ -74,7 +60,7 @@ static void at_shell_script_callback(struct modem_chat *chat,
7460
enum modem_chat_script_result result,
7561
void *user_data)
7662
{
77-
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT);
63+
modem_at_user_pipe_release();
7864
}
7965

8066
MODEM_CHAT_SCRIPT_DEFINE(
@@ -85,83 +71,6 @@ MODEM_CHAT_SCRIPT_DEFINE(
8571
CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_S
8672
);
8773

88-
static void at_shell_pipe_callback(struct modem_pipe *pipe,
89-
enum modem_pipe_event event,
90-
void *user_data)
91-
{
92-
ARG_UNUSED(user_data);
93-
94-
switch (event) {
95-
case MODEM_PIPE_EVENT_OPENED:
96-
LOG_INF("pipe opened");
97-
k_work_submit(&at_shell_attach_chat_work);
98-
break;
99-
100-
default:
101-
break;
102-
}
103-
}
104-
105-
void at_shell_pipelink_callback(struct modem_pipelink *link,
106-
enum modem_pipelink_event event,
107-
void *user_data)
108-
{
109-
ARG_UNUSED(user_data);
110-
111-
switch (event) {
112-
case MODEM_PIPELINK_EVENT_CONNECTED:
113-
LOG_INF("pipe connected");
114-
k_work_submit(&at_shell_open_pipe_work);
115-
break;
116-
117-
case MODEM_PIPELINK_EVENT_DISCONNECTED:
118-
LOG_INF("pipe disconnected");
119-
k_work_submit(&at_shell_release_chat_work);
120-
break;
121-
122-
default:
123-
break;
124-
}
125-
}
126-
127-
static void at_shell_open_pipe_handler(struct k_work *work)
128-
{
129-
ARG_UNUSED(work);
130-
131-
LOG_INF("opening pipe");
132-
133-
modem_pipe_attach(modem_pipelink_get_pipe(at_shell_pipelink),
134-
at_shell_pipe_callback,
135-
NULL);
136-
137-
modem_pipe_open_async(modem_pipelink_get_pipe(at_shell_pipelink));
138-
}
139-
140-
static void at_shell_attach_chat_handler(struct k_work *work)
141-
{
142-
ARG_UNUSED(work);
143-
144-
modem_chat_attach(&at_shell_chat, modem_pipelink_get_pipe(at_shell_pipelink));
145-
atomic_set_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT);
146-
LOG_INF("chat attached");
147-
}
148-
149-
static void at_shell_release_chat_handler(struct k_work *work)
150-
{
151-
ARG_UNUSED(work);
152-
153-
modem_chat_release(&at_shell_chat);
154-
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT);
155-
LOG_INF("chat released");
156-
}
157-
158-
static void at_shell_init_work(void)
159-
{
160-
k_work_init(&at_shell_open_pipe_work, at_shell_open_pipe_handler);
161-
k_work_init(&at_shell_attach_chat_work, at_shell_attach_chat_handler);
162-
k_work_init(&at_shell_release_chat_work, at_shell_release_chat_handler);
163-
}
164-
16574
static void at_shell_init_chat(void)
16675
{
16776
const struct modem_chat_config at_shell_chat_config = {
@@ -204,17 +113,11 @@ static void at_shell_init_script_chat(void)
204113
CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_S);
205114
}
206115

207-
static void at_shell_init_pipelink(void)
208-
{
209-
modem_pipelink_attach(at_shell_pipelink, at_shell_pipelink_callback, NULL);
210-
}
211-
212116
static int at_shell_init(void)
213117
{
214-
at_shell_init_work();
215118
at_shell_init_chat();
216119
at_shell_init_script_chat();
217-
at_shell_init_pipelink();
120+
modem_at_user_pipe_init(&at_shell_chat);
218121
return 0;
219122
}
220123

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

231-
if (!atomic_test_bit(&at_shell_state, AT_SHELL_STATE_ATTACHED_BIT)) {
232-
shell_error(sh, "modem is not ready");
233-
return -EPERM;
234-
}
235-
236-
if (atomic_test_and_set_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT)) {
237-
shell_error(sh, "script is already running");
238-
return -EBUSY;
134+
ret = modem_at_user_pipe_claim();
135+
if (ret < 0) {
136+
switch (ret) {
137+
case -EPERM:
138+
shell_error(sh, "modem is not ready");
139+
break;
140+
case -EBUSY:
141+
shell_error(sh, "script is already running");
142+
break;
143+
default:
144+
shell_error(sh, "unknown");
145+
}
146+
return ret;
239147
}
240148

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

266174
return ret;

drivers/modem/modem_at_user_pipe.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright (c) 2025 Embeint Holdings Pty Ltd
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/modem/at/user_pipe.h>
9+
#include <zephyr/modem/pipelink.h>
10+
#include <zephyr/sys/atomic.h>
11+
#include <zephyr/logging/log.h>
12+
13+
#define AT_UTIL_MODEM_NODE DT_ALIAS(modem)
14+
#define AT_UTIL_PIPELINK_NAME _CONCAT(user_pipe_, CONFIG_MODEM_AT_USER_PIPE_IDX)
15+
16+
#define AT_UTIL_STATE_ATTACHED_BIT 0
17+
#define AT_UTIL_STATE_SCRIPT_RUNNING_BIT 1
18+
19+
MODEM_PIPELINK_DT_DECLARE(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);
20+
21+
static struct modem_pipelink *at_util_pipelink =
22+
MODEM_PIPELINK_DT_GET(AT_UTIL_MODEM_NODE, AT_UTIL_PIPELINK_NAME);
23+
24+
static struct k_work at_util_open_pipe_work;
25+
static struct k_work at_util_attach_chat_work;
26+
static struct k_work at_util_release_chat_work;
27+
static struct modem_chat *at_util_chat;
28+
static atomic_t at_util_state;
29+
30+
LOG_MODULE_REGISTER(modem_at_user_pipe, CONFIG_MODEM_LOG_LEVEL);
31+
32+
static void at_util_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
33+
void *user_data)
34+
{
35+
ARG_UNUSED(user_data);
36+
37+
switch (event) {
38+
case MODEM_PIPE_EVENT_OPENED:
39+
LOG_INF("pipe opened");
40+
k_work_submit(&at_util_attach_chat_work);
41+
break;
42+
43+
default:
44+
break;
45+
}
46+
}
47+
48+
void at_util_pipelink_callback(struct modem_pipelink *link, enum modem_pipelink_event event,
49+
void *user_data)
50+
{
51+
ARG_UNUSED(user_data);
52+
53+
switch (event) {
54+
case MODEM_PIPELINK_EVENT_CONNECTED:
55+
LOG_INF("pipe connected");
56+
k_work_submit(&at_util_open_pipe_work);
57+
break;
58+
59+
case MODEM_PIPELINK_EVENT_DISCONNECTED:
60+
LOG_INF("pipe disconnected");
61+
k_work_submit(&at_util_release_chat_work);
62+
break;
63+
64+
default:
65+
break;
66+
}
67+
}
68+
69+
static void at_util_open_pipe_handler(struct k_work *work)
70+
{
71+
ARG_UNUSED(work);
72+
73+
LOG_INF("opening pipe");
74+
75+
modem_pipe_attach(modem_pipelink_get_pipe(at_util_pipelink), at_util_pipe_callback, NULL);
76+
77+
modem_pipe_open_async(modem_pipelink_get_pipe(at_util_pipelink));
78+
}
79+
80+
static void at_util_attach_chat_handler(struct k_work *work)
81+
{
82+
ARG_UNUSED(work);
83+
84+
modem_chat_attach(at_util_chat, modem_pipelink_get_pipe(at_util_pipelink));
85+
atomic_set_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
86+
LOG_INF("chat attached");
87+
}
88+
89+
static void at_util_release_chat_handler(struct k_work *work)
90+
{
91+
ARG_UNUSED(work);
92+
93+
modem_chat_release(at_util_chat);
94+
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT);
95+
LOG_INF("chat released");
96+
}
97+
98+
void modem_at_user_pipe_init(struct modem_chat *chat)
99+
{
100+
at_util_chat = chat;
101+
/* Initialise workers and setup callbacks */
102+
k_work_init(&at_util_open_pipe_work, at_util_open_pipe_handler);
103+
k_work_init(&at_util_attach_chat_work, at_util_attach_chat_handler);
104+
k_work_init(&at_util_release_chat_work, at_util_release_chat_handler);
105+
modem_pipelink_attach(at_util_pipelink, at_util_pipelink_callback, NULL);
106+
}
107+
108+
int modem_at_user_pipe_claim(void)
109+
{
110+
if (!atomic_test_bit(&at_util_state, AT_UTIL_STATE_ATTACHED_BIT)) {
111+
return -EPERM;
112+
}
113+
114+
if (atomic_test_and_set_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT)) {
115+
return -EBUSY;
116+
}
117+
118+
return 0;
119+
}
120+
121+
void modem_at_user_pipe_release(void)
122+
{
123+
atomic_clear_bit(&at_util_state, AT_UTIL_STATE_SCRIPT_RUNNING_BIT);
124+
}

0 commit comments

Comments
 (0)