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