Skip to content

Commit d010092

Browse files
committed
modem: hl78xx: Add AT Shell support
Adds AT shell support for the HL78xx modem driver, enabling developers to send AT commands directly through the Zephyr shell for testing and debugging purposes. Signed-off-by: Zafer SEN <[email protected]>
1 parent 1e57488 commit d010092

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

drivers/modem/hl78xx/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ zephyr_library_sources(
1313
hl78xx_apis.c
1414
)
1515

16+
zephyr_library_sources_ifdef(
17+
CONFIG_MODEM_HL78XX_AT_SHELL
18+
hl78xx_at_shell.c
19+
)
20+
1621
add_subdirectory_ifdef(CONFIG_HL78XX_EVT_MONITOR hl78xx_evt_monitor)
1722

1823
zephyr_library_include_directories(
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (c) 2025 Netfeasa Ltd.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/shell/shell.h>
9+
#include <zephyr/modem/chat.h>
10+
#include <zephyr/modem/pipelink.h>
11+
#include <zephyr/sys/atomic.h>
12+
#include <hl78xx.h>
13+
14+
#include <zephyr/logging/log.h>
15+
LOG_MODULE_REGISTER(modem_at_shell, CONFIG_MODEM_LOG_LEVEL);
16+
17+
#define AT_SHELL_STATE_SCRIPT_RUNNING_BIT 1
18+
19+
const static struct device *modem = DEVICE_DT_GET(DT_ALIAS(modem));
20+
static struct modem_chat *at_shell_chat;
21+
static uint8_t at_shell_request_buf[CONFIG_MODEM_AT_SHELL_COMMAND_MAX_SIZE];
22+
static struct modem_chat_script_chat at_shell_script_chat[1];
23+
static struct modem_chat_match at_shell_script_chat_matches[2];
24+
static uint8_t at_shell_match_buf[CONFIG_MODEM_AT_SHELL_RESPONSE_MAX_SIZE];
25+
static const struct shell *at_shell_active_shell;
26+
static atomic_t at_shell_state;
27+
28+
static void at_shell_print_any_match(struct modem_chat *chat, char **argv, uint16_t argc,
29+
void *user_data)
30+
{
31+
if (at_shell_active_shell == NULL) {
32+
return;
33+
}
34+
35+
if (argc != 2) {
36+
return;
37+
}
38+
39+
shell_print(at_shell_active_shell, "%s", argv[1]);
40+
}
41+
42+
static void at_shell_print_match(struct modem_chat *chat, char **argv, uint16_t argc,
43+
void *user_data)
44+
{
45+
if (at_shell_active_shell == NULL) {
46+
return;
47+
}
48+
49+
if (argc != 1) {
50+
return;
51+
}
52+
53+
shell_print(at_shell_active_shell, "%s", argv[0]);
54+
}
55+
56+
MODEM_CHAT_MATCHES_DEFINE(at_shell_abort_matches,
57+
MODEM_CHAT_MATCH("+CME ERROR:", "", at_shell_print_match),
58+
MODEM_CHAT_MATCH("ERROR", "", at_shell_print_match));
59+
60+
static void at_shell_script_callback(struct modem_chat *chat, enum modem_chat_script_result result,
61+
void *user_data)
62+
{
63+
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT);
64+
}
65+
66+
MODEM_CHAT_SCRIPT_DEFINE(at_shell_script, at_shell_script_chat, at_shell_abort_matches,
67+
at_shell_script_callback, CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_MS);
68+
69+
static void at_shell_init_script_chat(void)
70+
{
71+
/* Match anything except the expected response without progressing script */
72+
modem_chat_match_init(&at_shell_script_chat_matches[0]);
73+
modem_chat_match_set_match(&at_shell_script_chat_matches[0], "");
74+
modem_chat_match_set_separators(&at_shell_script_chat_matches[0], "");
75+
modem_chat_match_set_callback(&at_shell_script_chat_matches[0], at_shell_print_any_match);
76+
modem_chat_match_set_partial(&at_shell_script_chat_matches[0], true);
77+
modem_chat_match_enable_wildcards(&at_shell_script_chat_matches[0], false);
78+
79+
/* Match the expected response and terminate script */
80+
modem_chat_match_init(&at_shell_script_chat_matches[1]);
81+
modem_chat_match_set_match(&at_shell_script_chat_matches[1], "");
82+
modem_chat_match_set_separators(&at_shell_script_chat_matches[1], "");
83+
modem_chat_match_set_callback(&at_shell_script_chat_matches[1], at_shell_print_match);
84+
modem_chat_match_set_partial(&at_shell_script_chat_matches[1], false);
85+
modem_chat_match_enable_wildcards(&at_shell_script_chat_matches[1], false);
86+
87+
modem_chat_script_chat_init(at_shell_script_chat);
88+
modem_chat_script_chat_set_response_matches(at_shell_script_chat,
89+
at_shell_script_chat_matches,
90+
ARRAY_SIZE(at_shell_script_chat_matches));
91+
modem_chat_script_chat_set_timeout(at_shell_script_chat,
92+
CONFIG_MODEM_AT_SHELL_RESPONSE_TIMEOUT_MS);
93+
}
94+
95+
static int hl78xx_at_shell_init(void)
96+
{
97+
struct hl78xx_data *data = NULL;
98+
99+
if (device_is_ready(modem) == false) {
100+
LOG_ERR("%d, %s Device %s is not ready", __LINE__, __func__, modem->name);
101+
}
102+
data = (struct hl78xx_data *)modem->data;
103+
if (data == NULL) {
104+
LOG_ERR("%d, %s Modem data is NULL", __LINE__, __func__);
105+
return -EINVAL;
106+
}
107+
at_shell_chat = &data->chat;
108+
109+
at_shell_init_script_chat();
110+
return 0;
111+
}
112+
113+
static int at_shell_cmd_handler(const struct shell *sh, size_t argc, char **argv)
114+
{
115+
int ret;
116+
117+
if (argc < 2) {
118+
return -EINVAL;
119+
}
120+
if (atomic_test_and_set_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT)) {
121+
shell_error(sh, "script is already running");
122+
return -EBUSY;
123+
}
124+
strncpy(at_shell_request_buf, argv[1], sizeof(at_shell_request_buf) - 1);
125+
ret = modem_chat_script_chat_set_request(at_shell_script_chat, at_shell_request_buf);
126+
if (ret < 0) {
127+
return -EINVAL;
128+
}
129+
if (argc == 3) {
130+
strncpy(at_shell_match_buf, argv[2], sizeof(at_shell_match_buf) - 1);
131+
} else {
132+
strncpy(at_shell_match_buf, "OK", sizeof(at_shell_match_buf) - 1);
133+
}
134+
ret = modem_chat_match_set_match(&at_shell_script_chat_matches[1], at_shell_match_buf);
135+
if (ret < 0) {
136+
return -EINVAL;
137+
}
138+
at_shell_active_shell = sh;
139+
ret = modem_chat_run_script_async(at_shell_chat, &at_shell_script);
140+
if (ret < 0) {
141+
shell_error(sh, "failed to start script");
142+
atomic_clear_bit(&at_shell_state, AT_SHELL_STATE_SCRIPT_RUNNING_BIT);
143+
}
144+
return ret;
145+
}
146+
147+
SHELL_STATIC_SUBCMD_SET_CREATE(modem_sub_cmds,
148+
SHELL_CMD_ARG(at, NULL, "at <command> <response>",
149+
at_shell_cmd_handler, 1, 2),
150+
SHELL_SUBCMD_SET_END);
151+
152+
SHELL_CMD_REGISTER(modem, &modem_sub_cmds, "Modem commands", NULL);
153+
154+
SYS_INIT(hl78xx_at_shell_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

0 commit comments

Comments
 (0)