1 /** @file
2  * @brief Modem shell module
3  *
4  * Provide some modem shell commands that can be useful to applications.
5  */
6 
7 /*
8  * Copyright (c) 2018 Foundries.io
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #define LOG_MODULE_NAME modem_shell
14 
15 #include <zephyr/kernel.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <zephyr/device.h>
19 #include <zephyr/shell/shell.h>
20 
21 #include <zephyr/sys/printk.h>
22 
23 struct modem_shell_user_data {
24 	const struct shell *sh;
25 	void *user_data;
26 };
27 
28 #if defined(CONFIG_MODEM_CONTEXT)
29 #include "modem_context.h"
30 #define ms_context		modem_context
31 #define ms_max_context		CONFIG_MODEM_CONTEXT_MAX_NUM
32 #define ms_send(ctx_, buf_, size_) \
33 			(ctx_->iface.write(&ctx_->iface, buf_, size_))
34 #define ms_context_from_id	modem_context_from_id
35 #define UART_DEV_NAME(ctx)	(ctx->iface.dev->name)
36 #elif defined(CONFIG_MODEM_RECEIVER)
37 #include "modem_receiver.h"
38 #define ms_context		mdm_receiver_context
39 #define ms_max_context		CONFIG_MODEM_RECEIVER_MAX_CONTEXTS
40 #define ms_send			mdm_receiver_send
41 #define ms_context_from_id	mdm_receiver_context_from_id
42 #define UART_DEV_NAME(ctx_)	(ctx_->uart_dev->name)
43 #else
44 #error "MODEM_CONTEXT or MODEM_RECEIVER need to be enabled"
45 #endif
46 
cmd_modem_list(const struct shell * sh,size_t argc,char * argv[])47 static int cmd_modem_list(const struct shell *sh, size_t argc,
48 			  char *argv[])
49 {
50 	struct ms_context *mdm_ctx;
51 	int i, count = 0;
52 
53 	shell_fprintf(sh, SHELL_NORMAL, "Modem receivers:\n");
54 
55 	for (i = 0; i < ms_max_context; i++) {
56 		mdm_ctx = ms_context_from_id(i);
57 		if (mdm_ctx) {
58 			count++;
59 			shell_fprintf(sh, SHELL_NORMAL,
60 			     "%d:\tIface Device: %s\n"
61 				"\tManufacturer: %s\n"
62 				"\tModel:        %s\n"
63 				"\tRevision:     %s\n"
64 				"\tIMEI:         %s\n"
65 #if defined(CONFIG_MODEM_SIM_NUMBERS)
66 				"\tIMSI:         %s\n"
67 				"\tICCID:        %s\n"
68 #endif
69 #if defined(CONFIG_MODEM_CELL_INFO)
70 				"\tOperator:     %d\n"
71 				"\tLAC:          %d\n"
72 				"\tCellId:       %d\n"
73 				"\tAcT:          %d\n"
74 #endif
75 				"\tRSSI:         %d\n",
76 			       i,
77 			       UART_DEV_NAME(mdm_ctx),
78 			       mdm_ctx->data_manufacturer,
79 			       mdm_ctx->data_model,
80 			       mdm_ctx->data_revision,
81 			       mdm_ctx->data_imei,
82 #if defined(CONFIG_MODEM_SIM_NUMBERS)
83 			       mdm_ctx->data_imsi,
84 			       mdm_ctx->data_iccid,
85 #endif
86 #if defined(CONFIG_MODEM_CELL_INFO)
87 			       mdm_ctx->data_operator,
88 			       mdm_ctx->data_lac,
89 			       mdm_ctx->data_cellid,
90 			       mdm_ctx->data_act,
91 #endif
92 			       mdm_ctx->data_rssi ? *mdm_ctx->data_rssi : 0);
93 		}
94 	}
95 
96 	if (!count) {
97 		shell_fprintf(sh, SHELL_NORMAL, "None found.\n");
98 	}
99 
100 	return 0;
101 }
102 
cmd_modem_send(const struct shell * sh,size_t argc,char * argv[])103 static int cmd_modem_send(const struct shell *sh, size_t argc,
104 			  char *argv[])
105 {
106 	struct ms_context *mdm_ctx;
107 	char *endptr;
108 	int ret, i, arg = 1;
109 
110 	/* list */
111 	if (!argv[arg]) {
112 		shell_fprintf(sh, SHELL_ERROR,
113 			      "Please enter a modem index\n");
114 		return -EINVAL;
115 	}
116 
117 	/* <index> of modem receiver */
118 	i = (int)strtol(argv[arg], &endptr, 10);
119 	if (*endptr != '\0') {
120 		shell_fprintf(sh, SHELL_ERROR,
121 			      "Please enter a modem index\n");
122 		return -EINVAL;
123 	}
124 
125 	mdm_ctx = ms_context_from_id(i);
126 	if (!mdm_ctx) {
127 		shell_fprintf(sh, SHELL_ERROR, "Modem receiver not found!");
128 		return 0;
129 	}
130 
131 	for (i = arg + 1; i < argc; i++) {
132 		ret = ms_send(mdm_ctx, argv[i], strlen(argv[i]));
133 		if (ret < 0) {
134 			shell_fprintf(sh, SHELL_ERROR,
135 				      "Error sending '%s': %d\n", argv[i], ret);
136 			return 0;
137 		}
138 
139 		if (i == argc - 1) {
140 			ret = ms_send(mdm_ctx, "\r", 1);
141 		} else {
142 			ret = ms_send(mdm_ctx, " ", 1);
143 		}
144 
145 		if (ret < 0) {
146 			shell_fprintf(sh, SHELL_ERROR,
147 				      "Error sending (CRLF or space): %d\n",
148 				      ret);
149 			return 0;
150 		}
151 	}
152 
153 	return 0;
154 }
155 
cmd_modem_info(const struct shell * sh,size_t argc,char * argv[])156 static int cmd_modem_info(const struct shell *sh, size_t argc, char *argv[])
157 {
158 	struct ms_context *mdm_ctx;
159 	char *endptr;
160 	int i, arg = 1;
161 
162 	/* info */
163 	if (!argv[arg]) {
164 		shell_fprintf(sh, SHELL_ERROR,
165 			      "Please enter a modem index\n");
166 		return -EINVAL;
167 	}
168 
169 	/* <index> of modem receiver */
170 	i = (int)strtol(argv[arg], &endptr, 10);
171 	if (*endptr != '\0') {
172 		shell_fprintf(sh, SHELL_ERROR,
173 			      "Please enter a modem index\n");
174 		return -EINVAL;
175 	}
176 
177 	mdm_ctx = ms_context_from_id(i);
178 	if (!mdm_ctx) {
179 		shell_fprintf(sh, SHELL_ERROR, "Modem receiver not found!");
180 		return 0;
181 	}
182 
183 	shell_fprintf(sh, SHELL_NORMAL,
184 		      "Modem index      : %d\n"
185 		      "Iface Device     : %s\n"
186 		      "Manufacturer     : %s\n"
187 		      "Model            : %s\n"
188 		      "Revision         : %s\n"
189 		      "IMEI             : %s\n"
190 		      "RSSI             : %d\n",
191 		      i,
192 		      UART_DEV_NAME(mdm_ctx),
193 		      mdm_ctx->data_manufacturer,
194 		      mdm_ctx->data_model,
195 		      mdm_ctx->data_revision,
196 		      mdm_ctx->data_imei,
197 		      mdm_ctx->data_rssi ? *mdm_ctx->data_rssi : 0);
198 
199 	shell_fprintf(sh, SHELL_NORMAL, "GSM 07.10 muxing : disabled\n");
200 	return 0;
201 }
202 
203 SHELL_STATIC_SUBCMD_SET_CREATE(sub_modem,
204 	SHELL_CMD(info, NULL, "Show information for a modem", cmd_modem_info),
205 	SHELL_CMD(list, NULL, "List registered modems", cmd_modem_list),
206 	SHELL_CMD(send, NULL, "Send an AT <command> to a registered modem "
207 			      "receiver", cmd_modem_send),
208 	SHELL_SUBCMD_SET_END /* Array terminated. */
209 );
210 
211 SHELL_CMD_REGISTER(modem, &sub_modem, "Modem commands", NULL);
212