bg96.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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 "bg96.h"
  18. #include "bg96_private.h"
  19. #define MODEM_RESULT_CODE_POWERDOWN "POWERED DOWN"
  20. static const char *DCE_TAG = "bg96";
  21. /**
  22. * @brief Handle response from AT+CSQ
  23. */
  24. static esp_err_t bg96_handle_csq(modem_dce_t *dce, const char *line)
  25. {
  26. esp_err_t err = ESP_FAIL;
  27. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  28. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  29. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  30. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  31. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  32. } else if (!strncmp(line, "+CSQ", strlen("+CSQ"))) {
  33. /* store value of rssi and ber */
  34. uint32_t **csq = bg96_dce->priv_resource;
  35. /* +CSQ: <rssi>,<ber> */
  36. sscanf(line, "%*s%d,%d", csq[0], csq[1]);
  37. err = ESP_OK;
  38. }
  39. return err;
  40. }
  41. /**
  42. * @brief Handle response from AT+CBC
  43. */
  44. static esp_err_t bg96_handle_cbc(modem_dce_t *dce, const char *line)
  45. {
  46. esp_err_t err = ESP_FAIL;
  47. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  48. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  49. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  50. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  51. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  52. } else if (!strncmp(line, "+CBC", strlen("+CBC"))) {
  53. /* store value of bcs, bcl, voltage */
  54. uint32_t **cbc = bg96_dce->priv_resource;
  55. /* +CBC: <bcs>,<bcl>,<voltage> */
  56. sscanf(line, "%*s%d,%d,%d", cbc[0], cbc[1], cbc[2]);
  57. err = ESP_OK;
  58. }
  59. return err;
  60. }
  61. /**
  62. * @brief Handle response from +++
  63. */
  64. static esp_err_t bg96_handle_exit_data_mode(modem_dce_t *dce, const char *line)
  65. {
  66. esp_err_t err = ESP_FAIL;
  67. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  68. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  69. } else if (strstr(line, MODEM_RESULT_CODE_NO_CARRIER)) {
  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. }
  74. return err;
  75. }
  76. /**
  77. * @brief Handle response from ATD*99#
  78. */
  79. static esp_err_t bg96_handle_atd_ppp(modem_dce_t *dce, const char *line)
  80. {
  81. esp_err_t err = ESP_FAIL;
  82. if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
  83. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  84. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  85. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  86. }
  87. return err;
  88. }
  89. /**
  90. * @brief Handle response from AT+CGMM
  91. */
  92. static esp_err_t bg96_handle_cgmm(modem_dce_t *dce, const char *line)
  93. {
  94. esp_err_t err = ESP_FAIL;
  95. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  96. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  97. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  98. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  99. } else {
  100. int len = snprintf(dce->name, MODEM_MAX_NAME_LENGTH, "%s", line);
  101. if (len > 2) {
  102. /* Strip "\r\n" */
  103. strip_cr_lf_tail(dce->name, len);
  104. err = ESP_OK;
  105. }
  106. }
  107. return err;
  108. }
  109. /**
  110. * @brief Handle response from AT+CGSN
  111. */
  112. static esp_err_t bg96_handle_cgsn(modem_dce_t *dce, const char *line)
  113. {
  114. esp_err_t err = ESP_FAIL;
  115. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  116. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  117. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  118. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  119. } else {
  120. int len = snprintf(dce->imei, MODEM_IMEI_LENGTH + 1, "%s", line);
  121. if (len > 2) {
  122. /* Strip "\r\n" */
  123. strip_cr_lf_tail(dce->imei, len);
  124. err = ESP_OK;
  125. }
  126. }
  127. return err;
  128. }
  129. /**
  130. * @brief Handle response from AT+CIMI
  131. */
  132. static esp_err_t bg96_handle_cimi(modem_dce_t *dce, const char *line)
  133. {
  134. esp_err_t err = ESP_FAIL;
  135. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  136. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  137. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  138. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  139. } else {
  140. int len = snprintf(dce->imsi, MODEM_IMSI_LENGTH + 1, "%s", line);
  141. if (len > 2) {
  142. /* Strip "\r\n" */
  143. strip_cr_lf_tail(dce->imsi, len);
  144. err = ESP_OK;
  145. }
  146. }
  147. return err;
  148. }
  149. /**
  150. * @brief Handle response from AT+COPS?
  151. */
  152. static esp_err_t bg96_handle_cops(modem_dce_t *dce, const char *line)
  153. {
  154. esp_err_t err = ESP_FAIL;
  155. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  156. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  157. } else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
  158. err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
  159. } else if (!strncmp(line, "+COPS", strlen("+COPS"))) {
  160. /* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
  161. /* strtok will break the string, we need to create a copy */
  162. size_t len = strlen(line);
  163. char *line_copy = malloc(len + 1);
  164. strcpy(line_copy, line);
  165. /* +COPS: <mode>[, <format>[, <oper>[, <Act>]]] */
  166. char *str_ptr = NULL;
  167. char *p[5];
  168. uint8_t i = 0;
  169. /* strtok will broke string by replacing delimiter with '\0' */
  170. p[i] = strtok_r(line_copy, ",", &str_ptr);
  171. while (p[i]) {
  172. p[++i] = strtok_r(NULL, ",", &str_ptr);
  173. }
  174. if (i >= 3) {
  175. int len = snprintf(dce->oper, MODEM_MAX_OPERATOR_LENGTH, "%s", p[2]);
  176. if (len > 2) {
  177. /* Strip "\r\n" */
  178. strip_cr_lf_tail(dce->oper, len);
  179. err = ESP_OK;
  180. }
  181. }
  182. if (i >= 4) {
  183. dce->act = (uint8_t)strtol(p[3], NULL, 0);
  184. }
  185. free(line_copy);
  186. }
  187. return err;
  188. }
  189. /**
  190. * @brief Handle response from AT+QPOWD=1
  191. */
  192. static esp_err_t bg96_handle_power_down(modem_dce_t *dce, const char *line)
  193. {
  194. esp_err_t err = ESP_FAIL;
  195. if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
  196. err = ESP_OK;
  197. } else if (strstr(line, MODEM_RESULT_CODE_POWERDOWN)) {
  198. err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
  199. }
  200. return err;
  201. }
  202. /**
  203. * @brief Get signal quality
  204. *
  205. * @param dce Modem DCE object
  206. * @param rssi received signal strength indication
  207. * @param ber bit error ratio
  208. * @return esp_err_t
  209. * - ESP_OK on success
  210. * - ESP_FAIL on error
  211. */
  212. static esp_err_t bg96_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
  213. {
  214. modem_dte_t *dte = dce->dte;
  215. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  216. uint32_t *resource[2] = {rssi, ber};
  217. bg96_dce->priv_resource = resource;
  218. dce->handle_line = bg96_handle_csq;
  219. DCE_CHECK(dte->send_cmd(dte, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  220. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire signal quality failed", err);
  221. ESP_LOGD(DCE_TAG, "inquire signal quality ok");
  222. return ESP_OK;
  223. err:
  224. return ESP_FAIL;
  225. }
  226. /**
  227. * @brief Get battery status
  228. *
  229. * @param dce Modem DCE object
  230. * @param bcs Battery charge status
  231. * @param bcl Battery connection level
  232. * @param voltage Battery voltage
  233. * @return esp_err_t
  234. * - ESP_OK on success
  235. * - ESP_FAIL on error
  236. */
  237. static esp_err_t bg96_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
  238. {
  239. modem_dte_t *dte = dce->dte;
  240. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  241. uint32_t *resource[3] = {bcs, bcl, voltage};
  242. bg96_dce->priv_resource = resource;
  243. dce->handle_line = bg96_handle_cbc;
  244. DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  245. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
  246. ESP_LOGD(DCE_TAG, "inquire battery status ok");
  247. return ESP_OK;
  248. err:
  249. return ESP_FAIL;
  250. }
  251. /**
  252. * @brief Set Working Mode
  253. *
  254. * @param dce Modem DCE object
  255. * @param mode woking mode
  256. * @return esp_err_t
  257. * - ESP_OK on success
  258. * - ESP_FAIL on error
  259. */
  260. static esp_err_t bg96_set_working_mode(modem_dce_t *dce, modem_mode_t mode)
  261. {
  262. modem_dte_t *dte = dce->dte;
  263. switch (mode) {
  264. case MODEM_COMMAND_MODE:
  265. vTaskDelay(pdMS_TO_TICKS(1000)); // spec: 1s delay for the modem to recognize the escape sequence
  266. dce->handle_line = bg96_handle_exit_data_mode;
  267. if (dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) != ESP_OK) {
  268. // "+++" Could fail if we are already in the command mode.
  269. // in that case we ignore the timeout and re-sync the modem
  270. ESP_LOGI(DCE_TAG, "Sending \"+++\" command failed");
  271. dce->handle_line = esp_modem_dce_handle_response_default;
  272. DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
  273. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
  274. } else {
  275. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
  276. }
  277. ESP_LOGD(DCE_TAG, "enter command mode ok");
  278. dce->mode = MODEM_COMMAND_MODE;
  279. break;
  280. case MODEM_PPP_MODE:
  281. dce->handle_line = bg96_handle_atd_ppp;
  282. DCE_CHECK(dte->send_cmd(dte, "ATD*99***1#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
  283. if (dce->state != MODEM_STATE_SUCCESS) {
  284. // Initiate PPP mode could fail, if we've already "dialed" the data call before.
  285. // in that case we retry with "ATO" to just resume the data mode
  286. ESP_LOGD(DCE_TAG, "enter ppp mode failed, retry with ATO");
  287. dce->handle_line = bg96_handle_atd_ppp;
  288. DCE_CHECK(dte->send_cmd(dte, "ATO\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
  289. DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
  290. }
  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 bg96_dce bg96 object
  307. * @return esp_err_t
  308. * - ESP_OK on success
  309. * - ESP_FAIL on error
  310. */
  311. static esp_err_t bg96_power_down(modem_dce_t *dce)
  312. {
  313. modem_dte_t *dte = dce->dte;
  314. dce->handle_line = bg96_handle_power_down;
  315. DCE_CHECK(dte->send_cmd(dte, "AT+QPOWD=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 bg96_dce bg96 object
  326. * @return esp_err_t
  327. * - ESP_OK on success
  328. * - ESP_FAIL on error
  329. */
  330. static esp_err_t bg96_get_module_name(bg96_modem_dce_t *bg96_dce)
  331. {
  332. modem_dte_t *dte = bg96_dce->parent.dte;
  333. bg96_dce->parent.handle_line = bg96_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(bg96_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 bg96_dce bg96 object
  345. * @return esp_err_t
  346. * - ESP_OK on success
  347. * - ESP_FAIL on error
  348. */
  349. static esp_err_t bg96_get_imei_number(bg96_modem_dce_t *bg96_dce)
  350. {
  351. modem_dte_t *dte = bg96_dce->parent.dte;
  352. bg96_dce->parent.handle_line = bg96_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(bg96_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 bg96_dce bg96 object
  364. * @return esp_err_t
  365. * - ESP_OK on success
  366. * - ESP_FAIL on error
  367. */
  368. static esp_err_t bg96_get_imsi_number(bg96_modem_dce_t *bg96_dce)
  369. {
  370. modem_dte_t *dte = bg96_dce->parent.dte;
  371. bg96_dce->parent.handle_line = bg96_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(bg96_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 dce Modem DCE object
  383. * @return esp_err_t
  384. * - ESP_OK on success
  385. * - ESP_FAIL on error
  386. */
  387. static esp_err_t bg96_get_operator_name(modem_dce_t *dce)
  388. {
  389. modem_dte_t *dte = dce->dte;
  390. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  391. bg96_dce->parent.handle_line = bg96_handle_cops;
  392. DCE_CHECK(dte->send_cmd(dte, "AT+COPS?\r", MODEM_COMMAND_TIMEOUT_OPERATOR) == ESP_OK, "send command failed", err);
  393. DCE_CHECK(bg96_dce->parent.state == MODEM_STATE_SUCCESS, "get network operator failed", err);
  394. ESP_LOGD(DCE_TAG, "get network operator ok");
  395. return ESP_OK;
  396. err:
  397. return ESP_FAIL;
  398. }
  399. /**
  400. * @brief Deinitialize BG96 object
  401. *
  402. * @param dce Modem DCE object
  403. * @return esp_err_t
  404. * - ESP_OK on success
  405. * - ESP_FAIL on fail
  406. */
  407. static esp_err_t bg96_deinit(modem_dce_t *dce)
  408. {
  409. bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
  410. if (dce->dte) {
  411. dce->dte->dce = NULL;
  412. }
  413. free(bg96_dce);
  414. return ESP_OK;
  415. }
  416. modem_dce_t *bg96_init(modem_dte_t *dte)
  417. {
  418. DCE_CHECK(dte, "DCE should bind with a DTE", err);
  419. /* malloc memory for bg96_dce object */
  420. bg96_modem_dce_t *bg96_dce = calloc(1, sizeof(bg96_modem_dce_t));
  421. DCE_CHECK(bg96_dce, "calloc bg96_dce failed", err);
  422. /* Bind DTE with DCE */
  423. bg96_dce->parent.dte = dte;
  424. dte->dce = &(bg96_dce->parent);
  425. /* Bind methods */
  426. bg96_dce->parent.handle_line = NULL;
  427. bg96_dce->parent.sync = esp_modem_dce_sync;
  428. bg96_dce->parent.echo_mode = esp_modem_dce_echo;
  429. bg96_dce->parent.store_profile = esp_modem_dce_store_profile;
  430. bg96_dce->parent.set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
  431. bg96_dce->parent.define_pdp_context = esp_modem_dce_define_pdp_context;
  432. bg96_dce->parent.hang_up = esp_modem_dce_hang_up;
  433. bg96_dce->parent.get_signal_quality = bg96_get_signal_quality;
  434. bg96_dce->parent.get_battery_status = bg96_get_battery_status;
  435. bg96_dce->parent.get_operator_name = bg96_get_operator_name;
  436. bg96_dce->parent.set_working_mode = bg96_set_working_mode;
  437. bg96_dce->parent.power_down = bg96_power_down;
  438. bg96_dce->parent.deinit = bg96_deinit;
  439. /* Sync between DTE and DCE */
  440. DCE_CHECK(esp_modem_dce_sync(&(bg96_dce->parent)) == ESP_OK, "sync failed", err_io);
  441. /* Close echo */
  442. DCE_CHECK(esp_modem_dce_echo(&(bg96_dce->parent), false) == ESP_OK, "close echo mode failed", err_io);
  443. /* Get Module name */
  444. DCE_CHECK(bg96_get_module_name(bg96_dce) == ESP_OK, "get module name failed", err_io);
  445. /* Get IMEI number */
  446. DCE_CHECK(bg96_get_imei_number(bg96_dce) == ESP_OK, "get imei failed", err_io);
  447. /* Get IMSI number */
  448. DCE_CHECK(bg96_get_imsi_number(bg96_dce) == ESP_OK, "get imsi failed", err_io);
  449. /* Get operator name */
  450. DCE_CHECK(bg96_get_operator_name(&(bg96_dce->parent)) == ESP_OK, "get operator name failed", err_io);
  451. return &(bg96_dce->parent);
  452. err_io:
  453. free(bg96_dce);
  454. err:
  455. return NULL;
  456. }