1 // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <string.h>
15 #include "esp_log.h"
16 #include "esp_modem_dce_service.h"
17
18 static const char *DCE_TAG = "dce_service";
19
20 /**
21 * @brief Macro defined for error checking
22 *
23 */
24 #define DCE_CHECK(a, str, goto_tag, ...) \
25 do \
26 { \
27 if (!(a)) \
28 { \
29 ESP_LOGE(DCE_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
30 goto goto_tag; \
31 } \
32 } while (0)
33
esp_modem_dce_handle_response_default(modem_dce_t * dce,const char * line)34 esp_err_t esp_modem_dce_handle_response_default(modem_dce_t *dce, const char *line)
35 {
36 esp_err_t err = ESP_FAIL;
37 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
38 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
39 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
40 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
41 }
42 return err;
43 }
44
45 /**
46 * @brief Handle response from AT+CSQ (Get signal quality)
47 *
48 */
esp_modem_dce_handle_csq(modem_dce_t * dce,const char * line)49 static esp_err_t esp_modem_dce_handle_csq(modem_dce_t *dce, const char *line)
50 {
51 esp_err_t err = ESP_FAIL;
52 esp_modem_dce_t *esp_dce = __containerof(dce, esp_modem_dce_t, parent);
53 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
54 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
55 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
56 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
57 } else if (!strncmp(line, "+CSQ", strlen("+CSQ"))) {
58 /* store value of rssi and ber */
59 uint32_t **csq = esp_dce->priv_resource;
60 /* +CSQ: <rssi>,<ber> */
61 sscanf(line, "%*s%d,%d", csq[0], csq[1]);
62 err = ESP_OK;
63 }
64 return err;
65 }
66
67 /**
68 * @brief Handle response from AT+CBC (Get battery status)
69 *
70 */
esp_modem_dce_handle_cbc(modem_dce_t * dce,const char * line)71 static esp_err_t esp_modem_dce_handle_cbc(modem_dce_t *dce, const char *line)
72 {
73 esp_err_t err = ESP_FAIL;
74 esp_modem_dce_t *esp_dce = __containerof(dce, esp_modem_dce_t, parent);
75 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
76 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
77 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
78 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
79 } else if (!strncmp(line, "+CBC", strlen("+CBC"))) {
80 /* store value of bcs, bcl, voltage */
81 uint32_t **cbc = esp_dce->priv_resource;
82 /* +CBC: <bcs>,<bcl>,<voltage> */
83 sscanf(line, "%*s%d,%d,%d", cbc[0], cbc[1], cbc[2]);
84 err = ESP_OK;
85 }
86 return err;
87 }
88
esp_modem_dce_handle_exit_data_mode(modem_dce_t * dce,const char * line)89 esp_err_t esp_modem_dce_handle_exit_data_mode(modem_dce_t *dce, const char *line)
90 {
91 esp_err_t err = ESP_FAIL;
92 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
93 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
94 } else if (strstr(line, MODEM_RESULT_CODE_NO_CARRIER)) {
95 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
96 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
97 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
98 }
99 return err;
100 }
101
esp_modem_dce_handle_atd_ppp(modem_dce_t * dce,const char * line)102 esp_err_t esp_modem_dce_handle_atd_ppp(modem_dce_t *dce, const char *line)
103 {
104 esp_err_t err = ESP_FAIL;
105 if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
106 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
107 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
108 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
109 }
110 return err;
111 }
112
113 /**
114 * @brief Handle response from AT+CGMM (Get DCE module name)
115 *
116 */
esp_modem_dce_handle_cgmm(modem_dce_t * dce,const char * line)117 static esp_err_t esp_modem_dce_handle_cgmm(modem_dce_t *dce, const char *line)
118 {
119 esp_err_t err = ESP_FAIL;
120 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
121 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
122 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
123 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
124 } else {
125 int len = snprintf(dce->name, MODEM_MAX_NAME_LENGTH, "%s", line);
126 if (len > 2) {
127 /* Strip "\r\n" */
128 strip_cr_lf_tail(dce->name, len);
129 err = ESP_OK;
130 }
131 }
132 return err;
133 }
134
135 /**
136 * @brief Handle response from AT+CGSN (Get DCE module IMEI number)
137 *
138 */
esp_modem_dce_handle_cgsn(modem_dce_t * dce,const char * line)139 static esp_err_t esp_modem_dce_handle_cgsn(modem_dce_t *dce, const char *line)
140 {
141 esp_err_t err = ESP_FAIL;
142 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
143 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
144 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
145 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
146 } else {
147 int len = snprintf(dce->imei, MODEM_IMEI_LENGTH + 1, "%s", line);
148 if (len > 2) {
149 /* Strip "\r\n" */
150 strip_cr_lf_tail(dce->imei, len);
151 err = ESP_OK;
152 }
153 }
154 return err;
155 }
156
157 /**
158 * @brief Handle response from AT+CIMI (Get DCE module IMSI number)
159 *
160 */
esp_modem_dce_handle_cimi(modem_dce_t * dce,const char * line)161 static esp_err_t esp_modem_dce_handle_cimi(modem_dce_t *dce, const char *line)
162 {
163 esp_err_t err = ESP_FAIL;
164 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
165 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
166 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
167 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
168 } else {
169 int len = snprintf(dce->imsi, MODEM_IMSI_LENGTH + 1, "%s", line);
170 if (len > 2) {
171 /* Strip "\r\n" */
172 strip_cr_lf_tail(dce->imsi, len);
173 err = ESP_OK;
174 }
175 }
176 return err;
177 }
178
179 /**
180 * @brief Handle response from AT+COPS? (Get Operator's name)
181 *
182 */
esp_modem_dce_handle_cops(modem_dce_t * dce,const char * line)183 static esp_err_t esp_modem_dce_handle_cops(modem_dce_t *dce, const char *line)
184 {
185 esp_err_t err = ESP_FAIL;
186 if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
187 err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
188 } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
189 err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
190 } else if (!strncmp(line, "+COPS", strlen("+COPS"))) {
191 /* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
192 /* strtok will break the string, we need to create a copy */
193 size_t len = strlen(line);
194 char *line_copy = malloc(len + 1);
195 strcpy(line_copy, line);
196 /* +COPS: <mode>[, <format>[, <oper>[, <Act>]]] */
197 char *str_ptr = NULL;
198 char *p[5];
199 uint8_t i = 0;
200 /* strtok will broke string by replacing delimiter with '\0' */
201 p[i] = strtok_r(line_copy, ",", &str_ptr);
202 while (p[i]) {
203 p[++i] = strtok_r(NULL, ",", &str_ptr);
204 }
205 if (i >= 3) {
206 int len = snprintf(dce->oper, MODEM_MAX_OPERATOR_LENGTH, "%s", p[2]);
207 if (len > 2) {
208 /* Strip "\r\n" */
209 strip_cr_lf_tail(dce->oper, len);
210 err = ESP_OK;
211 }
212 }
213 if (i >= 4) {
214 dce->act = (uint8_t)strtol(p[3], NULL, 0);
215 }
216 free(line_copy);
217 }
218 return err;
219 }
220
esp_modem_dce_sync(modem_dce_t * dce)221 esp_err_t esp_modem_dce_sync(modem_dce_t *dce)
222 {
223 modem_dte_t *dte = dce->dte;
224 dce->handle_line = esp_modem_dce_handle_response_default;
225 DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
226 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
227 ESP_LOGD(DCE_TAG, "sync ok");
228 return ESP_OK;
229 err:
230 return ESP_FAIL;
231 }
232
esp_modem_dce_echo(modem_dce_t * dce,bool on)233 esp_err_t esp_modem_dce_echo(modem_dce_t *dce, bool on)
234 {
235 modem_dte_t *dte = dce->dte;
236 dce->handle_line = esp_modem_dce_handle_response_default;
237 if (on) {
238 DCE_CHECK(dte->send_cmd(dte, "ATE1\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
239 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enable echo failed", err);
240 ESP_LOGD(DCE_TAG, "enable echo ok");
241 } else {
242 DCE_CHECK(dte->send_cmd(dte, "ATE0\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
243 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "disable echo failed", err);
244 ESP_LOGD(DCE_TAG, "disable echo ok");
245 }
246 return ESP_OK;
247 err:
248 return ESP_FAIL;
249 }
250
esp_modem_dce_store_profile(modem_dce_t * dce)251 esp_err_t esp_modem_dce_store_profile(modem_dce_t *dce)
252 {
253 modem_dte_t *dte = dce->dte;
254 dce->handle_line = esp_modem_dce_handle_response_default;
255 DCE_CHECK(dte->send_cmd(dte, "AT&W\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
256 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "save settings failed", err);
257 ESP_LOGD(DCE_TAG, "save settings ok");
258 return ESP_OK;
259 err:
260 return ESP_FAIL;
261 }
262
esp_modem_dce_set_flow_ctrl(modem_dce_t * dce,modem_flow_ctrl_t flow_ctrl)263 esp_err_t esp_modem_dce_set_flow_ctrl(modem_dce_t *dce, modem_flow_ctrl_t flow_ctrl)
264 {
265 modem_dte_t *dte = dce->dte;
266 char command[16];
267 int len = snprintf(command, sizeof(command), "AT+IFC=%d,%d\r", dte->flow_ctrl, flow_ctrl);
268 DCE_CHECK(len < sizeof(command), "command too long: %s", err, command);
269 dce->handle_line = esp_modem_dce_handle_response_default;
270 DCE_CHECK(dte->send_cmd(dte, command, MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
271 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "set flow control failed", err);
272 ESP_LOGD(DCE_TAG, "set flow control ok");
273 return ESP_OK;
274 err:
275 return ESP_FAIL;
276 }
277
esp_modem_dce_define_pdp_context(modem_dce_t * dce,uint32_t cid,const char * type,const char * apn)278 esp_err_t esp_modem_dce_define_pdp_context(modem_dce_t *dce, uint32_t cid, const char *type, const char *apn)
279 {
280 modem_dte_t *dte = dce->dte;
281 char command[64];
282 int len = snprintf(command, sizeof(command), "AT+CGDCONT=%d,\"%s\",\"%s\"\r", cid, type, apn);
283 DCE_CHECK(len < sizeof(command), "command too long: %s", err, command);
284 dce->handle_line = esp_modem_dce_handle_response_default;
285 DCE_CHECK(dte->send_cmd(dte, command, MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
286 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "define pdp context failed", err);
287 ESP_LOGD(DCE_TAG, "define pdp context ok");
288 return ESP_OK;
289 err:
290 return ESP_FAIL;
291 }
292
esp_modem_dce_get_signal_quality(modem_dce_t * dce,uint32_t * rssi,uint32_t * ber)293 esp_err_t esp_modem_dce_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
294 {
295 modem_dte_t *dte = dce->dte;
296 esp_modem_dce_t *esp_dce = __containerof(dce, esp_modem_dce_t, parent);
297 uint32_t *resource[2] = {rssi, ber};
298 esp_dce->priv_resource = resource;
299 dce->handle_line = esp_modem_dce_handle_csq;
300 DCE_CHECK(dte->send_cmd(dte, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
301 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire signal quality failed", err);
302 ESP_LOGD(DCE_TAG, "inquire signal quality ok");
303 return ESP_OK;
304 err:
305 return ESP_FAIL;
306 }
307
esp_modem_dce_get_battery_status(modem_dce_t * dce,uint32_t * bcs,uint32_t * bcl,uint32_t * voltage)308 esp_err_t esp_modem_dce_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
309 {
310 modem_dte_t *dte = dce->dte;
311 esp_modem_dce_t *esp_dce = __containerof(dce, esp_modem_dce_t, parent);
312 uint32_t *resource[3] = {bcs, bcl, voltage};
313 esp_dce->priv_resource = resource;
314 dce->handle_line = esp_modem_dce_handle_cbc;
315 DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
316 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
317 ESP_LOGD(DCE_TAG, "inquire battery status ok");
318 return ESP_OK;
319 err:
320 return ESP_FAIL;
321 }
322
esp_modem_dce_get_module_name(modem_dce_t * dce)323 esp_err_t esp_modem_dce_get_module_name(modem_dce_t *dce)
324 {
325 modem_dte_t *dte = dce->dte;
326 dce->handle_line = esp_modem_dce_handle_cgmm;
327 DCE_CHECK(dte->send_cmd(dte, "AT+CGMM\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
328 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "get module name failed", err);
329 ESP_LOGD(DCE_TAG, "get module name ok");
330 return ESP_OK;
331 err:
332 return ESP_FAIL;
333 }
334
esp_modem_dce_get_imei_number(modem_dce_t * dce)335 esp_err_t esp_modem_dce_get_imei_number(modem_dce_t *dce)
336 {
337 modem_dte_t *dte = dce->dte;
338 dce->handle_line = esp_modem_dce_handle_cgsn;
339 DCE_CHECK(dte->send_cmd(dte, "AT+CGSN\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
340 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "get imei number failed", err);
341 ESP_LOGD(DCE_TAG, "get imei number ok");
342 return ESP_OK;
343 err:
344 return ESP_FAIL;
345 }
346
esp_modem_dce_get_imsi_number(modem_dce_t * dce)347 esp_err_t esp_modem_dce_get_imsi_number(modem_dce_t *dce)
348 {
349 modem_dte_t *dte = dce->dte;
350 dce->handle_line = esp_modem_dce_handle_cimi;
351 DCE_CHECK(dte->send_cmd(dte, "AT+CIMI\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
352 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "get imsi number failed", err);
353 ESP_LOGD(DCE_TAG, "get imsi number ok");
354 return ESP_OK;
355 err:
356 return ESP_FAIL;
357 }
358
esp_modem_dce_get_operator_name(modem_dce_t * dce)359 esp_err_t esp_modem_dce_get_operator_name(modem_dce_t *dce)
360 {
361 modem_dte_t *dte = dce->dte;
362 dce->handle_line = esp_modem_dce_handle_cops;
363 DCE_CHECK(dte->send_cmd(dte, "AT+COPS?\r", MODEM_COMMAND_TIMEOUT_OPERATOR) == ESP_OK, "send command failed", err);
364 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "get network operator failed", err);
365 ESP_LOGD(DCE_TAG, "get network operator ok");
366 return ESP_OK;
367 err:
368 return ESP_FAIL;
369 }
370
esp_modem_dce_hang_up(modem_dce_t * dce)371 esp_err_t esp_modem_dce_hang_up(modem_dce_t *dce)
372 {
373 modem_dte_t *dte = dce->dte;
374 dce->handle_line = esp_modem_dce_handle_response_default;
375 DCE_CHECK(dte->send_cmd(dte, "ATH\r", MODEM_COMMAND_TIMEOUT_HANG_UP) == ESP_OK, "send command failed", err);
376 DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "hang up failed", err);
377 ESP_LOGD(DCE_TAG, "hang up ok");
378 return ESP_OK;
379 err:
380 return ESP_FAIL;
381 }
382