FRDM-K64F, Avnet M14A2A, Grove Shield, to create smart home system. In use with AT&Ts M2x & Flow.
Dependencies: mbed FXOS8700CQ MODSERIAL
Revision 75:8cc98a3b9c62, committed 2016-08-13
- Comitter:
- fkellermavnet
- Date:
- Sat Aug 13 17:46:30 2016 +0000
- Parent:
- 74:3e3ee15584e5
- Parent:
- 73:da723fedfdd2
- Child:
- 76:a7a9b9cbfbc0
- Commit message:
- Re-merged in Stefan's branch with Eaddy branch.
Changed in this revision
--- a/cell_modem.cpp Sat Aug 13 15:08:11 2016 +0000 +++ b/cell_modem.cpp Sat Aug 13 17:46:30 2016 +0000 @@ -222,11 +222,12 @@ } int rsp_idx = 0; + // TODO: Test if @EXTERR:<code> while (rsp_list[rsp_idx]) { if (strcasecmp(cmd_buf, rsp_list[rsp_idx]) == 0) { return rsp_idx; } else if (strncmp(cmd_buf, "@EXTERR", 7) == 0){ - pc.printf("----- We got EXTERR ---\r\n"); + PRINTF("----- We got EXTERR ---\r\n"); return 2; } else if (strncmp(cmd_buf, "+CME", 4) == 0){ return 3;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cell_modem.cpp.orig Sat Aug 13 17:46:30 2016 +0000 @@ -0,0 +1,344 @@ +/* =================================================================== +Copyright c 2016, AVNET Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific +language governing permissions and limitations under the License. + +======================================================================== */ + +#include "mbed.h" +#include <cctype> +#include <string> + +#include "config_me.h" +#include "wnc_control.h" +#include "hardware.h" + +#define MDM_DBG_OFF 0 +#define MDM_DBG_AT_CMDS (1 << 0) +int mdm_dbgmask = MDM_DBG_OFF; + +#define WNC_WAIT_FOR_AT_CMD_MS 40 + +DigitalOut mdm_uart2_rx_boot_mode_sel(PTC17); // on powerup, 0 = boot mode, 1 = normal boot +DigitalOut mdm_power_on(PTB9); // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem) +DigitalOut mdm_wakeup_in(PTC2); // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield + +DigitalOut mdm_reset(PTC12); // active high + +DigitalOut shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active +DigitalOut mdm_uart1_cts(PTD0); + +#define TOUPPER(a) (a) //toupper(a) + +const char ok_str[] = "OK"; +const char error_str[] = "ERROR"; + +#define MDM_OK 0 +#define MDM_ERR_TIMEOUT -1 + +#define MAX_AT_RSP_LEN 255 + +ssize_t mdm_getline(char *buff, size_t size, int timeout_ms) { + int cin = -1; + int cin_last; + + if (NULL == buff || size == 0) { + return -1; + } + + size_t len = 0; + Timer timer; + timer.start(); + while ((len < (size-1)) && (timer.read_ms() < timeout_ms)) { + if (mdm.readable()) { + cin_last = cin; + cin = mdm.getc(); + if (isprint(cin)) { + buff[len++] = (char)cin; + continue; + } else if (('\r' == cin_last) && ('\n' == cin)) { + break; + } + } +// wait_ms(1); + } + buff[len] = (char)NULL; + + return len; +} + +int mdm_sendAtCmd(const char *cmd, const char **rsp_list, int timeout_ms) { + // Per WNC wait: + wait_ms(WNC_WAIT_FOR_AT_CMD_MS); + + if (cmd && strlen(cmd) > 0) { + if (mdm_dbgmask & MDM_DBG_AT_CMDS) { + PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd); + } + mdm.puts(cmd); + mdm.puts("\r\n"); + } + + if (rsp_list) { + Timer timer; + char rsp[MAX_AT_RSP_LEN+1]; + int len; + + timer.start(); + while (timer.read_ms() < timeout_ms) { + len = mdm_getline(rsp, sizeof(rsp), timeout_ms - timer.read_ms()); + + if (len < 0) + return MDM_ERR_TIMEOUT; + + if (len == 0) + continue; + + if (mdm_dbgmask & MDM_DBG_AT_CMDS) { + PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", rsp); + } + + if (rsp_list) { + int rsp_idx = 0; + while (rsp_list[rsp_idx]) { + if (strcasecmp(rsp, rsp_list[rsp_idx]) == 0) { + return rsp_idx; + } else if (strncmp(rsp, "@EXTERR", 7) == 0){ + pc.printf("----- We got EXTERR ---\r\n"); + return 2; + } else if (strncmp(rsp, "+CME", 4) == 0){ + return 3; + } + rsp_idx++; + } + } + } + return MDM_ERR_TIMEOUT; + } + return MDM_OK; +} + +int mdm_init(void) { + // Hard reset the modem (doesn't go through + // the signal level translator) + mdm_reset = 0; + + // disable signal level translator (necessary + // for the modem to boot properly). All signals + // except mdm_reset go through the level translator + // and have internal pull-up/down in the module. While + // the level translator is disabled, these pins will + // be in the correct state. + shield_3v3_1v8_sig_trans_ena = 0; + + // While the level translator is disabled and ouptut pins + // are tristated, make sure the inputs are in the same state + // as the WNC Module pins so that when the level translator is + // enabled, there are no differences. + mdm_uart2_rx_boot_mode_sel = 1; // UART2_RX should be high + mdm_power_on = 0; // powr_on should be low + mdm_wakeup_in = 1; // wake-up should be high + mdm_uart1_cts = 0; // indicate that it is ok to send + + // Now, wait for the WNC Module to perform its initial boot correctly + wait(1.0); + + // The WNC module initializes comms at 115200 8N1 so set it up + mdm.baud(115200); + + //Now, enable the level translator, the input pins should now be the + //same as how the M14A module is driving them with internal pull ups/downs. + //When enabled, there will be no changes in these 4 pins... + shield_3v3_1v8_sig_trans_ena = 1; + + // Now, give the modem 60 seconds to start responding by + // sending simple 'AT' commands to modem once per second. + Timer timer; + timer.start(); + while (timer.read() < 60) { + const char * rsp_lst[] = { ok_str, error_str, NULL }; + int rc = mdm_sendAtCmd("AT", rsp_lst, 500); + if (rc == 0) + return true; //timer.read(); + wait_ms(1000 - (timer.read_ms() % 1000)); + PRINTF("\r%d",timer.read_ms()/1000); + } + return false; +} + +int mdm_sendAtCmdRsp(const char *cmd, const char **rsp_list, int timeout_ms, string * rsp, int * len) { + static char cmd_buf[3200]; // Need enough room for the WNC sockreads (over 3000 chars) + size_t n = strlen(cmd); + + // Per WNC wait: + wait_ms(WNC_WAIT_FOR_AT_CMD_MS); + + if (cmd && n > 0) { + if (mdm_dbgmask & MDM_DBG_AT_CMDS) { + PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd); + } +// mdm.puts(cmd); +// mdm.puts("\r\n"); + while (n--) { + mdm.putc(*cmd++); + wait_us(1000); + }; + mdm.putc('\r'); + wait_us(1000); + mdm.putc('\n'); + wait_us(1000); + } + + if (rsp_list) { + rsp->erase(); // Clean up from prior cmd response + *len = 0; + Timer timer; + timer.start(); + while (timer.read_ms() < timeout_ms) { + int lenCmd = mdm_getline(cmd_buf, sizeof(cmd_buf), timeout_ms - timer.read_ms()); + + if (lenCmd == 0) + continue; + + if (lenCmd < 0) + return MDM_ERR_TIMEOUT; + else { + *len += lenCmd; + *rsp += cmd_buf; + } + + if (mdm_dbgmask & MDM_DBG_AT_CMDS) { + PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", cmd_buf); + } + + int rsp_idx = 0; + while (rsp_list[rsp_idx]) { + if (strcasecmp(cmd_buf, rsp_list[rsp_idx]) == 0) { + return rsp_idx; + } else if (strncmp(cmd_buf, "@EXTERR", 7) == 0){ + pc.printf("----- We got EXTERR ---\r\n"); + return 2; + } else if (strncmp(cmd_buf, "+CME", 4) == 0){ + return 3; + } + rsp_idx++; + } + } + return MDM_ERR_TIMEOUT; + } + + return MDM_OK; +} + +void reinitialize_mdm(void) +{ + // Initialize the modem + PRINTF(GRN "Modem RE-initializing..." DEF "\r\n"); + if (!mdm_init()) { + PRINTF(RED "\n\rModem RE-initialization failed!" DEF "\n"); + } + PRINTF("\r\n"); +} +// These are built on the fly +string MyServerIpAddress; +string MySocketData; + +//******************************************************************************************************************************************** +//* Process JSON response messages +//******************************************************************************************************************************************** +bool extract_JSON(char* search_field, char* found_string) +{ + char* beginquote; + char* endquote; + beginquote = strchr(search_field, '{'); //start of JSON + endquote = strchr(search_field, '}'); //end of JSON + if (beginquote) + { + uint16_t ifoundlen; + if (endquote) + { + ifoundlen = (uint16_t) (endquote - beginquote) + 1; + strncpy(found_string, beginquote, ifoundlen ); + found_string[ifoundlen] = 0; //null terminate + return true; + } + else + { + endquote = strchr(search_field, '\0'); //end of string... sometimes the end bracket is missing + ifoundlen = (uint16_t) (endquote - beginquote) + 1; + strncpy(found_string, beginquote, ifoundlen ); + found_string[ifoundlen] = 0; //null terminate + return false; + } + } + else + { + return false; + } +} //extract_JSON + +int cell_modem_init() +{ + int i; + + pc.baud(115200); + // Initialize the modem + PRINTF(GRN "Modem initializing... will take up to 60 seconds" DEF "\r\n"); + do { + i=mdm_init(); + if (!i) { + PRINTF(RED "Modem initialization failed!" DEF "\n"); + } + } while (!i); + + //Software init + software_init_mdm(); + + // Resolve URL to IP address to connect to + resolve_mdm(); + // Open the socket (connect to the server) + sockopen_mdm(); + return (0); +} + +int cell_modem_Sendreceive(char* tx_string, char* rx_string) +{ + int iStatus = 0; //error by default + PRINTF(DEF "\r\n"); + PRINTF(BLU "Sending to modem : %s" DEF "\r\n", &tx_string[0]); + sockwrite_mdm(&tx_string[0]); + if (sockread_mdm(&MySocketData, 1024, 20)) + { + PRINTF(DEF "\r\n"); + PRINTF(YEL "Read back : %s" DEF "\r\n", &MySocketData[0]); + char stringToCharBuf[BUF_SIZE_FOR_N_MAX_SOCKREAD*MAX_WNC_SOCKREAD_PAYLOAD+1]; // WNC can return max of 1500 (per sockread) + if ((MySocketData.length() + 1) < sizeof(stringToCharBuf)) + { + strcpy(stringToCharBuf, MySocketData.c_str()); + if (extract_JSON(stringToCharBuf, &rx_string[0])) + { + PRINTF(GRN "JSON : %s" DEF "\n", &rx_string[0]); + iStatus = 1; //all good + } + } + else + { + PRINTF(RED "BUFFER not big enough for sock data!" DEF "\r\n"); + } + } + else + { + PRINTF(RED "No response..." DEF "\r\n"); + } + return iStatus; +}
--- a/wnc_control.cpp Sat Aug 13 15:08:11 2016 +0000 +++ b/wnc_control.cpp Sat Aug 13 17:46:30 2016 +0000 @@ -59,12 +59,12 @@ cmd_str += MY_APN_STR; cmd_str += ",IP"; at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, 4*WNC_TIMEOUT_MS); // Set APN, cmd seems to take a little longer sometimes - PUTS(cmd_str.c_str()); } static bool reportStatus = true; do { + PUTS("------------ software_init_mdm! --------->\r\n"); if (check_wnc_ready() == 0) { if (reportStatus == false) @@ -290,6 +290,8 @@ // 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 + if (pRespStr->size() > 0) + { pos = pRespStr->find("CREG: "); if (pos != string::npos) { @@ -309,7 +311,15 @@ #ifdef WNC_CMD_DEBUG_ON_VERBOSE PUTS("------------ WNC Ready ---------------->\r\n"); #endif - + } + else + { +#ifdef WNC_CMD_DEBUG_ON_VERBOSE + PUTS("------------ CREG No Reply !----------->\r\n"); +#endif + return (-2); + } + return (0); } @@ -326,6 +336,7 @@ PUTS("FAIL send cmd: "); #ifdef WNC_CMD_DEBUG_ON_VERBOSE PUTS(s); + #else string truncStr(s, 50); truncStr += "\r\n"; @@ -366,7 +377,7 @@ pc.printf("[[WNC_MDM_ERR = WNC_EXTERR]] \r\n"); } - if (cmdRes == 0) + if (cmdRes == 0) WNC_MDM_ERR = WNC_OK; return (cmdRes); @@ -375,8 +386,7 @@ int at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) { //Eaddy - static const char * rsp_lst[] = { "OK", "ERROR","@EXTERR", "+CME",NULL }; - //static const char * rsp_lst[] = { "OK", "ERROR", NULL }; + static const char * rsp_lst[] = { "OK", "ERROR","@EXTERR", "+CME", NULL }; int len; #ifdef WNC_CMD_DEBUG_ON @@ -416,6 +426,7 @@ PUTS("]\r\n"); #endif #endif + #if 0 if (res > 0) return -1; @@ -428,7 +439,7 @@ return 0; } else if (res == 2) { /* @EXTERR */ - pc.printf("@EXTERR and res = %d \r\n", res); + PRINTF("@EXTERR and res = %d \r\n", res); return -3; } else return -1; @@ -522,7 +533,11 @@ cmd_str += "\","; cmd_str += port; cmd_str += ",30"; - send_wnc_cmd(cmd_str.c_str(), &pRespStr, 31000); + int cmd = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 31000); + if (cmd != WNC_OK) { + // Per WNC: re-close even if open fails! + at_sockclose_wnc(); + } } void at_sockclose_wnc(void) @@ -588,7 +603,6 @@ } cmd_str += "\""; res = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 120000); - if (res == -3) PUTS("sockwrite is disconnect \r\n"); } @@ -619,29 +633,35 @@ // 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; + if (send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_TIMEOUT_MS) == 0) + { + 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) + // 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 + else i = 0; - if (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 { - 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; + PUTS("no readsock reply!\r\n"); + return (0); } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wnc_control.cpp.orig Sat Aug 13 17:46:30 2016 +0000 @@ -0,0 +1,652 @@ +/* =================================================================== +Copyright c 2016, AVNET Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific +language governing permissions and limitations under the License. + +======================================================================== */ + +#include "mbed.h" +#include <cctype> +#include <string> +#include "config_me.h" +#include "wnc_control.h" +#include "hardware.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 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, + WNC_EXTERR = -4 +}; + +// 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) +{ + // Temp put here to fix new boards needing init, + // the check for on the cellular network was preventing the PDNSET from happening!!!! + { + PUTS("SET APN STRING!\r\n"); + string * pRespStr; + string cmd_str("AT%PDNSET=1,"); + cmd_str += MY_APN_STR; + cmd_str += ",IP"; + at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, 4*WNC_TIMEOUT_MS); // Set APN, cmd seems to take a little longer sometimes + PUTS(cmd_str.c_str()); + } + + 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; +// 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) + { + PUTS("Bad URL!!!!!!\r\n"); + } + } while (WNC_MDM_ERR != WNC_OK); + + 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) + 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) + { + PUTS("Sock write no response!\r\n"); + software_init_mdm(); + } + else if (WNC_MDM_ERR == WNC_CMD_ERR) + { + PUTS("Socket Write fail!!!\r\n"); + software_init_mdm(); + }else if (WNC_MDM_ERR == WNC_EXTERR) + { + PUTS("Socket Disconnected (broken) !!!\r\n"); + sockclose_mdm(); + sockopen_mdm(); + //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 Lukas 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 + 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 + 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 + 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 + PUTS("------------ WNC Cell Link Down! ------>\r\n"); +#endif + return (-2); + } + } + +#ifdef WNC_CMD_DEBUG_ON_VERBOSE + 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 + PUTS("FAIL send cmd: "); + #ifdef WNC_CMD_DEBUG_ON_VERBOSE + PUTS(s); + #else + string truncStr(s, 50); + truncStr += "\r\n"; + PUTS(truncStr.c_str()); + #endif +#else + 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 + PUTS("[---------- Network Status -------------\r\n"); + #endif + string * pRespStr; + at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, 5000); + #ifdef WNC_CMD_DEBUG_ON_VERBOSE + 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 == -3) { + WNC_MDM_ERR = WNC_EXTERR; + pc.printf("[[WNC_MDM_ERR = WNC_EXTERR]] \r\n"); + } + + if (cmdRes == 0) + WNC_MDM_ERR = WNC_OK; + + return (cmdRes); +} + +int at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) +{ + //Eaddy + static const char * rsp_lst[] = { "OK", "ERROR","@EXTERR", "+CME",NULL }; + //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 += "..."; + PRINTF("Send: <<%s>>\r\n",truncStr.c_str()); + } + else + #endif + 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 + PUTS("["); + #ifdef WNC_CMD_DEBUG_ON_VERBOSE + PUTS(wncStr.c_str()); + PUTS("]\r\n"); + #else + if (wncStr.size() < 51) + PUTS(wncStr.c_str()); + else + { + string truncStr = wncStr.substr(0,50) + "..."; + PUTS(truncStr.c_str()); + } + PUTS("]\r\n"); + #endif +#endif +#if 0 + if (res > 0) + return -1; + else + return 0; +#else + //Eaddy added + if (res == 0) { + /* OK */ + return 0; + } else if (res == 2) { + /* @EXTERR */ + pc.printf("@EXTERR and res = %d \r\n", res); + return -3; + } else + return -1; +#endif + } + else + { + 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) + { + PUTS("Hard Reset!\r\n"); + pdnSet = false; + intSet = false; + sockDialSet = false; + } + + 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 ; + + 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 + PUTS("URL Resolve fail, substr Err\r\n"); + } + else + PUTS("URL Resolve fail, no quotes\r\n"); + } + else + 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); + int res; + 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 += "\""; + res = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 120000); + + if (res == -3) + PUTS("sockwrite is disconnect \r\n"); + } + else + 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 + PUTS("sockread Err, to many to read\r\n"); + + return (numBytes); +}