sim800.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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 <stdlib.h>
  15. #include <string.h>
  16. #include "esp_log.h"
  17. #include "esp_modem_dce_service.h"
  18. #include "sim800.h"
  19. #define MODEM_RESULT_CODE_POWERDOWN "POWER DOWN"
  20. /**
  21. * @brief Macro defined for error checking
  22. *
  23. */
  24. static const char *DCE_TAG = "sim800";
  25. #define DCE_CHECK(a, str, goto_tag, ...) \
  26. do \
  27. { \
  28. if (!(a)) \
  29. { \
  30. ESP_LOGE(DCE_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
  31. goto goto_tag; \
  32. } \
  33. } while (0)
  34. /**
  35. * @brief SIM800 Modem
  36. *
  37. */
  38. typedef struct {
  39. void *priv_resource; /*!< Private resource */
  40. modem_dce_t parent; /*!< DCE parent class */
  41. } sim800_modem_dce_t;
  42. /**
  43. * @brief Handle response from AT+CSQ
  44. */
  45. static esp_err_t sim800_handle_csq(modem_dce_t *dce, const char *line)
  46. {
  47. esp_err_t err = ESP_FAIL;
  48. sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
  49. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  50. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  51. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  52. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  53. } else if (!strncmp(line, "+CSQ", strlen("+CSQ"))) {
  54. /* store value of rssi and ber */
  55. uint32_t **csq = sim800_dce->priv_resource;
  56. /* +CSQ: <rssi>,<ber> */
  57. sscanf(line, "%*s%d,%d", csq[0], csq[1]);
  58. err = ESP_OK;
  59. }
  60. return err;
  61. }
  62. /**
  63. * @brief Handle response from AT+CBC
  64. */
  65. static esp_err_t sim800_handle_cbc(modem_dce_t *dce, const char *line)
  66. {
  67. esp_err_t err = ESP_FAIL;
  68. sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
  69. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  70. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  71. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  72. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  73. } else if (!strncmp(line, "+CBC", strlen("+CBC"))) {
  74. /* store value of bcs, bcl, voltage */
  75. uint32_t **cbc = sim800_dce->priv_resource;
  76. /* +CBC: <bcs>,<bcl>,<voltage> */
  77. sscanf(line, "%*s%d,%d,%d", cbc[0], cbc[1], cbc[2]);
  78. err = ESP_OK;
  79. }
  80. return err;
  81. }
  82. /**
  83. * @brief Handle response from +++
  84. */
  85. static esp_err_t sim800_handle_exit_data_mode(modem_dce_t *dce, const char *line)
  86. {
  87. esp_err_t err = ESP_FAIL;
  88. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  89. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  90. } else if (strstr(line, MODEM_RESULT_CODE_NO_CARRIER)) {
  91. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  92. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  93. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  94. }
  95. return err;
  96. }
  97. /**
  98. * @brief Handle response from ATD*99#
  99. */
  100. static esp_err_t sim800_handle_atd_ppp(modem_dce_t *dce, const char *line)
  101. {
  102. esp_err_t err = ESP_FAIL;
  103. if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
  104. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  105. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  106. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  107. }
  108. return err;
  109. }
  110. /**
  111. * @brief Handle response from AT+CGMM
  112. */
  113. static esp_err_t sim800_handle_cgmm(modem_dce_t *dce, const char *line)
  114. {
  115. esp_err_t err = ESP_FAIL;
  116. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  117. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  118. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  119. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  120. } else {
  121. int len = snprintf(dce->name, MODEM_MAX_NAME_LENGTH, "%s", line);
  122. if (len > 2) {
  123. /* Strip "\r\n" */
  124. strip_cr_lf_tail(dce->name, len);
  125. err = ESP_OK;
  126. }
  127. }
  128. return err;
  129. }
  130. /**
  131. * @brief Handle response from AT+CGSN
  132. */
  133. static esp_err_t sim800_handle_cgsn(modem_dce_t *dce, const char *line)
  134. {
  135. esp_err_t err = ESP_FAIL;
  136. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  137. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  138. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  139. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  140. } else {
  141. int len = snprintf(dce->imei, MODEM_IMEI_LENGTH + 1, "%s", line);
  142. if (len > 2) {
  143. /* Strip "\r\n" */
  144. strip_cr_lf_tail(dce->imei, len);
  145. err = ESP_OK;
  146. }
  147. }
  148. return err;
  149. }
  150. /**
  151. * @brief Handle response from AT+CIMI
  152. */
  153. static esp_err_t sim800_handle_cimi(modem_dce_t *dce, const char *line)
  154. {
  155. esp_err_t err = ESP_FAIL;
  156. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  157. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  158. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  159. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  160. } else {
  161. int len = snprintf(dce->imsi, MODEM_IMSI_LENGTH + 1, "%s", line);
  162. if (len > 2) {
  163. /* Strip "\r\n" */
  164. strip_cr_lf_tail(dce->imsi, len);
  165. err = ESP_OK;
  166. }
  167. }
  168. return err;
  169. }
  170. /**
  171. * @brief Handle response from AT+COPS?
  172. */
  173. static esp_err_t sim800_handle_cops(modem_dce_t *dce, const char *line)
  174. {
  175. esp_err_t err = ESP_FAIL;
  176. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  177. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  178. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  179. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  180. } else if (!strncmp(line, "+COPS", strlen("+COPS"))) {
  181. /* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
  182. /* strtok will break the string, we need to create a copy */
  183. size_t len = strlen(line);
  184. char *line_copy = malloc(len + 1);
  185. strcpy(line_copy, line);
  186. /* +COPS: <mode>[, <format>[, <oper>]] */
  187. char *str_ptr = NULL;
  188. char *p[3];
  189. uint8_t i = 0;
  190. /* strtok will broke string by replacing delimiter with '\0' */
  191. p[i] = strtok_r(line_copy, ",", &str_ptr);
  192. while (p[i]) {
  193. p[++i] = strtok_r(NULL, ",", &str_ptr);
  194. }
  195. if (i >= 3) {
  196. int len = snprintf(dce->oper, MODEM_MAX_OPERATOR_LENGTH, "%s", p[2]);
  197. if (len > 2) {
  198. /* Strip "\r\n" */
  199. strip_cr_lf_tail(dce->oper, len);
  200. err = ESP_OK;
  201. }
  202. }
  203. free(line_copy);
  204. }
  205. return err;
  206. }
  207. /**
  208. * @brief Handle response from AT+CPOWD=1
  209. */
  210. static esp_err_t sim800_handle_power_down(modem_dce_t *dce, const char *line)
  211. {
  212. esp_err_t err = ESP_FAIL;
  213. if (strstr(line, MODEM_RESULT_CODE_POWERDOWN)) {
  214. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  215. }
  216. return err;
  217. }
  218. /**
  219. * @brief Get signal quality
  220. *
  221. * @param dce Modem DCE object
  222. * @param rssi received signal strength indication
  223. * @param ber bit error ratio
  224. * @return esp_err_t
  225. * - ESP_OK on success
  226. * - ESP_FAIL on error
  227. */
  228. static esp_err_t sim800_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
  229. {
  230. modem_dte_t *dte = dce->dte;
  231. sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
  232. uint32_t *resource[2] = {rssi, ber};
  233. sim800_dce->priv_resource = resource;
  234. dce->handle_line = sim800_handle_csq;
  235. DCE_CHECK(dte->send_cmd(dte, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  236. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire signal quality failed", err);
  237. ESP_LOGD(DCE_TAG, "inquire signal quality ok");
  238. return ESP_OK;
  239. err:
  240. return ESP_FAIL;
  241. }
  242. /**
  243. * @brief Get battery status
  244. *
  245. * @param dce Modem DCE object
  246. * @param bcs Battery charge status
  247. * @param bcl Battery connection level
  248. * @param voltage Battery voltage
  249. * @return esp_err_t
  250. * - ESP_OK on success
  251. * - ESP_FAIL on error
  252. */
  253. static esp_err_t sim800_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
  254. {
  255. modem_dte_t *dte = dce->dte;
  256. sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
  257. uint32_t *resource[3] = {bcs, bcl, voltage};
  258. sim800_dce->priv_resource = resource;
  259. dce->handle_line = sim800_handle_cbc;
  260. DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  261. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
  262. ESP_LOGD(DCE_TAG, "inquire battery status ok");
  263. return ESP_OK;
  264. err:
  265. return ESP_FAIL;
  266. }
  267. /**
  268. * @brief Set Working Mode
  269. *
  270. * @param dce Modem DCE object
  271. * @param mode woking mode
  272. * @return esp_err_t
  273. * - ESP_OK on success
  274. * - ESP_FAIL on error
  275. */
  276. static esp_err_t sim800_set_working_mode(modem_dce_t *dce, modem_mode_t mode)
  277. {
  278. modem_dte_t *dte = dce->dte;
  279. switch (mode) {
  280. case MODEM_COMMAND_MODE:
  281. dce->handle_line = sim800_handle_exit_data_mode;
  282. DCE_CHECK(dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
  283. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
  284. ESP_LOGD(DCE_TAG, "enter command mode ok");
  285. dce->mode = MODEM_COMMAND_MODE;
  286. break;
  287. case MODEM_PPP_MODE:
  288. dce->handle_line = sim800_handle_atd_ppp;
  289. DCE_CHECK(dte->send_cmd(dte, "ATD*99#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
  290. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
  291. ESP_LOGD(DCE_TAG, "enter ppp mode ok");
  292. dce->mode = MODEM_PPP_MODE;
  293. break;
  294. default:
  295. ESP_LOGW(DCE_TAG, "unsupported working mode: %d", mode);
  296. goto err;
  297. break;
  298. }
  299. return ESP_OK;
  300. err:
  301. return ESP_FAIL;
  302. }
  303. /**
  304. * @brief Power down
  305. *
  306. * @param sim800_dce sim800 object
  307. * @return esp_err_t
  308. * - ESP_OK on success
  309. * - ESP_FAIL on error
  310. */
  311. static esp_err_t sim800_power_down(modem_dce_t *dce)
  312. {
  313. modem_dte_t *dte = dce->dte;
  314. dce->handle_line = sim800_handle_power_down;
  315. DCE_CHECK(dte->send_cmd(dte, "AT+CPOWD=1\r", MODEM_COMMAND_TIMEOUT_POWEROFF) == ESP_OK, "send command failed", err);
  316. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "power down failed", err);
  317. ESP_LOGD(DCE_TAG, "power down ok");
  318. return ESP_OK;
  319. err:
  320. return ESP_FAIL;
  321. }
  322. /**
  323. * @brief Get DCE module name
  324. *
  325. * @param sim800_dce sim800 object
  326. * @return esp_err_t
  327. * - ESP_OK on success
  328. * - ESP_FAIL on error
  329. */
  330. static esp_err_t sim800_get_module_name(sim800_modem_dce_t *sim800_dce)
  331. {
  332. modem_dte_t *dte = sim800_dce->parent.dte;
  333. sim800_dce->parent.handle_line = sim800_handle_cgmm;
  334. DCE_CHECK(dte->send_cmd(dte, "AT+CGMM\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  335. DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get module name failed", err);
  336. ESP_LOGD(DCE_TAG, "get module name ok");
  337. return ESP_OK;
  338. err:
  339. return ESP_FAIL;
  340. }
  341. /**
  342. * @brief Get DCE module IMEI number
  343. *
  344. * @param sim800_dce sim800 object
  345. * @return esp_err_t
  346. * - ESP_OK on success
  347. * - ESP_FAIL on error
  348. */
  349. static esp_err_t sim800_get_imei_number(sim800_modem_dce_t *sim800_dce)
  350. {
  351. modem_dte_t *dte = sim800_dce->parent.dte;
  352. sim800_dce->parent.handle_line = sim800_handle_cgsn;
  353. DCE_CHECK(dte->send_cmd(dte, "AT+CGSN\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  354. DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get imei number failed", err);
  355. ESP_LOGD(DCE_TAG, "get imei number ok");
  356. return ESP_OK;
  357. err:
  358. return ESP_FAIL;
  359. }
  360. /**
  361. * @brief Get DCE module IMSI number
  362. *
  363. * @param sim800_dce sim800 object
  364. * @return esp_err_t
  365. * - ESP_OK on success
  366. * - ESP_FAIL on error
  367. */
  368. static esp_err_t sim800_get_imsi_number(sim800_modem_dce_t *sim800_dce)
  369. {
  370. modem_dte_t *dte = sim800_dce->parent.dte;
  371. sim800_dce->parent.handle_line = sim800_handle_cimi;
  372. DCE_CHECK(dte->send_cmd(dte, "AT+CIMI\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  373. DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get imsi number failed", err);
  374. ESP_LOGD(DCE_TAG, "get imsi number ok");
  375. return ESP_OK;
  376. err:
  377. return ESP_FAIL;
  378. }
  379. /**
  380. * @brief Get Operator's name
  381. *
  382. * @param sim800_dce sim800 object
  383. * @return esp_err_t
  384. * - ESP_OK on success
  385. * - ESP_FAIL on error
  386. */
  387. static esp_err_t sim800_get_operator_name(sim800_modem_dce_t *sim800_dce)
  388. {
  389. modem_dte_t *dte = sim800_dce->parent.dte;
  390. sim800_dce->parent.handle_line = sim800_handle_cops;
  391. DCE_CHECK(dte->send_cmd(dte, "AT+COPS?\r", MODEM_COMMAND_TIMEOUT_OPERATOR) == ESP_OK, "send command failed", err);
  392. DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get network operator failed", err);
  393. ESP_LOGD(DCE_TAG, "get network operator ok");
  394. return ESP_OK;
  395. err:
  396. return ESP_FAIL;
  397. }
  398. /**
  399. * @brief Deinitialize SIM800 object
  400. *
  401. * @param dce Modem DCE object
  402. * @return esp_err_t
  403. * - ESP_OK on success
  404. * - ESP_FAIL on fail
  405. */
  406. static esp_err_t sim800_deinit(modem_dce_t *dce)
  407. {
  408. sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
  409. if (dce->dte) {
  410. dce->dte->dce = NULL;
  411. }
  412. free(sim800_dce);
  413. return ESP_OK;
  414. }
  415. modem_dce_t *sim800_init(modem_dte_t *dte)
  416. {
  417. DCE_CHECK(dte, "DCE should bind with a DTE", err);
  418. /* malloc memory for sim800_dce object */
  419. sim800_modem_dce_t *sim800_dce = calloc(1, sizeof(sim800_modem_dce_t));
  420. DCE_CHECK(sim800_dce, "calloc sim800_dce failed", err);
  421. /* Bind DTE with DCE */
  422. sim800_dce->parent.dte = dte;
  423. dte->dce = &(sim800_dce->parent);
  424. /* Bind methods */
  425. sim800_dce->parent.handle_line = NULL;
  426. sim800_dce->parent.sync = esp_modem_dce_sync;
  427. sim800_dce->parent.echo_mode = esp_modem_dce_echo;
  428. sim800_dce->parent.store_profile = esp_modem_dce_store_profile;
  429. sim800_dce->parent.set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
  430. sim800_dce->parent.define_pdp_context = esp_modem_dce_define_pdp_context;
  431. sim800_dce->parent.hang_up = esp_modem_dce_hang_up;
  432. sim800_dce->parent.get_signal_quality = sim800_get_signal_quality;
  433. sim800_dce->parent.get_battery_status = sim800_get_battery_status;
  434. sim800_dce->parent.set_working_mode = sim800_set_working_mode;
  435. sim800_dce->parent.power_down = sim800_power_down;
  436. sim800_dce->parent.deinit = sim800_deinit;
  437. /* Sync between DTE and DCE */
  438. DCE_CHECK(esp_modem_dce_sync(&(sim800_dce->parent)) == ESP_OK, "sync failed", err_io);
  439. /* Close echo */
  440. DCE_CHECK(esp_modem_dce_echo(&(sim800_dce->parent), false) == ESP_OK, "close echo mode failed", err_io);
  441. /* Get Module name */
  442. DCE_CHECK(sim800_get_module_name(sim800_dce) == ESP_OK, "get module name failed", err_io);
  443. /* Get IMEI number */
  444. DCE_CHECK(sim800_get_imei_number(sim800_dce) == ESP_OK, "get imei failed", err_io);
  445. /* Get IMSI number */
  446. DCE_CHECK(sim800_get_imsi_number(sim800_dce) == ESP_OK, "get imsi failed", err_io);
  447. /* Get operator name */
  448. DCE_CHECK(sim800_get_operator_name(sim800_dce) == ESP_OK, "get operator name failed", err_io);
  449. return &(sim800_dce->parent);
  450. err_io:
  451. free(sim800_dce);
  452. err:
  453. return NULL;
  454. }