#include "CONFIG.h" #if EC800M #include "stm32f10x.h" #include #include #include #include #include "ec800m.h" #include "Common_Util.h" #include "Log_Module.h" #include "At_Module.h" /** * 龙三郎 **/ // 方法声明 void ec800m_reset(void); // 重置状态。该文件中的方法共用状态,在使用下面的方法前需要重置一下状态。 void ec800m_exit_sleep(void); // 退出休眠 void ec800m_enter_sleep(void); // 进入休眠 /** * 查询休眠模式 * 输入<< * * 输出>> * n 睡眠模式。0 禁用,默认;1 启用。 **/ enum Result ec800m_query_sleep(uint8_t * n); // 查询休眠模式。 enum Result ec800m_query_sleep_sync(uint8_t * n); // 查询休眠模式。同步 /** * 设置休眠模式 * 输入<< * n 参数。0 禁用;1启用。 * 输出>> * **/ enum Result ec800m_set_sleep(uint8_t n); // 设置休眠模式。 enum Result ec800m_set_sleep_sync(uint8_t n); // 设置休眠模式。同步 /** * 设置功能模式 * 输入<< * fun 0 最小功能模式;1 全功能模式。 * 输出>> * **/ enum Result ec800m_set_cfun(uint8_t fun); enum Result ec800m_set_cfun_sync(uint8_t fun); // 同步 /** * 设置ps域网络注册状态 * 输入<< * n 0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 * 输出>> * **/ enum Result ec800m_set_cgreg(uint8_t n); enum Result ec800m_set_cgreg_sync(uint8_t n); // 同步 /** * 查询ps域网络注册状态 * 输入<< * * 输出>> * n 控制指定URC的上报。0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 * stat 网络注册状态。0 未注册;1 已注册,归属地网络; 2 未注册;3 注册被拒绝;4 未知;5 已注册,漫游。 * lac 基站位置区号。用于基站定位,2个字节。 * ci 基站小区ID。用于基站定位,4个字节。 * **/ enum Result ec800m_query_cgreg(uint8_t * n, uint8_t * stat, uint16_t * lac, uint32_t * ci); enum Result ec800m_query_cgreg_sync(uint8_t * n, uint8_t * stat, uint16_t * lac, uint32_t * ci); // 同步 /** * 查询socket服务状态 * 输入<< * connectID Socket ID。范围1-11 * * 输出>> * state Socket服务状态。0 未连接;1 正在连接;2 已建立连接;3 服务正在监听;4 连接断开。 * * **/ enum Result ec800m_query_socket_state(uint8_t connectID, uint8_t * state); enum Result ec800m_query_socket_state_sync(uint8_t connectID, uint8_t * state); // 同步 /** * 打开socket服务 * 输入<< * connectID Socket ID。范围1-11 * service_type Socket服务类型。取值为"UDP", "TCP"。 * IP_address 远程服务器地址 * remote_port 远程服务器端口 * access_mode Socket服务的数据访问模式。0 缓存模式;1 直吐模式;2 透传模式。 * * 输出>> * err 操作错误代码。0 表示没有错误;其余参考移远文档。 * **/ enum Result ec800m_open_socket(uint8_t connectID, char * service_type, char * IP_address, uint16_t remote_port, uint8_t access_mode, uint16_t * err); enum Result ec800m_open_socket_sync(uint8_t connectID, char * service_type, char * IP_address, uint16_t remote_port, uint8_t access_mode, uint16_t * err); // 同步 /** * 关闭socket服务 * 输入<< * connectID Socket ID。范围1-11 * * 输出>> * **/ enum Result ec800m_close_socket(uint8_t connectID); enum Result ec800m_close_socket_sync(uint8_t connectID); // 同步 /** * 解释:控制是否回显AT+QISEND要发送的数据 * 为了便于处理返回,发送数据时需要关闭回显。 * 输入<< * echo 是否回显AT+QISEND要发送的数据。0 不回显;1 回显。默认是回显 * * 输出>> * **/ enum Result ec800m_set_qisde(uint8_t echo); enum Result ec800m_set_qisde_sync(uint8_t echo); // 同步 /** * 发送数据 * 输入<< * connectID Socket ID。范围1-11。 * send_length 发送长度。 * data 待发送的数据。 * * **/ enum Result ec800m_send(uint8_t connectID, uint8_t * data, uint16_t data_length); enum Result ec800m_send_sync(uint8_t connectID, uint8_t * data, uint16_t data_length); // 同步 /** * 接收数据 * 输入<< * connectID Socket ID。范围0-11。 * * 输出>> * data 接收的数据。 * data_length 接收的数据长度。 **/ enum Result ec800m_recv(uint8_t connectID, uint8_t * data, uint16_t * data_length); // 接收数据 /** * 接收数据。带计时 * 输入<< * connectID Socket ID。范围0-11。 * * 输出>> * data 接收的数据。 * data_length 接收的数据长度。 * **/ enum Result ec800m_recv_with_time(uint8_t connectID, uint8_t * data, uint16_t * data_length, uint32_t time_out); enum Result ec800m_recv_with_time_sync(uint8_t connectID, uint8_t * data, uint16_t * data_length, uint32_t time_out); // 同步 /** * 解释:关闭模块 * 关闭模块,关闭后会自动重启。 * 输入<< * n 模块关机方式。0 立即关机;1 正常关机。默认是1 * * **/ enum Result ec800m_power_down(uint8_t n); enum Result ec800m_power_down_sync(uint8_t n); // 同步 /** * 模块是否启动成功 * 输入<< * * 输出>> * **/ enum Result ec800m_ready(void); /** * 查询信号质量 * 输入<< * * 输出>> * RSRP * RSRQ * RSSI * SINR **/ enum Result ec800m_qeng_servingcell(int * RSRP, int * RSRQ, int * RSSI, int * SINR); enum Result ec800m_qeng_servingcell_sync(int * RSRP, int * RSRQ, int * RSSI, int * SINR); /** * 查询ICCID * 输入<< * * 输出>> * iccid SIM卡卡号 **/ enum Result ec800m_query_qccid(char * iccid); enum Result ec800m_query_qccid_sync(char * iccid); // AT指令 static char AT_CMD[256]; // EC800M提供的一些方法 struct EC800M_Struct ec800m = { .timer = { .time = 0, .flag = 0 }, .reset = ec800m_reset, .exit_sleep = ec800m_exit_sleep, .enter_sleep = ec800m_enter_sleep, .query_sleep = ec800m_query_sleep, .query_sleep_sync = ec800m_query_sleep_sync, .set_sleep = ec800m_set_sleep, .set_sleep_sync = ec800m_set_sleep_sync, .set_cfun = ec800m_set_cfun, .set_cfun_sync = ec800m_set_cfun_sync, .set_cgreg = ec800m_set_cgreg, .set_cgreg_sync = ec800m_set_cgreg_sync, .query_cgreg = ec800m_query_cgreg, .query_cgreg_sync = ec800m_query_cgreg_sync, .query_socket_state = ec800m_query_socket_state, .query_socket_state_sync = ec800m_query_socket_state_sync, .open_socket = ec800m_open_socket, .open_socket_sync = ec800m_open_socket_sync, .close_socket = ec800m_close_socket, .close_socket_sync = ec800m_close_socket_sync, .set_qisde = ec800m_set_qisde, .set_qisde_sync = ec800m_set_qisde_sync, .send = ec800m_send, .send_sync = ec800m_send_sync, .recv = ec800m_recv, .recv_with_time = ec800m_recv_with_time, .recv_with_time_sync = ec800m_recv_with_time_sync, .power_down = ec800m_power_down, .power_down_sync = ec800m_power_down_sync, .ready = ec800m_ready, .qeng_servingcell = ec800m_qeng_servingcell, .qeng_servingcell_sync = ec800m_qeng_servingcell_sync, .query_qccid = ec800m_query_qccid, .query_qccid_sync = ec800m_query_qccid_sync }; // 发送AT指令 static void send_data(uint8_t * data, uint16_t length) { // 发送AT指令 AT_Send_Bytes(data, length); } // 发送AT指令 static uint8_t send_at_string(char * cmd) { uint8_t state = 0; if(AT_Get_Status() == AT_Status_None) { // 发送AT指令 AT_Send_String(cmd); state = 1; } return state; } // 获取状态 static enum STATUS getStatus(void) { return ec800m.status; } // 设置状态 static void setStatus(enum STATUS status) { ec800m.status = status; } // 获取定时 static uint32_t getTimerMs(void) { return time_get_delay(&ec800m.timer); } // 清除定时 static void clearTimer(void) { time_clear(&ec800m.timer); } // 设置定时 //static void setTimerMs(uint32_t time) //{ // ec800m.timer_ms = time; //} // 获取ID static uint8_t getActiveID(void) { return ec800m.activeID; } static void setActiveID(uint8_t activeID) { ec800m.activeID = activeID; } // 验证ID static uint8_t verifyActiveID(uint8_t activeID) { if(getActiveID() == 0 || getActiveID() == activeID){ return 1; } else { Log_Printf_Debug("activeID repetition!\r\n"); return 0; } } // 返回超时结果 static enum Result overtime(void) { setStatus(Status_Overtime); // 超时 // 发送日志 Log_Printf_Debug("接收超时: %d\r\n", AT_result_length()); Log_SendArray_Debug(AT_result(), AT_result_length()); return Result_Failed; // 结果 } // 返回成功结果 static enum Result success_no_log(void) { // 成功 setStatus(Status_Success); // 结果 return Result_Success; } // 返回成功结果 static enum Result success(void) { // 发送日志 Log_Printf_Debug("接收成功: %d\r\n", AT_result_length()); Log_SendArray_Debug(AT_result(), AT_result_length()); return success_no_log(); } // 返回失败结果 static enum Result failed(int type) { // 失败 setStatus(Status_Failed); if(type == 1) { Log_Printf_Debug("activeID: %d, error: 接收结果过期,请重置状态\r\n", ec800m.activeID); // 打印日志 } else if(type == 2) { // 发送日志 Log_Printf_Debug("activeID: %d, AT接收失败: %d\r\n", ec800m.activeID, AT_result_length()); Log_SendArray_Debug(AT_result(), AT_result_length()); } else { Log_Printf_Debug("activeID: %d, error: 未知错误类型\r\n", ec800m.activeID); // 打印日志 } // 失败结果 return Result_Failed; } // 重置状态。该文件中的方法共用状态,在使用方法前需要重置一下状态。 void ec800m_reset(void) { setStatus(Status_None); // 重置状态 setActiveID(0); // 重置ID clearTimer(); // 重置计时 AT_Clear(); // 清除AT指令 } // 发送指令并改变状态 enum Result send_at_nolog(char * cmd, uint8_t activeID) { if(send_at_string(cmd)) // 发送AT指令 { Log_Printf_Debug("发送成功: %d\r\n", strlen(cmd)); // 打印日志 setActiveID(activeID); // 活动ID setStatus(Status_Sending); // 设置已发送 clearTimer(); // 重置计时 return Result_None; // 未知结果 } else { Log_Printf_Debug("activeID: %d, error: AT指令发送失败\r\n", ec800m.activeID); // 打印日志 return Result_Failed; // 失败结果 } } enum Result send_at(char * cmd, uint8_t activeID) { enum Result result = send_at_nolog(cmd, activeID); if(result == Result_None) // 发送成功 { Log_Printf_Debug(cmd); // 打印AT指令 } return result; } // 退出休眠 void ec800m_exit_sleep(void) { GPIO_ResetBits(WAKE_GPIO, WAKE_GPIO_Pin); // 拉低io口,唤醒模组 } // 进入休眠 void ec800m_enter_sleep(void) { GPIO_SetBits(WAKE_GPIO, WAKE_GPIO_Pin); // 拉高io口,进入睡眠 } /** * 查询休眠模式 * 输入<< * * 输出>> * n 睡眠模式。0 禁用,默认;1 启用。 * **/ enum Result ec800m_query_sleep(uint8_t * n) { enum Result result = Result_None; int activeID = 1, time = 500; // 活动ID, 超时时间 if(!verifyActiveID(activeID)){ return Result_Failed; } // 校验ID // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QSCLK?\r\r\n"); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 char * Line1 = strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 拆解第二行 char * saveptr_inner = NULL; char * split_inner = ": "; strtok_r(Line2, split_inner, &saveptr_inner); // 获取mode * n = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 查询休眠模式。同步方法 * 输入<< * * 输出>> * n 睡眠模式。0 禁用,默认;1 启用。 * **/ enum Result ec800m_query_sleep_sync(uint8_t * n) { enum Result result = Result_None; while(1) { result = ec800m_query_sleep(n); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 设置休眠模式 * n 参数。0 禁用;1启用。 **/ enum Result ec800m_set_sleep(uint8_t n) { enum Result result = Result_None; int activeID = 2, time = 500; // 活动ID, 超时时间 if(!verifyActiveID(activeID)){ return Result_Failed; } // 校验ID // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QSCLK=%d\r\r\n", n); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 设置休眠模式。同步 * n 参数。0 禁用;1启用。 **/ enum Result ec800m_set_sleep_sync(uint8_t n) { enum Result result = Result_None; while(1) { result = ec800m_set_sleep(n); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 设置功能模式 * fun 0 最小功能模式;1 全功能模式。 **/ enum Result ec800m_set_cfun(uint8_t fun) { enum Result result = Result_None; int activeID = 4, time; // 活动ID, 超时时间 // 校验参数 if(fun == 0){ time = 3000; } else if(fun == 1){ time = 5000; } else { Log_Printf_Debug("set_cfun params error!\r\n"); return Result_Failed; } // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+CFUN=%d\r\r\n", fun); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { // 防止接收不完整 if(AT_wait_time() > 10) // 过10ms之后再取数据,避免数据截断。 { result = success(); // 成功 } } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 设置功能模式 * 输入<< * fun 0 最小功能模式;1 全功能模式。 * 输出>> * **/ enum Result ec800m_set_cfun_sync(uint8_t fun) { enum Result result = Result_None; while(1) { result = ec800m_set_cfun(fun); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 设置ps域网络注册状态 * n 0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 **/ enum Result ec800m_set_cgreg(uint8_t n) { enum Result result = Result_None; int activeID = 6, time = 500; // 活动ID, 超时时间 // 校验参数 if(n > 2) { Log_Printf_Debug("set_cgreg params error!\r\n"); return Result_Failed; } // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+CGREG=%d\r\r\n", n); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 设置ps域网络注册状态 * 输入<< * n 0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 * 输出>> * **/ enum Result ec800m_set_cgreg_sync(uint8_t n) { enum Result result = Result_None; while(1) { result = ec800m_set_cgreg(n); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 查询ps域网络注册状态 * 输入<< * * 输出>> * n 控制指定URC的上报。0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 * stat 网络注册状态。0 未注册;1 已注册,归属地网络; 2 未注册;3 注册被拒绝;4 未知;5 已注册,漫游。 * lac 基站位置区号。用于基站定位,2个字节。 * ci 基站小区ID。用于基站定位,4个字节。 * **/ enum Result ec800m_query_cgreg(uint8_t * n, uint8_t * stat, uint16_t * lac, uint32_t * ci) { enum Result result = Result_None; int activeID = 9, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+CGREG?\r\r\n"); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 拆解第二行 char * saveptr_inner = NULL; char * split_inner = ": ,\""; strtok_r(Line2, split_inner, &saveptr_inner); * n = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * stat = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * lac = strtoul(strtok_r(NULL, split_inner, &saveptr_inner), NULL, 16); * ci = strtoul(strtok_r(NULL, split_inner, &saveptr_inner), NULL, 16); // 打印 Log_Printf_Debug("mode: %d, stat: %d, lac: %d, ci: %d\r\n", * n, * stat, * lac, * ci); } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 查询ps域网络注册状态 * 输入<< * * 输出>> * n 控制指定URC的上报。0 禁止上报网络注册;1 允许上报网络注册;2 允许上报网络注册和位置信息 * stat 网络注册状态。0 未注册;1 已注册,归属地网络; 2 未注册;3 注册被拒绝;4 未知;5 已注册,漫游。 * lac 基站位置区号。用于基站定位,2个字节。 * ci 基站小区ID。用于基站定位,4个字节。 * **/ enum Result ec800m_query_cgreg_sync(uint8_t * n, uint8_t * stat, uint16_t * lac, uint32_t * ci) { enum Result result = Result_None; while(1) { result = ec800m_query_cgreg(n, stat, lac, ci); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 查询socket服务状态 * connectID Socket ID。范围1-11 * state Socket服务状态。0 未连接;1 正在连接;2 已建立连接;3 服务正在监听;4 连接断开。 * * activeID 9 **/ enum Result ec800m_query_socket_state(uint8_t connectID, uint8_t * state) { enum Result result = Result_None; int activeID = 9, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QISTATE=1,%d\r\r\n", connectID); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 查询结果为空 if(strcmp(Line2, "OK") == 0){ * state = 0; } else { // 拆解第二行 char * saveptr_inner = NULL; char * split_inner = ": ,\""; strtok_r(Line2, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); * state = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); } // 打印 Log_Printf_Debug("result: %d\r\n", * state); } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 查询socket服务状态 * connectID Socket ID。范围1-11 * state Socket服务状态。0 未连接;1 正在连接;2 已建立连接;3 服务正在监听;4 连接断开。 * * activeID 9 **/ enum Result ec800m_query_socket_state_sync(uint8_t connectID, uint8_t * state) { enum Result result = Result_None; while(1) { result = ec800m_query_socket_state(connectID, state); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 打开socket服务 * 输入<< * connectID Socket ID。范围1-11 * service_type Socket服务类型。取值为"UDP", "TCP"。 * IP_address 远程服务器地址 * remote_port 远程服务器端口 * access_mode Socket服务的数据访问模式。0 缓存模式;1 直吐模式;2 透传模式。 * * 输出>> * err 操作错误代码。0 表示没有错误;其余参考移远文档。 * * activeID 19 **/ enum Result ec800m_open_socket(uint8_t connectID, char * service_type, char * IP_address, uint16_t remote_port, uint8_t access_mode, uint16_t * err) { enum Result result = Result_None; int activeID = 19, time = 3000; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QIOPEN=1,%d,\"%s\",\"%s\",%d,%d,%d\r\r\n", connectID, service_type, IP_address, remote_port, 0, access_mode); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "+QIOPEN: ") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 第三行 char * Line3 = strtok_r(NULL, split, &saveptr); // 查询结果为空 if(strcmp(Line2, "OK") == 0) { // 拆解第三行 char * saveptr_inner = NULL; char * split_inner = ": ,\""; strtok_r(Line3, split_inner, &saveptr_inner); uint8_t connID = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * err = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); Log_Printf_Debug("result: %d, %d\r\n", connID, * err); } } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 打开socket服务 * 输入<< * connectID Socket ID。范围1-11 * service_type Socket服务类型。取值为"UDP", "TCP"。 * IP_address 远程服务器地址 * remote_port 远程服务器端口 * access_mode Socket服务的数据访问模式。0 缓存模式;1 直吐模式;2 透传模式。 * * 输出>> * err 操作错误代码。0 表示没有错误;其余参考移远文档。 * * activeID 19 **/ enum Result ec800m_open_socket_sync(uint8_t connectID, char * service_type, char * IP_address, uint16_t remote_port, uint8_t access_mode, uint16_t * err) { enum Result result = Result_None; while(1) { result = ec800m_open_socket(connectID, service_type, IP_address, remote_port, access_mode, err); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 关闭socket服务 * 输入<< * connectID Socket ID。范围1-11 * * activeID 29 **/ enum Result ec800m_close_socket(uint8_t connectID) { enum Result result = Result_None; int activeID = 29, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QICLOSE=%d\r\r\n", connectID); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 关闭socket服务 * 输入<< * connectID Socket ID。范围1-11 * * activeID 29 **/ enum Result ec800m_close_socket_sync(uint8_t connectID) { enum Result result = Result_None; while(1) { result = ec800m_close_socket(connectID); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 解释:控制是否回显AT+QISEND要发送的数据 * 为了便于处理返回,发送数据时需要关闭回显。 * 输入<< * echo 是否回显AT+QISEND要发送的数据。0 不回显;1 回显。默认是回显 * * activeID 45 **/ enum Result ec800m_set_qisde(uint8_t echo) { enum Result result = Result_None; int activeID = 45, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QISDE=%d\r\r\n", echo); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 解释:控制是否回显AT+QISEND要发送的数据 * 为了便于处理返回,发送数据时需要关闭回显。 * 输入<< * echo 是否回显AT+QISEND要发送的数据。0 不回显;1 回显。默认是回显 * * activeID 45 **/ enum Result ec800m_set_qisde_sync(uint8_t echo) { enum Result result = Result_None; while(1) { result = ec800m_set_qisde(echo); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 发送数据 * 输入<< * connectID Socket ID。范围1-11。 * send_length 发送长度。 * data 待发送的数据。 * * activeID 49 **/ enum Result ec800m_send(uint8_t connectID, uint8_t * data, uint16_t data_length) { enum Result result = Result_None; int activeID = 49, time = 10000; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QISEND=%d,%d\r\r\n", connectID, data_length); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "> ") != NULL) // 有响应 { // 发送日志 Log_Printf_Debug("AT返回: %d\r\n", AT_result_length()); Log_SendArray_Debug(AT_result(), AT_result_length()); // Log_Printf_Debug("coap:\r\n"); // Log_SendHex(data, data_length); // Log_Printf_Debug("\r\n"); // 发送数据 send_data(data, data_length); // 清理一下AT返回结果缓存 AT_Clear_Result(); } else if(strstr((char * )AT_result(), "SEND OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 } else if(strstr((char * )AT_result(), "SEND FALL\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } /** * 发送数据 * 输入<< * connectID Socket ID。范围1-11。 * send_length 发送长度。 * data 待发送的数据。 * * activeID 49 **/ enum Result ec800m_send_sync(uint8_t connectID, uint8_t * data, uint16_t data_length) { enum Result result = Result_None; while(1) { result = ec800m_send(connectID, data, data_length); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 接收数据 * 输入<< * connectID Socket ID。范围0-11。 * * 输出>> * data 接收的数据。 * data_length 接收的数据长度。 * **/ enum Result ec800m_recv(uint8_t connectID, uint8_t * data, uint16_t * data_length) { // 设置AT为使用中,防止被其他程序占用 AT_Set_Status(AT_Status_Using); enum Result result = Result_None; // 校验参数 if(connectID > 11) { Log_Printf_Debug("recv params error!\r\n"); return Result_Failed; } char cmp[20]; sprintf(cmp, "+QIURC: \"recv\",%d", connectID); // 拼接AT指令 // 判断是否接收到 if(strstr((char * )AT_result(), cmp) != NULL) { // 防止接收不完整 uint32_t last_time = AT_wait_time(); if(last_time > 10) // 过10ms之后再取数据,避免数据截断。 { // 发送日志 Log_Printf_Debug("AT返回: %d, time_diff: %d\r\n", AT_result_length(), last_time); // Log_SendArray_Debug(AT_result(), AT_result_length()); char * saveptr = NULL; char * split = "\r\n"; char * Line1 = strtok_r((char * )AT_result(), split, &saveptr); uint8_t Line1_Len = strlen(Line1); Log_Printf_Debug("Line1(%d): %s\r\n",Line1_Len ,Line1); // 分割Line1,获取报文长度 char * saveptr_inner = NULL; char * split_inner = ","; strtok_r(Line1, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); * data_length = strtoul(strtok_r(NULL, split_inner, &saveptr_inner), NULL, 10); uint16_t line_length = Line1_Len + 4; // 内存拷贝 memcpy(data, AT_result() + line_length, * data_length); // 成功 result = Result_Success; // 清理一下AT返回结果缓存 AT_Clear_Result(); } } return result; } /** * 接收数据。带计时 * 输入<< * connectID Socket ID。范围0-11。 * * 输出>> * data 接收的数据。 * data_length 接收的数据长度。 * **/ enum Result ec800m_recv_with_time(uint8_t connectID, uint8_t * data, uint16_t * data_length, uint32_t time_out) { enum Result result = Result_None; int activeID = 59, time = time_out; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { setStatus(Status_Sending); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else { // 接收数据 result = ec800m.recv(connectID, data, data_length); if(result == Result_Success) { result = success_no_log(); // 成功 } } return result; } /** * 接收数据。带计时 * 输入<< * connectID Socket ID。范围0-11。 * * 输出>> * data 接收的数据。 * data_length 接收的数据长度。 * **/ enum Result ec800m_recv_with_time_sync(uint8_t connectID, uint8_t * data, uint16_t * data_length, uint32_t time_out) { enum Result result = Result_None; while(1) { result = ec800m_recv_with_time(connectID, data, data_length, time_out); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 解释:关闭模块 * 关闭模块,关闭后会自动重启。 * 输入<< * n 模块关机方式。0 立即关机;1 正常关机。默认是1 * * activeID 69 **/ enum Result ec800m_power_down(uint8_t n) { enum Result result = Result_None; int activeID = 69, time = 3000; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QPOWD=%d\r\r\n", n); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); } else if(strstr((char * )AT_result(), "POWERED DOWN\r\n") != NULL) // 查询是否返回 { result = success(); } return result; } /** * 解释:关闭模块。同步 * 关闭模块,关闭后会自动重启。 * 输入<< * n 模块关机方式。0 立即关机;1 正常关机。默认是1 * * activeID 69 **/ enum Result ec800m_power_down_sync(uint8_t n) { enum Result result = Result_None; while(1) { result = ec800m_power_down(n); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 模块是否启动成功 * 输入<< * * 输出>> * **/ enum Result ec800m_ready(void) { if(AT_Get_Status() != AT_Status_None) { return Result_None; } enum Result result = Result_None; // 判断是否接收到 uint8_t RDY[5]="RDY"; if(memmem(AT_result(),AT_result_length(),RDY,strlen((char *)RDY)) != 0) { uint32_t last_time = AT_wait_time(); if(last_time > 20) // 过10ms之后再取数据,避免数据截断。 { // 发送日志 Log_Printf_Debug("AT返回: %d\r\n", AT_result_length()); Log_SendArray_Debug(AT_result(), AT_result_length()); // 成功结果 result = Result_Success; // 清理一下AT返回结果缓存 AT_Clear_Result(); } } return result; } /** * 查询信号质量 * 输入<< * * 输出>> * RSRP * RSRQ * RSSI * SINR **/ enum Result ec800m_qeng_servingcell(int * RSRP, int * RSRQ, int * RSSI, int * SINR) { enum Result result = Result_None; int activeID = 71, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QENG=\"servingcell\"\r\r\n"); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 拆解第二行 char * saveptr_inner = NULL; char * split_inner = ": ,\""; strtok_r(Line2, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); strtok_r(NULL, split_inner, &saveptr_inner); * RSRP = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * RSRQ = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * RSSI = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); * SINR = atoi(strtok_r(NULL, split_inner, &saveptr_inner)); // 打印 Log_Printf_Debug("RSRP: %d, RSRQ: %d, RSSI: %d, SINR: %d\r\n", * RSRP, * RSRQ, * RSSI, * SINR); } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } enum Result ec800m_qeng_servingcell_sync(int * RSRP, int * RSRQ, int * RSSI, int * SINR) { enum Result result = Result_None; while(1) { result = ec800m_qeng_servingcell(RSRP, RSRQ, RSSI, SINR); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } /** * 查询ICCID * 输入<< * * 输出>> * iccid SIM卡卡号 **/ enum Result ec800m_query_qccid(char * iccid) { enum Result result = Result_None; int activeID = 75, time = 500; // 活动ID, 超时时间 // 校验ID if(!verifyActiveID(activeID)){ return Result_Failed; } // 判断状态 if(getStatus() == Status_None) // 空闲状态 { sprintf(AT_CMD, "AT+QCCID\r\r\n"); // 拼接AT指令 result = send_at(AT_CMD, activeID); } else if(getStatus() != Status_Sending) // 上一次的结果没有清除,返回错误,为了保证时效性,需要重置状态。重新调用 { result = failed(1); // 失败 } else if(getTimerMs() > time) // 正在发送状态。判断超时 { result = overtime(); // 超时 } else if(strstr((char * )AT_result(), "OK\r\n") != NULL) // 查询是否返回 { result = success(); // 成功 // 处理返回结果 char * saveptr = NULL; char * split = "\r\n"; // 第一行 char * Line1 = strtok_r((char * )AT_result(), split, &saveptr); // 第二行 char * Line2 = strtok_r(NULL, split, &saveptr); // 拆解第二行 char * saveptr_inner = NULL; char * split_inner = ": ,\""; strtok_r(Line2, split_inner, &saveptr_inner); // 字符串拷贝 strcpy(iccid, strtok_r(NULL, split_inner, &saveptr_inner)); // 打印 Log_Printf_Debug("ICCID: %s\r\n", iccid); } else if(strstr((char * )AT_result(), "ERROR\r\n") != NULL) // 查询是否返回 { result = failed(2); // 失败 } return result; } enum Result ec800m_query_qccid_sync(char * iccid) { enum Result result = Result_None; while(1) { result = ec800m_query_qccid(iccid); if(result != Result_None) { // 重置 ec800m.reset(); break; } } return result; } #endif