|
@@ -0,0 +1,414 @@
|
|
|
|
|
+#include "ec200u.h"
|
|
|
|
|
+#include "../swapi/subjects/serial/serial.h"
|
|
|
|
|
+
|
|
|
|
|
+// 模块名称
|
|
|
|
|
+static const char MODULE_NAME[] = "EC200U";
|
|
|
|
|
+
|
|
|
|
|
+#define MAX_CMD_CHARS 65535 // 单条指令最大字符数
|
|
|
|
|
+#define MAX_ACK_CHARS 65535 // 指令应答最大字符数
|
|
|
|
|
+#define WAIT_ACK_TIMEOUT 9000 // 等待应答超时时间ms
|
|
|
|
|
+#define R_SILENT_TIMEOUT 50 // 应答静默超时时间ms
|
|
|
|
|
+
|
|
|
|
|
+// 关闭命令回显模式
|
|
|
|
|
+static const char *AT_USE_ECHO = "ATE0" ;
|
|
|
|
|
+// 获取模块的IMEI号
|
|
|
|
|
+static const char *AT_GET_IMEI = "AT+CGSN" ;
|
|
|
|
|
+// 查看网络注册状态
|
|
|
|
|
+static const char *AT_GET_CREG = "AT+CREG?";
|
|
|
|
|
+// 获取当前信号强度
|
|
|
|
|
+static const char *AT_GET_CSQ = "AT+CSQ" ;
|
|
|
|
|
+// 获取SIM-PIN状态
|
|
|
|
|
+static const char *AT_GET_PINSTA = "AT+CPIN?";
|
|
|
|
|
+// 获取SIM-ICCID号
|
|
|
|
|
+static const char *AT_GET_ICCID = "AT+ICCID";
|
|
|
|
|
+// 激活USB网络模式
|
|
|
|
|
+static const char *AT_QCFG_CMD1 = "AT+QCFG=\"usbnet\",1";
|
|
|
|
|
+static const char *AT_QCFG_CMD2 = "AT+qnetdevctl=1,1,1" ;
|
|
|
|
|
+
|
|
|
|
|
+// AT指令请求和应答
|
|
|
|
|
+typedef struct
|
|
|
|
|
+{
|
|
|
|
|
+ // 指令
|
|
|
|
|
+ struct
|
|
|
|
|
+ {
|
|
|
|
|
+ char data[MAX_CMD_CHARS+1]; // 指令数据(字符串)
|
|
|
|
|
+ int len; // 指令长度
|
|
|
|
|
+ } cmd;
|
|
|
|
|
+ // 等待执行结束的超时ms
|
|
|
|
|
+ int timeout;
|
|
|
|
|
+ // 等待执行结束的信号量
|
|
|
|
|
+ void *hEndSgl;
|
|
|
|
|
+ // 应答
|
|
|
|
|
+ struct
|
|
|
|
|
+ {
|
|
|
|
|
+ int ret; // 返回值: >0时执行成功, 表明应答数据的长度; <0时出错(-1超时)
|
|
|
|
|
+ char data[MAX_ACK_CHARS+1]; // 应答数据(字符串)
|
|
|
|
|
+ } ack;
|
|
|
|
|
+} SATCmdTrans;
|
|
|
|
|
+
|
|
|
|
|
+// 与模块的串口通讯
|
|
|
|
|
+typedef struct
|
|
|
|
|
+{
|
|
|
|
|
+ void *h; // 打开的串口句柄
|
|
|
|
|
+ void *do_cmd_mutex; // 指令执行互斥量, 同一时刻正在执行的指令只能有一条
|
|
|
|
|
+ SATCmdTrans *pTrans; // 执行的指令及其应答结果: 空闲时为空, 工作时不为空
|
|
|
|
|
+} SEC200UCom;
|
|
|
|
|
+
|
|
|
|
|
+static SEC200UCom s_myCom;
|
|
|
|
|
+
|
|
|
|
|
+// 定义AT指令格式符
|
|
|
|
|
+#define CR '\r' // 回车
|
|
|
|
|
+#define LF '\n' // 换行
|
|
|
|
|
+#define CRLF "\r\n" // 回车换行
|
|
|
|
|
+#define ATOK "\r\nOK\r\n" // 应答成功
|
|
|
|
|
+#define ATER "ERROR" // 应答失败
|
|
|
|
|
+
|
|
|
|
|
+// 执行一条指令, 返回: 大于0成功; 小于0失败(-1命令超时)
|
|
|
|
|
+static int comio_doCmd(SATCmdTrans *pTrans/*要执行的指令(IN&OUT)*/, int timeout/*等待应答的超时时间, 单位是毫秒*/)
|
|
|
|
|
+{
|
|
|
|
|
+ SEC200UCom *pComIO = &s_myCom; const char *log_prefix = serial_get_log_prefix(pComIO->h);
|
|
|
|
|
+ unsigned long stime, wtime, etime; char *pAtCmdStr; int atCmdLen, ret;
|
|
|
|
|
+
|
|
|
|
|
+ xgettickcount(&stime);
|
|
|
|
|
+ ret = sw_mutex_lock(pComIO->do_cmd_mutex, timeout);
|
|
|
|
|
+ if(ret != 0) { pTrans->ack.ret = -1; goto end_p; } // 互斥量上锁超时
|
|
|
|
|
+ xgettickcount(&etime); wtime = etime - stime;
|
|
|
|
|
+
|
|
|
|
|
+ pTrans->hEndSgl = sw_signal_create();
|
|
|
|
|
+ if(!pTrans->hEndSgl) { pTrans->ack.ret = -2; goto end_p; }
|
|
|
|
|
+
|
|
|
|
|
+ pAtCmdStr = (char *)sw_heap_malloc(pTrans->cmd.len+2);
|
|
|
|
|
+ if(!pAtCmdStr) { pTrans->ack.ret = -3; goto end_p; }
|
|
|
|
|
+ memcpy(pAtCmdStr, pTrans->cmd.data, pTrans->cmd.len);
|
|
|
|
|
+ pAtCmdStr[pTrans->cmd.len] = CR; pAtCmdStr[pTrans->cmd.len+1] = '\0';
|
|
|
|
|
+ atCmdLen = strlen((const char *)pAtCmdStr);
|
|
|
|
|
+
|
|
|
|
|
+ serial_recvThrd_pause(pComIO->h); sw_thrd_delay(THRDWAIT_DELAY); // "pComIO->pTrans"的控制权转移前, 先暂停串口数据的接收
|
|
|
|
|
+ ret = serial_send_data(pComIO->h, (unsigned char *)pAtCmdStr, atCmdLen); // 发送一条指令
|
|
|
|
|
+ sw_heap_free(pAtCmdStr); // 释放AT指令字符串内存
|
|
|
|
|
+ if(ret == atCmdLen)
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_trace("[%s] %s send a cmd(%d bytes): %s", MODULE_NAME, log_prefix, pTrans->cmd.len, pTrans->cmd.data);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_error("[%s] %s failed to send a cmd(%d bytes, ret=%d): %s!!", MODULE_NAME, log_prefix, pTrans->cmd.len, ret, pTrans->cmd.data);
|
|
|
|
|
+ serial_recvThrd_resume(pComIO->h); pTrans->ack.ret = -4; goto end_p;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pTrans->timeout = (wtime > timeout ? 0 : (timeout - wtime));
|
|
|
|
|
+ pComIO->pTrans = pTrans; serial_recvThrd_resume(pComIO->h); // 恢复串口数据接收, "pComIO->pTrans"的控制权转移给接收线程.
|
|
|
|
|
+ sw_signal_wait(pTrans->hEndSgl, WAIT_FOREVER); // 等待指令执行结束, "pComIO->pTrans"的控制权收回
|
|
|
|
|
+
|
|
|
|
|
+end_p:
|
|
|
|
|
+ if(pTrans->hEndSgl) sw_signal_destroy(pTrans->hEndSgl);
|
|
|
|
|
+ pComIO->pTrans = NULL;
|
|
|
|
|
+ sw_mutex_unlock(pComIO->do_cmd_mutex);
|
|
|
|
|
+ return pTrans->ack.ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 接收、处理来自EC200U模块的数据报文帧, 串口-线程回调
|
|
|
|
|
+static int comio_data_recv_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
|
|
|
|
|
+{
|
|
|
|
|
+ SEC200UCom *pComIO = &s_myCom; void *pSerial = pComIO->h; SATCmdTrans *pTrans = pComIO->pTrans;
|
|
|
|
|
+ const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
|
|
|
|
|
+ const char *log_prefix = serial_get_log_prefix(pSerial); bool bPrintRecvBuf = true;
|
|
|
|
|
+ static unsigned long enteredWaitAckTime = 0, now; static unsigned long enteredSilentTime = 0; static int nSilentRecvBytes = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if(!pTrans) { goto ret_p2; } // 无主动指令时
|
|
|
|
|
+
|
|
|
|
|
+ // 1, 计算命令应答超时
|
|
|
|
|
+ if(enteredWaitAckTime == 0) xgettickcount(&enteredWaitAckTime);
|
|
|
|
|
+ xgettickcount(&now);
|
|
|
|
|
+
|
|
|
|
|
+ // 2, 分析应答回复内容
|
|
|
|
|
+ if(strstr((const char *)pRecvBuf, ATOK) != NULL || strstr((const char *)pRecvBuf, ATER) != NULL)
|
|
|
|
|
+ { // 已应答
|
|
|
|
|
+ if(nRecvBytes > nSilentRecvBytes) { enteredSilentTime = now; nSilentRecvBytes = nRecvBytes; }
|
|
|
|
|
+ if((now-enteredSilentTime) < R_SILENT_TIMEOUT) { goto ret_p3; } // 等待静默期结束(延期多接收一会数据, 避免"内容"在"ATOK"或"ATER"之后)
|
|
|
|
|
+ memcpy(pTrans->ack.data, pRecvBuf, nRecvBytes);
|
|
|
|
|
+ pTrans->ack.ret = nRecvBytes; pTrans->ack.data[pTrans->ack.ret] = '\0'; bPrintRecvBuf = false;
|
|
|
|
|
+ sw_log_trace("[%s] %s received a cmd ack(%d bytes): %s", MODULE_NAME, log_prefix, pTrans->ack.ret, pTrans->ack.data);
|
|
|
|
|
+ goto ret_p1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if((now-enteredWaitAckTime) >= pTrans->timeout)
|
|
|
|
|
+ { // 已超时
|
|
|
|
|
+ sw_log_error("[%s] %s timeout occurred while waiting for the \"%s\" command's ack!!", MODULE_NAME, log_prefix, pTrans->cmd.data);
|
|
|
|
|
+ pTrans->ack.ret = -1; pTrans->ack.data[0] = '\0';
|
|
|
|
|
+ goto ret_p1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ { // 继续收
|
|
|
|
|
+ goto ret_p3;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3, 缓存数据接收控制
|
|
|
|
|
+ret_p1: // 点亮信号量, 表明本指令执行结束
|
|
|
|
|
+ sw_signal_give(pComIO->pTrans->hEndSgl); enteredWaitAckTime = 0; enteredSilentTime = 0; nSilentRecvBytes = 0;
|
|
|
|
|
+ goto ret_p2;
|
|
|
|
|
+
|
|
|
|
|
+ret_p2: // 清接收缓存, 重新开始一轮新指令
|
|
|
|
|
+ if(nRecvBytes > 0 && bPrintRecvBuf)
|
|
|
|
|
+ {
|
|
|
|
|
+ serial_printf_recv_buffer(pSerial, LEVEL_TRACE); // 十六进制打印当前串口接收数据缓存
|
|
|
|
|
+ sw_log_warn("[%s] %s discarded %d bytes of meaningless data!", MODULE_NAME, log_prefix, nRecvBytes);
|
|
|
|
|
+ }
|
|
|
|
|
+ if(nRecvBytes > 0) serial_clear_recv_buffer(pSerial);
|
|
|
|
|
+ goto ret_p3;
|
|
|
|
|
+
|
|
|
|
|
+ret_p3: return 1; // 持续累加的接收新数据
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 打开与模块的通讯, 返回: 0成功, <0时失败
|
|
|
|
|
+int EC200U_ComInit()
|
|
|
|
|
+{
|
|
|
|
|
+ s_myCom.do_cmd_mutex = sw_mutex_create();
|
|
|
|
|
+ if(!s_myCom.do_cmd_mutex) { sw_log_error("[%s] error to create a mutex!!", MODULE_NAME); return -1; }
|
|
|
|
|
+ s_myCom.pTrans = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ const char *serialName = "/dev/ttyUSB0"; int baudrate = 115200;
|
|
|
|
|
+ const char *parityCheck = "none"; // 无校检
|
|
|
|
|
+ s_myCom.h = serial_open(serialName, baudrate, parityCheck, \
|
|
|
|
|
+ comio_data_recv_proc, comio_data_recv_proc, NULL);
|
|
|
|
|
+ if(!s_myCom.h)
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_error("[%s] failed to open the \"%s:%d(%s parity)\" device!!", \
|
|
|
|
|
+ MODULE_NAME, serialName, baudrate, parityCheck);
|
|
|
|
|
+ sw_mutex_destroy(s_myCom.do_cmd_mutex); return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_USE_ECHO); trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(!(ret > 0 && strstr(trans.ack.data, ATOK)))
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_error("[%s] failed to close echo mode!!", MODULE_NAME);
|
|
|
|
|
+ EC200U_ComExit(); return -2+ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_QCFG_CMD1); trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(!(ret > 0 && strstr(trans.ack.data, ATOK)))
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_error("[%s] failed to configure USB network mode!!", MODULE_NAME);
|
|
|
|
|
+ EC200U_ComExit(); return -3+ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_QCFG_CMD2); trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(!(ret > 0 && strstr(trans.ack.data, ATOK)))
|
|
|
|
|
+ {
|
|
|
|
|
+ sw_log_error("[%s] failed to activate USB network mode!!", MODULE_NAME);
|
|
|
|
|
+ EC200U_ComExit(); return -4+ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭与模块的通讯, 返回: 0成功, <0时失败
|
|
|
|
|
+int EC200U_ComExit()
|
|
|
|
|
+{
|
|
|
|
|
+ if(s_myCom.h) serial_close(s_myCom.h, WAITTHRD_SAFEEXIT_TIMEOUT);
|
|
|
|
|
+ if(s_myCom.do_cmd_mutex) sw_mutex_destroy(s_myCom.do_cmd_mutex);
|
|
|
|
|
+ memset(&s_myCom, 0, sizeof(s_myCom));
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 改写sysfs虚拟文件, 返回: 0成功, <0失败
|
|
|
|
|
+static int sysfs_write(const char *path, const char *value)
|
|
|
|
|
+{
|
|
|
|
|
+ int fd = open(path, O_WRONLY);
|
|
|
|
|
+ if (fd < 0) return -1;
|
|
|
|
|
+ ssize_t len = write(fd, value, strlen(value));
|
|
|
|
|
+ if(len != strlen(value)) { close(fd); return -2; }
|
|
|
|
|
+ close(fd); return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 控制模块断电重启, 返回: 0成功, <0时失败
|
|
|
|
|
+// 138脚 -- gpio4.IO[20] (4-1)*32+20 = 116 -- 4G_POWER
|
|
|
|
|
+int EC200U_Repower()
|
|
|
|
|
+{
|
|
|
|
|
+ sysfs_write("/sys/class/gpio/unexport", "116"); // 撤销原导出
|
|
|
|
|
+ if(sysfs_write("/sys/class/gpio/export", "116") < 0) return -2; // 重设新导出
|
|
|
|
|
+ if(sysfs_write("/sys/class/gpio/gpio116/direction", "out") < 0) return -3; // 设置为输出
|
|
|
|
|
+ if(sysfs_write("/sys/class/gpio/gpio116/value", "1") < 0) return -4; // 输出高电平-断电
|
|
|
|
|
+ sw_thrd_delay(5000); // 等一段时间-毫秒
|
|
|
|
|
+ if(sysfs_write("/sys/class/gpio/gpio116/value", "0") < 0) return -5; // 输出低电平-上电
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取模块的标识号, 返回: =15成功, <0失败(-1命令超时)
|
|
|
|
|
+int EC200U_GetIMEI(char buf[16]/*固定长15个十进制数字组成*/)
|
|
|
|
|
+{
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_GET_IMEI);
|
|
|
|
|
+ trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(ret < 0) return ret; // 执行超时或出错
|
|
|
|
|
+ else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
|
|
|
|
|
+
|
|
|
|
|
+ const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
|
|
|
|
|
+lsa_p: // 行扫描, 逐行分析应答结果
|
|
|
|
|
+ if((*p) == '\0') goto end_p;
|
|
|
|
|
+ pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
|
|
|
|
|
+ if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
|
|
|
|
|
+ if(pLineE) { lineLen = pLineE - pLineS; }
|
|
|
|
|
+ if(lineLen == 0)
|
|
|
|
|
+ { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
|
|
|
|
|
+ if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
|
|
|
|
|
+ else goto end_p;
|
|
|
|
|
+ }
|
|
|
|
|
+ //// 示例: "359759002514931"
|
|
|
|
|
+ if(lineLen == 15)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool isHex = true;
|
|
|
|
|
+ for(int i = 0; i < lineLen; i++) if(!xisxdigit(pLineS[i])) { isHex = false; break; }
|
|
|
|
|
+ if(isHex) { memcpy(buf, pLineS, lineLen); buf[lineLen] = '\0'; return lineLen; } // 成功读到模块的IMEI号
|
|
|
|
|
+ }
|
|
|
|
|
+ p = pLineE + crlfLen;
|
|
|
|
|
+ goto lsa_p; // 继续分析下一行
|
|
|
|
|
+
|
|
|
|
|
+end_p:
|
|
|
|
|
+ return -5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取网络注册状态, 返回: >=0成功, <0失败(-1命令超时)
|
|
|
|
|
+int EC200U_GetCregState()
|
|
|
|
|
+{
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_GET_CREG);
|
|
|
|
|
+ trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(ret < 0) return ret; // 执行超时或出错
|
|
|
|
|
+ else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
|
|
|
|
|
+
|
|
|
|
|
+ const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
|
|
|
|
|
+ const char *p1, *p2; char statBuf[3]; int statLen;
|
|
|
|
|
+lsa_p: // 行扫描, 逐行分析应答结果
|
|
|
|
|
+ if((*p) == '\0') goto end_p;
|
|
|
|
|
+ pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
|
|
|
|
|
+ if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
|
|
|
|
|
+ if(pLineE) { lineLen = pLineE - pLineS; }
|
|
|
|
|
+ if(lineLen == 0)
|
|
|
|
|
+ { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
|
|
|
|
|
+ if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
|
|
|
|
|
+ else goto end_p;
|
|
|
|
|
+ }
|
|
|
|
|
+ //// 示例: "+CREG: <n>,<stat>"
|
|
|
|
|
+ //// 说明: <n>注册状态报告模式, <stat>当前网络注册状态
|
|
|
|
|
+ p1 = strstr(pLineS, "+CREG:"); p2 = NULL;
|
|
|
|
|
+ if(p1 && p1 < pLineE) { p1 += 6; p2 = strchr(p1, ','); }
|
|
|
|
|
+ if(p2 && p2 < pLineE)
|
|
|
|
|
+ {
|
|
|
|
|
+ p2++; while(*p2 == 0x20 && p2 < pLineE) { p2++; } // 跳过空格
|
|
|
|
|
+ statLen = (pLineE - p2); if(statLen != 1 && statLen != 2) return -5; // 状态值范围: 1或2个数字
|
|
|
|
|
+ memcpy(statBuf, p2, statLen); statBuf[statLen] = '\0';
|
|
|
|
|
+ bool isDigit = true;
|
|
|
|
|
+ for(int i = 0; i < strlen(statBuf); i++) if(!xisdigit(statBuf[i])) { isDigit = false; break; }
|
|
|
|
|
+ if(isDigit) return atoi(statBuf); // 成功读到模块的网络注册状态值
|
|
|
|
|
+ else return -6;
|
|
|
|
|
+ }
|
|
|
|
|
+ p = pLineE + crlfLen;
|
|
|
|
|
+ goto lsa_p; // 继续分析下一行
|
|
|
|
|
+
|
|
|
|
|
+end_p:
|
|
|
|
|
+ return -7;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取当前信号强度, 返回: >=0成功, <0失败(-1命令超时)
|
|
|
|
|
+int EC200U_GetRSSIFromCSQ()
|
|
|
|
|
+{
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_GET_CSQ);
|
|
|
|
|
+ trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(ret < 0) return ret; // 执行超时或出错
|
|
|
|
|
+ else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
|
|
|
|
|
+
|
|
|
|
|
+ const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
|
|
|
|
|
+ const char *p1, *p2; char rssiBuf[3]; int rssiLen;
|
|
|
|
|
+lsa_p: // 行扫描, 逐行分析应答结果
|
|
|
|
|
+ if((*p) == '\0') goto end_p;
|
|
|
|
|
+ pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
|
|
|
|
|
+ if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
|
|
|
|
|
+ if(pLineE) { lineLen = pLineE - pLineS; }
|
|
|
|
|
+ if(lineLen == 0)
|
|
|
|
|
+ { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
|
|
|
|
|
+ if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
|
|
|
|
|
+ else goto end_p;
|
|
|
|
|
+ }
|
|
|
|
|
+ //// 示例: "+CSQ: 15,99"
|
|
|
|
|
+ //// 说明: 逗号前第一个数值是RSSI的值
|
|
|
|
|
+ p1 = strstr(pLineS, "+CSQ:"); p2 = NULL;
|
|
|
|
|
+ if(p1 && p1 < pLineE) { p1 += 5; p2 = strchr(p1, ','); }
|
|
|
|
|
+ if(p2 && p2 < pLineE)
|
|
|
|
|
+ {
|
|
|
|
|
+ while(*p1 == 0x20 && p1 < p2) { p1++; } // 跳过空格
|
|
|
|
|
+ rssiLen = (p2 - p1); if(rssiLen != 1 && rssiLen != 2) return -5; // 强度值范围: 0-99, 1或2个数字
|
|
|
|
|
+ memcpy(rssiBuf, p1, rssiLen); rssiBuf[rssiLen] = '\0';
|
|
|
|
|
+ bool isDigit = true;
|
|
|
|
|
+ for(int i = 0; i < strlen(rssiBuf); i++) if(!xisdigit(rssiBuf[i])) { isDigit = false; break; }
|
|
|
|
|
+ if(isDigit) return atoi(rssiBuf); // 成功读到模块的接收信号强度值
|
|
|
|
|
+ else return -6;
|
|
|
|
|
+ }
|
|
|
|
|
+ p = pLineE + crlfLen;
|
|
|
|
|
+ goto lsa_p; // 继续分析下一行
|
|
|
|
|
+
|
|
|
|
|
+end_p:
|
|
|
|
|
+ return -7;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 返回电话卡的状态, 返回: 1已可用, <0失败(-1命令超时)
|
|
|
|
|
+int EC200U_IsSimCardReady()
|
|
|
|
|
+{
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_GET_PINSTA);
|
|
|
|
|
+ trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(ret < 0) return ret; // 执行超时或出错
|
|
|
|
|
+ else if(strstr(trans.ack.data, ATOK) && strstr(trans.ack.data, "+CPIN: READY")) return 1;
|
|
|
|
|
+ else return -5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取电话卡标识号, 返回: =20成功, <0失败(-1命令超时)
|
|
|
|
|
+int EC200U_GetSimICCID(char buf[21]/*一般由20个十进制数字组成*/)
|
|
|
|
|
+{
|
|
|
|
|
+ SATCmdTrans trans; memset(&trans, 0, sizeof(SATCmdTrans));
|
|
|
|
|
+ strcpy(trans.cmd.data, AT_GET_ICCID);
|
|
|
|
|
+ trans.cmd.len = strlen(trans.cmd.data);
|
|
|
|
|
+ int ret = comio_doCmd(&trans, WAIT_ACK_TIMEOUT);
|
|
|
|
|
+ if(ret < 0) return ret; // 执行超时或出错
|
|
|
|
|
+ else if(strstr(trans.ack.data, ATOK) == NULL) goto end_p; // 未收到成功应答
|
|
|
|
|
+
|
|
|
|
|
+ const char *p = trans.ack.data, *pLineS, *pLineE; int lineLen, crlfLen = strlen(CRLF);
|
|
|
|
|
+ const char *p1, *p2; int iccidLen;
|
|
|
|
|
+lsa_p: // 行扫描, 逐行分析应答结果
|
|
|
|
|
+ if((*p) == '\0') goto end_p;
|
|
|
|
|
+ pLineS = strstr(p, CRLF); pLineE = NULL; lineLen = 0;
|
|
|
|
|
+ if(pLineS) { pLineS += crlfLen; pLineE = strstr(pLineS, CRLF); }
|
|
|
|
|
+ if(pLineE) { lineLen = pLineE - pLineS; }
|
|
|
|
|
+ if(lineLen == 0)
|
|
|
|
|
+ { // 连续两个CRLF, 上面的逻辑保证了"lineLen"只可能大于或等于0, 不会是小于0
|
|
|
|
|
+ if(pLineE) { p = pLineE; goto lsa_p; } // 跳第一个CRLF, 继续分析下一行
|
|
|
|
|
+ else goto end_p;
|
|
|
|
|
+ }
|
|
|
|
|
+ //// 示例: "+ICCID: 89860117831003134201"
|
|
|
|
|
+ p1 = strstr(pLineS, "+ICCID:"); p2 = NULL;
|
|
|
|
|
+ if(p1 && p1 < pLineE) { p1 += 7; p2 = pLineE; }
|
|
|
|
|
+ if(p2)
|
|
|
|
|
+ {
|
|
|
|
|
+ while(*p1 == 0x20 && p1 < p2) { p1++; } // 跳过空格
|
|
|
|
|
+ iccidLen = (p2 - p1); if(iccidLen != 20) return -5; // 长度不对
|
|
|
|
|
+ bool isHex = true;
|
|
|
|
|
+ for(int i = 0; i < iccidLen; i++) if(!xisxdigit(p1[i])) { isHex = false; break; }
|
|
|
|
|
+ if(isHex) { memcpy(buf, p1, iccidLen); buf[iccidLen] = '\0'; return iccidLen; } // 成功读到SIM卡的ICCID号
|
|
|
|
|
+ else return -6;
|
|
|
|
|
+ }
|
|
|
|
|
+ p = pLineE + crlfLen;
|
|
|
|
|
+ goto lsa_p; // 继续分析下一行
|
|
|
|
|
+
|
|
|
|
|
+end_p:
|
|
|
|
|
+ return -7;
|
|
|
|
|
+}
|