Fork with SeeedStudio Xadow GPS v2 enabled
Dependencies: FXOS8700CQ MODSERIAL XadowGPS mbed
Fork of Avnet_ATT_Cellular_IOT by
wnc_control.cpp
- Committer:
- fkellermavnet
- Date:
- 2016-07-26
- Revision:
- 53:dcccf2881fa0
- Parent:
- 46:da9d788f5d5a
- Child:
- 62:73c564e883e9
File content as of revision 53:dcccf2881fa0:
#include "mbed.h" #include <cctype> #include <string> #include "config_me.h" #include "SerialBuffered.h" #include "wnc_control.h" // Outputs detailed WNC command info #define WNC_CMD_DEBUG_ON // Full debug output, longer cmds and extra cellular status checking #undef WNC_CMD_DEBUG_ON_VERBOSE extern Serial pc; extern Serial mdm; extern string MyServerIpAddress; extern string MySocketData; int reinitialize_mdm(void); enum WNC_ERR_e { WNC_OK =0, WNC_CMD_ERR = -1, WNC_NO_RESPONSE = -2, WNC_CELL_LINK_DOWN = -3 }; // Contains result of last call to send_wnc_cmd(..) WNC_ERR_e WNC_MDM_ERR = WNC_OK; // Contains the RAW WNC UART responses static string wncStr; static int socketOpen = 0; void software_init_mdm(void) { static bool reportStatus = true; do { if (check_wnc_ready() == 0) { if (reportStatus == false) { puts("Re-connected to cellular network!\n\r"); reportStatus = true; } // WNC has SIM and registered on network do { WNC_MDM_ERR = WNC_OK; at_init_wnc(); if (WNC_MDM_ERR == WNC_NO_RESPONSE) { reinitialize_mdm(); at_init_wnc(true); // Hard reset occurred so make it go through the software init(); } } while (WNC_MDM_ERR != WNC_OK); } else { if (reportStatus == true) { puts("Not connected to cellular network!\n\r"); reportStatus = false; } // Atempt to re-register // string * pRespStr; // pc.puts("Force re-register!\r\n"); // at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, WNC_TIMEOUT_MS); // wait_ms(31000); // at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, WNC_TIMEOUT_MS); // wait_ms(31000); WNC_MDM_ERR = WNC_CELL_LINK_DOWN; } } while (WNC_MDM_ERR != WNC_OK); } void resolve_mdm(void) { do { WNC_MDM_ERR = WNC_OK; at_dnsresolve_wnc(MY_SERVER_URL, &MyServerIpAddress); if (WNC_MDM_ERR == WNC_NO_RESPONSE) { software_init_mdm(); } else if (WNC_MDM_ERR == WNC_CMD_ERR) { pc.puts("Bad URL!!!!!!\r\n"); } } while (WNC_MDM_ERR != WNC_OK); pc.printf("My Server IP: %s\r\n", MyServerIpAddress.c_str()); } void sockopen_mdm(void) { do { WNC_MDM_ERR = WNC_OK; at_sockopen_wnc(MyServerIpAddress, MY_PORT_STR); if (WNC_MDM_ERR == WNC_NO_RESPONSE) { software_init_mdm(); } else if (WNC_MDM_ERR == WNC_CMD_ERR) pc.puts("Socket open fail!!!!\r\n"); else socketOpen = 1; } while (WNC_MDM_ERR != WNC_OK); } void sockwrite_mdm(const char * s) { if (socketOpen == 1) { do { WNC_MDM_ERR = WNC_OK; at_sockwrite_wnc(s); if (WNC_MDM_ERR == WNC_NO_RESPONSE) { pc.puts("Sock write no response!\r\n"); software_init_mdm(); } else if (WNC_MDM_ERR == WNC_CMD_ERR) { pc.puts("Socket Write fail!!!\r\n"); software_init_mdm(); } } while (WNC_MDM_ERR != WNC_OK); } else puts("Socket is closed for write!\r\n"); } unsigned sockread_mdm(string * sockData, int len, int retries) { unsigned n = 0; if (socketOpen == 1) { do { WNC_MDM_ERR = WNC_OK; n = at_sockread_wnc(sockData, len, retries); if (WNC_MDM_ERR == WNC_NO_RESPONSE) { if (n == 0) software_init_mdm(); else puts("Sock read partial data!!!\r\n"); } else if (WNC_MDM_ERR == WNC_CMD_ERR) puts("Sock read fail!!!!\r\n"); } while (WNC_MDM_ERR == WNC_NO_RESPONSE); } else { puts("Socket is closed for read\r\n"); sockData->erase(); } return (n); } void sockclose_mdm(void) { do { WNC_MDM_ERR = WNC_OK; at_sockclose_wnc(); // Assume close happened even if it went bad // going bad will result in a re-init anyways and if close // fails we're pretty much in bad state and not much can do socketOpen = 0; if (WNC_MDM_ERR == WNC_NO_RESPONSE) { software_init_mdm(); } else if (WNC_MDM_ERR == WNC_CMD_ERR) puts("Sock close fail!!!\r\n"); } while (WNC_MDM_ERR != WNC_OK); } /** * C++ version 0.4 char* style "itoa": * Written by Lukás Chmela * Released under GPLv3. */ char* itoa(int value, char* result, int base) { // check that the base if valid if ( base < 2 || base > 36 ) { *result = '\0'; return result; } char* ptr = result, *ptr1 = result, tmp_char; int tmp_value; do { tmp_value = value; value /= base; *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; } while ( value ); // Apply negative sign if ( tmp_value < 0 ) *ptr++ = '-'; *ptr-- = '\0'; while ( ptr1 < ptr ) { tmp_char = *ptr; *ptr-- = *ptr1; *ptr1++ = tmp_char; } return result; } extern int mdm_sendAtCmdRsp(const char *cmd, const char **rsp_list, int timeout_ms, string * rsp, int * len); int check_wnc_ready(void) { string * pRespStr; size_t pos; int regSts; int cmdRes1, cmdRes2; #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("<-------- Begin Cell Status ------------\r\n"); #endif cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, WNC_TIMEOUT_MS); // Check RSSI,BER cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, WNC_TIMEOUT_MS); // Check if SIM locked if ((cmdRes1 != 0) && (cmdRes2 != 0)) { #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("------------ WNC No Response! --------->\r\n"); #endif return (-2); } // If SIM Card not ready don't bother with commands! if (pRespStr->find("CPIN: READY") == string::npos) { #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("------------ WNC SIM Problem! --------->\r\n"); #endif return (-1); } // SIM card OK, now check for signal and cellular network registration cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, WNC_TIMEOUT_MS); // Check if registered on network pos = pRespStr->find("CREG: "); if (pos != string::npos) { // The registration is the 2nd arg in the comma separated list *pRespStr = pRespStr->substr(pos+8, 1); regSts = atoi(pRespStr->c_str()); // 1 - registered home, 5 - registered roaming if ((regSts != 1) && (regSts != 5)) { #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("------------ WNC Cell Link Down! ------>\r\n"); #endif return (-2); } } #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("------------ WNC Ready ---------------->\r\n"); #endif return (0); } // Sets a global with failure or success, assumes 1 thread all the time int send_wnc_cmd(const char * s, string ** r, int ms_timeout) { int cmdRes; if (check_wnc_ready() < 0) { static string noRespStr; #ifdef WNC_CMD_DEBUG_ON pc.puts("FAIL send cmd: "); #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts(s); #else string truncStr(s, 50); truncStr += "\r\n"; pc.puts(truncStr.c_str()); #endif #else pc.puts("FAIL send cmd!\r\n"); #endif WNC_MDM_ERR = WNC_CELL_LINK_DOWN; noRespStr.erase(); *r = &noRespStr; return (-3); } #ifdef WNC_CMD_DEBUG_ON #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("[---------- Network Status -------------\r\n"); #endif string * pRespStr; at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, 5000); #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts("---------------------------------------]\r\n"); #endif #endif // If WNC ready, send user command cmdRes = at_send_wnc_cmd(s, r, ms_timeout); if (cmdRes == -1) WNC_MDM_ERR = WNC_CMD_ERR; if (cmdRes == -2) WNC_MDM_ERR = WNC_NO_RESPONSE; if (cmdRes == 0) WNC_MDM_ERR = WNC_OK; return (cmdRes); } int at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) { static const char * rsp_lst[] = { "OK", "ERROR", NULL }; int len; #ifdef WNC_CMD_DEBUG_ON #ifdef WNC_CMD_DEBUG_ON_VERBOSE #else if (strlen(s) > 60) { string truncStr(s,57); truncStr += "..."; pc.printf("Send: <<%s>>\r\n",truncStr.c_str()); } else #endif pc.printf("Send: <<%s>>\r\n",s); #endif int res = mdm_sendAtCmdRsp(s, rsp_lst, ms_timeout, &wncStr, &len); *r = &wncStr; // Return a pointer to the static string if (res >= 0) { #ifdef WNC_CMD_DEBUG_ON pc.puts("["); #ifdef WNC_CMD_DEBUG_ON_VERBOSE pc.puts(wncStr.c_str()); pc.puts("]\r\n"); #else if (wncStr.size() < 51) pc.puts(wncStr.c_str()); else { string truncStr = wncStr.substr(0,50) + "..."; pc.puts(truncStr.c_str()); } pc.puts("]\r\n"); #endif #endif if (res > 0) return -1; else return 0; } else { pc.puts("No response from WNC!\n\r"); return -2; } } void at_at_wnc(void) { string * pRespStr; send_wnc_cmd("AT", &pRespStr, WNC_TIMEOUT_MS); // Heartbeat? } void at_init_wnc(bool hardReset) { static bool pdnSet = false; static bool intSet = false; static bool sockDialSet = false; string * pRespStr; int cmdRes; if (hardReset == true) { pc.puts("Hard Reset!\r\n"); pdnSet = false; intSet = false; sockDialSet = false; } pc.puts("Start AT init of WNC:\r\n"); // Quick commands below do not need to check cellular connectivity cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_TIMEOUT_MS); // Heartbeat? cmdRes += at_send_wnc_cmd("ATE0", &pRespStr, WNC_TIMEOUT_MS); // Echo Off cmdRes += at_send_wnc_cmd("AT+CMEE=2", &pRespStr, WNC_TIMEOUT_MS); // 2 - verbose error, 1 - numeric error, 0 - just ERROR // If the simple commands are not working no chance of more complex. // I have seen re-trying commands make it worse. if (cmdRes < 0) { // Since I used the at_send_wnc_cmd I am setting the error state based upon // the responses. And since these are simple commands, even if the WNC // is saying ERROR, treat it like a no response. WNC_MDM_ERR = WNC_NO_RESPONSE; return ; } if (intSet == false) cmdRes = send_wnc_cmd("AT@INTERNET=1", &pRespStr, WNC_TIMEOUT_MS); if (cmdRes == 0) intSet = true; else return ; if (pdnSet == false) { string cmd_str("AT%PDNSET=1,"); cmd_str += MY_APN_STR; cmd_str += ",IP"; cmdRes = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 4*WNC_TIMEOUT_MS); // Set APN, cmd seems to take a little longer sometimes } if (cmdRes == 0) pdnSet = true; else return ; if (sockDialSet == false) cmdRes = send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, WNC_TIMEOUT_MS); if (cmdRes == 0) sockDialSet = true; else return ; pc.puts("SUCCESS: AT init of WNC!\r\n"); } void at_sockopen_wnc(const string & ipStr, const char * port ) { string * pRespStr; send_wnc_cmd("AT@SOCKCREAT=1", &pRespStr, WNC_TIMEOUT_MS); string cmd_str("AT@SOCKCONN=1,\""); cmd_str += ipStr; cmd_str += "\","; cmd_str += port; cmd_str += ",30"; send_wnc_cmd(cmd_str.c_str(), &pRespStr, 31000); } void at_sockclose_wnc(void) { string * pRespStr; send_wnc_cmd("AT@SOCKCLOSE=1", &pRespStr, WNC_TIMEOUT_MS); } int at_dnsresolve_wnc(const char * s, string * ipStr) { string * pRespStr; string str(s); str = "AT@DNSRESVDON=\"" + str + "\""; if (send_wnc_cmd(str.c_str(), &pRespStr, 15000) == 0) { size_t pos_start = pRespStr->find(":\"") + 2; size_t pos_end = pRespStr->rfind("\"") - 1; if ((pos_start != string::npos) && (pos_end != string::npos)) { if (pos_end > pos_start) { // Make a copy for use later (the source string is re-used) *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1); return 1; } else pc.puts("URL Resolve fail, substr Err\r\n"); } else pc.puts("URL Resolve fail, no quotes\r\n"); } else pc.puts("URL Resolve fail, WNC cmd fail\r\n"); *ipStr = "192.168.0.1"; return -1; } void at_sockwrite_wnc(const char * s) { string * pRespStr; char num2str[6]; size_t sLen = strlen(s); if (sLen <= 1500) { string cmd_str("AT@SOCKWRITE=1,"); itoa(sLen, num2str, 10); cmd_str += num2str; cmd_str += ",\""; while(*s != '\0') { itoa((int)*s++, num2str, 16); // Always 2-digit ascii hex: if (strlen(num2str) == 1) { num2str[2] = '\0'; num2str[1] = num2str[0]; num2str[0] = '0'; } cmd_str += num2str; } cmd_str += "\""; send_wnc_cmd(cmd_str.c_str(), &pRespStr, 120000); } else pc.puts("sockwrite Err, string to long\r\n"); } unsigned at_sockread_wnc(string * pS, unsigned n, unsigned retries = 0) { unsigned i, numBytes = 0; string * pRespStr; string cmd_str("AT@SOCKREAD=1,"); // Clean slate pS->erase(); if (n <= 1500) { char num2str[6]; itoa(n, num2str, 10); cmd_str += num2str; retries += 1; while (retries--) { // Assuming someone is sending then calling this to receive response, invoke // a pause to give the response some time to come back and then also // between each retry. wait_ms(10); send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_TIMEOUT_MS); size_t pos_start = pRespStr->find("\"") + 1; size_t pos_end = pRespStr->rfind("\"") - 1; // Make sure search finds what it's looking for! if (pos_start != string::npos && pos_end != string::npos) i = (pos_end - pos_start + 1); // Num hex chars, 2 per byte else i = 0; if (i > 0) { retries = 1; // If any data found retry 1 more time to catch data that might be in another // WNC payload string byte; while (pos_start < pos_end) { byte = pRespStr->substr(pos_start, 2); *pS += (char)strtol(byte.c_str(), NULL, 16); pos_start += 2; } numBytes += i/2; } } } else pc.puts("sockread Err, to many to read\r\n"); return (numBytes); }