Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
WncController.cpp
00001 /* 00002 Copyright (c) 2016 Fred Kellerman 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 THE SOFTWARE. 00021 00022 @file WncController.cpp 00023 @purpose Controls WNC 14A2A Cellular Modem 00024 @version 1.0 00025 @date July 2016 00026 @author Fred Kellerman 00027 00028 00029 An Example of usage: 00030 00031 WncControllerK64F mdm(&wncPinList, &mdmUart, &debugUart); 00032 00033 mdm.enableDebug(true, true); 00034 00035 if (false == mdm.powerWncOn("m2m.com.attz", 60)) { 00036 while(1); 00037 } 00038 00039 // ICCID and MSISDN 00040 string iccid; string msisdn; 00041 if (mdm.getICCID(&iccid) == true) { 00042 if (mdm.convertICCIDtoMSISDN(iccid, &msisdn) == true) { 00043 // Send an SMS message (must use 15-digit MISDN number!) 00044 mdm.sendSMSText(msisdn.c_str(), "Hello from WNC Kit -> from WNC"); 00045 } 00046 } 00047 00048 // Get an IP address setup for the socket #1 (0 indexed)) 00049 if (true == mdm.resolveUrl(0, "www.att.com")) 00050 { 00051 // Report server IP 00052 if (true == mdm.getIpAddr(0, ipAddrStr)) { 00053 debugUart.puts("Server IP: "); 00054 debugUart.puts(ipAddrStr); 00055 debugUart.puts("\r\n"); 00056 } 00057 00058 // Open Socket #1, TCP=true resolved IP on port 80: 00059 if (true == mdm.openSocket(0, 80, true)) { 00060 // Write some data 00061 const uint8_t * dataStr = "GET /index.html HTTP/1.0\r\nFrom: someuser@someuser.com\r\nUser-Agent: HTTPTool/1.0\r\n\r\n"; 00062 if (true == mdm.write(0, dataStr, strlen((const char *)dataStr))) 00063 { 00064 const uint8_t * myBuf; 00065 mdm.setReadRetries(0, 20); 00066 uint32_t n = mdm.read(0, &myBuf); 00067 if (n > 0) 00068 debugUart.printf("Read %d chars: %s\r\n", n, myBuf); 00069 else 00070 debugUart.puts("No read data!\r\n"); 00071 } 00072 } 00073 } 00074 00075 */ 00076 00077 00078 #include <cstdlib> 00079 #include <cctype> 00080 #include <string.h> 00081 #include "WncController.h" 00082 00083 namespace WncController_fk { 00084 00085 ///////////////////////////////////////////////////// 00086 // Static initializers 00087 ///////////////////////////////////////////////////// 00088 WncController::WncSocketInfo_s WncController::m_sSock[MAX_NUM_WNC_SOCKETS]; 00089 const WncController::WncSocketInfo_s WncController::defaultSockStruct = { 0, false, "192.168.0.1", 80, 0, 25, true, 30 }; 00090 00091 WncController::WncState_e WncController::m_sState = WNC_OFF; 00092 uint16_t WncController::m_sCmdTimeoutMs = WNC_CMD_TIMEOUT_MS; 00093 string WncController::m_sApnStr = "NULL"; 00094 string WncController::m_sWncStr; 00095 uint8_t WncController::m_sPowerUpTimeoutSecs = MAX_POWERUP_TIMEOUT; 00096 bool WncController::m_sDebugEnabled = false; 00097 bool WncController::m_sMoreDebugEnabled = false; 00098 bool WncController::m_sCheckNetStatus = false; // Turn on internet status check between every command 00099 const char * const WncController::INVALID_IP_STR = ""; 00100 bool WncController::m_sReadyForSMS = false; 00101 00102 00103 /** 00104 * C++ version 0.4 char* style "itoa": 00105 * Written by Lukás Chmela 00106 * Released under GPLv3. 00107 */ 00108 static char* itoa(int64_t value, char* result, int base) 00109 { 00110 // check that the base is valid 00111 if ( base < 2 || base > 36 ) { 00112 *result = '\0'; 00113 return result; 00114 } 00115 00116 char* ptr = result, *ptr1 = result, tmp_char; 00117 int64_t tmp_value; 00118 00119 do { 00120 tmp_value = value; 00121 value /= base; 00122 *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; 00123 } while ( value ); 00124 00125 // Apply negative sign 00126 if ( tmp_value < 0 ) 00127 *ptr++ = '-'; 00128 00129 *ptr-- = '\0'; 00130 00131 while ( ptr1 < ptr ) { 00132 tmp_char = *ptr; 00133 *ptr-- = *ptr1; 00134 *ptr1++ = tmp_char; 00135 } 00136 00137 return result; 00138 } 00139 00140 const char * WncController::_to_string(int64_t value) 00141 { 00142 static char str[21]; // room for signed 64-bit + null 00143 itoa(value, str, 10); 00144 return (str); 00145 } 00146 00147 const char * WncController::_to_hex_string(uint8_t value) 00148 { 00149 static char str[3]; // room for 8-bit + null 00150 itoa(value, str, 16); 00151 return (str); 00152 } 00153 00154 WncController::WncController(void) 00155 { 00156 for(unsigned i=0; i<MAX_NUM_WNC_SOCKETS; i++) 00157 m_sSock[i] = defaultSockStruct; 00158 } 00159 00160 WncController::~WncController(void) {}; 00161 00162 void WncController::enableDebug(bool on, bool moreDebugOn) 00163 { 00164 m_sDebugEnabled = on; 00165 m_sMoreDebugEnabled = moreDebugOn; 00166 } 00167 00168 WncController::WncState_e WncController::getWncStatus(void) 00169 { 00170 return (m_sState); 00171 } 00172 00173 int16_t WncController::getDbmRssi(void) 00174 { 00175 int16_t rssi, ber; 00176 if (at_getrssiber_wnc(&rssi, &ber) == true) 00177 return (rssi); 00178 else 00179 return (99); 00180 } 00181 00182 int16_t WncController::get3gBer(void) 00183 { 00184 int16_t rssi, ber; 00185 if (at_getrssiber_wnc(&rssi, &ber) == true) 00186 return (ber); 00187 else 00188 return (99); 00189 } 00190 00191 bool WncController::powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs) 00192 { 00193 dbgPuts("Waiting for WNC to Initialize..."); 00194 m_sPowerUpTimeoutSecs = powerUpTimeoutSecs; 00195 m_sState = WNC_ON_NO_CELL_LINK; // Turn soft on to allow "AT" for init to be sent! 00196 if (initWncModem(powerUpTimeoutSecs) == true) { 00197 // Set the Apn 00198 setApnName(apn); 00199 if (false == softwareInitMdm()) { 00200 dbgPuts("Software init failed!"); 00201 m_sState = WNC_OFF; 00202 } 00203 } 00204 else { 00205 dbgPuts("Power up failed!"); 00206 m_sState = WNC_OFF; 00207 } 00208 00209 return ((m_sState == WNC_ON) || (m_sState == WNC_ON_NO_CELL_LINK)); 00210 } 00211 00212 size_t WncController::sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout) 00213 { 00214 string * respStr; 00215 00216 if (sizeRespBuf > 0) { 00217 at_send_wnc_cmd(cmd, &respStr, ms_timeout); 00218 strncpy(resp, respStr->c_str(), sizeRespBuf); 00219 if (respStr->size() > sizeRespBuf) 00220 dbgPuts("sendCustomCmd truncated!"); 00221 00222 return (respStr->size()); 00223 } 00224 00225 dbgPuts("sendCustomCmd: would have overrun!"); 00226 00227 return (0); 00228 } 00229 00230 bool WncController::pingUrl(const char * url) 00231 { 00232 string ipAddr; 00233 00234 if (true == at_dnsresolve_wnc(url, &ipAddr)) 00235 return (pingIp(ipAddr.c_str())); 00236 else 00237 dbgPuts("pingUrl DNS resolve: failed!"); 00238 00239 return (false); 00240 } 00241 00242 bool WncController::pingIp(const char * ip) 00243 { 00244 if (true == at_ping_wnc(ip)) 00245 return (true); 00246 else 00247 dbgPuts("pingIp: failed!"); 00248 00249 return (false); 00250 } 00251 00252 bool WncController::getWncNetworkingStats(WncIpStats * s) 00253 { 00254 return (at_get_wnc_net_stats(s)); 00255 } 00256 00257 bool WncController::getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR]) 00258 { 00259 if (numSock < MAX_NUM_WNC_SOCKETS) { 00260 strncpy(myIpAddr, m_sSock[numSock].myIpAddressStr.c_str(), MAX_LEN_IP_STR); 00261 myIpAddr[MAX_LEN_IP_STR - 1] = '\0'; 00262 return (true); 00263 } 00264 else { 00265 myIpAddr[0] = '\0'; 00266 return (false); 00267 } 00268 } 00269 00270 bool WncController::setApnName(const char * const apnStr) 00271 { 00272 if (at_setapn_wnc(apnStr) == true) 00273 { 00274 m_sApnStr = apnStr; 00275 return (true); 00276 } 00277 else 00278 return (false); 00279 } 00280 00281 bool WncController::resolveUrl(uint16_t numSock, const char * url) 00282 { 00283 bool cmdRes; 00284 00285 if (numSock < MAX_NUM_WNC_SOCKETS) { 00286 if (strlen(url) > 0) { 00287 cmdRes = at_dnsresolve_wnc(url, &m_sSock[numSock].myIpAddressStr); 00288 if (cmdRes == false) 00289 dbgPuts("Cannot resolve URL!"); 00290 return (cmdRes); 00291 } 00292 else 00293 dbgPuts("Invalid URL"); 00294 } 00295 else 00296 dbgPuts("Invalid Sock num!"); 00297 00298 return (false); 00299 } 00300 00301 bool WncController::setIpAddr(uint16_t numSock, const char * ipStr) 00302 { 00303 if (numSock < MAX_NUM_WNC_SOCKETS) { 00304 m_sSock[numSock].myIpAddressStr = ipStr; 00305 return (true); 00306 } 00307 else { 00308 dbgPuts("Bad socket num!"); 00309 return (false); 00310 } 00311 } 00312 00313 void WncController::setWncCmdTimeout(uint16_t toMs) 00314 { 00315 m_sCmdTimeoutMs = toMs; 00316 } 00317 00318 bool WncController::openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec) 00319 { 00320 if (resolveUrl(numSock, url) == true) 00321 return (openSocket(numSock, port, tcp, timeOutSec)); 00322 00323 return (false); 00324 } 00325 00326 bool WncController::openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec) 00327 { 00328 if (setIpAddr(numSock, ipAddr) == true) 00329 return (openSocket(numSock, port, tcp, timeOutSec)); 00330 00331 return (false); 00332 } 00333 00334 bool WncController::openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec) 00335 { 00336 if (numSock < MAX_NUM_WNC_SOCKETS) { 00337 // IPV4 ip addr sanity check! 00338 size_t lenIpStr = m_sSock[numSock].myIpAddressStr.size(); 00339 if (lenIpStr < 7 || lenIpStr > 15) { 00340 dbgPuts("Invalid IP Address!"); 00341 return (false); 00342 } 00343 00344 // Already open ? Must close if want to re-open with new settings. 00345 if (m_sSock[numSock].open == true) { 00346 dbgPuts("Socket already open, close then re-open!"); 00347 if (true == at_sockclose_wnc(m_sSock[numSock].numWncSock)) 00348 m_sSock[numSock].open = false; 00349 else 00350 return (false); 00351 } 00352 00353 m_sSock[numSock].myPort = port; 00354 m_sSock[numSock].isTcp = tcp; 00355 m_sSock[numSock].timeOutSec = timeOutSec; 00356 00357 int16_t numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), port, numSock, tcp, timeOutSec); 00358 m_sSock[numSock].numWncSock = numWncSock; 00359 if (numWncSock > 0 && numWncSock <= (uint16_t)MAX_NUM_WNC_SOCKETS) 00360 m_sSock[numSock].open = true; 00361 else { 00362 m_sSock[numSock].open = false; 00363 dbgPuts("Socket open fail!!!!"); 00364 00365 // If the modem is not responding don't bother it. 00366 if (WNC_NO_RESPONSE != getWncStatus()) { 00367 // Work-around. If the sock open fails it needs to be told 00368 // to close. If 6 sock opens happen with a fail, it further 00369 // crashes the WNC. Not sure why the sock won't open. 00370 at_sockclose_wnc(m_sSock[numSock].numWncSock); 00371 } 00372 } 00373 } 00374 else { 00375 dbgPuts("Bad socket num or IP!"); 00376 return (false); 00377 } 00378 00379 return (m_sSock[numSock].open); 00380 } 00381 00382 bool WncController::sockWrite(const uint8_t * const s, uint16_t n, uint16_t numSock, bool isTcp) 00383 { 00384 bool result = true; 00385 00386 AtCmdErr_e cmdRes = at_sockwrite_wnc(s, n, m_sSock[numSock].numWncSock, isTcp); 00387 if (cmdRes != WNC_AT_CMD_OK) { 00388 if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00389 { 00390 // This may throw away any data that hasn't been written out of the WNC 00391 // but at this point with the way the WNC currently works we have 00392 // no choice. 00393 closeOpenSocket(numSock); 00394 } 00395 result = false; 00396 } 00397 00398 return (result); 00399 } 00400 00401 bool WncController::write(uint16_t numSock, const uint8_t * s, uint32_t n) 00402 { 00403 bool result; 00404 00405 if (numSock < MAX_NUM_WNC_SOCKETS) { 00406 if (m_sSock[numSock].open == true) { 00407 if (n <= MAX_WNC_WRITE_BYTES) { 00408 result = sockWrite(s, n, numSock, m_sSock[numSock].isTcp); 00409 } 00410 else { 00411 uint16_t rem = n % MAX_WNC_WRITE_BYTES; 00412 while (n >= MAX_WNC_WRITE_BYTES) { 00413 n -= MAX_WNC_WRITE_BYTES; 00414 result = sockWrite(s, MAX_WNC_WRITE_BYTES, numSock, m_sSock[numSock].isTcp); 00415 if (result == false) { 00416 n = 0; 00417 rem = 0; 00418 dbgPuts("Sock write fail!"); 00419 } 00420 else 00421 s += MAX_WNC_WRITE_BYTES; 00422 } 00423 if (rem > 0) 00424 result = sockWrite(s, rem, numSock, m_sSock[numSock].isTcp); 00425 } 00426 } 00427 else { 00428 dbgPuts("Socket is closed for write!"); 00429 result = false; 00430 } 00431 } 00432 else { 00433 dbgPuts("Bad socket num!"); 00434 result = false; 00435 } 00436 00437 return (result); 00438 } 00439 00440 size_t WncController::read(uint16_t numSock, const uint8_t ** readBuf) 00441 { 00442 static string theBuf; 00443 string readStr; 00444 00445 theBuf.erase(); // Clean-up from last time 00446 00447 if (numSock < MAX_NUM_WNC_SOCKETS) { 00448 if (m_sSock[numSock].open == true) { 00449 uint8_t i = m_sSock[numSock].readRetries; 00450 uint16_t to = m_sSock[numSock].readRetryWaitMs; 00451 bool foundData = false; 00452 do { 00453 AtCmdErr_e cmdRes; 00454 cmdRes = at_sockread_wnc(&readStr, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00455 if (WNC_AT_CMD_OK == cmdRes) { 00456 // This will let this loop read until the socket data is 00457 // empty. If no data, then wait the retry amount of time. 00458 if (readStr.size() > 0) { 00459 theBuf += readStr; 00460 foundData = true; 00461 i = 1; 00462 } 00463 else { 00464 // Once data is found start returning it asap 00465 if (foundData == false) 00466 waitMs(to); 00467 } 00468 } 00469 else { 00470 theBuf += readStr; // Append what if any we got before it errored. 00471 dbgPuts("Sockread failed!"); 00472 if (WNC_NO_RESPONSE == getWncStatus()) { 00473 i = 0; 00474 } 00475 else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00476 { 00477 // This may throw away any data that hasn't been read out of the WNC 00478 // but at this point with the way the WNC currently works we have 00479 // no choice. 00480 closeOpenSocket(numSock); 00481 i = 0; 00482 } 00483 else 00484 waitMs(to); 00485 } 00486 } while (i-- > 0); 00487 } 00488 else { 00489 dbgPuts("Socket is closed for read"); 00490 } 00491 } 00492 else { 00493 dbgPuts("Bad socket num!"); 00494 } 00495 00496 *readBuf = (const uint8_t *)theBuf.c_str(); 00497 00498 return (theBuf.size()); 00499 } 00500 00501 size_t WncController::read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen) 00502 { 00503 uint32_t numCopied = 0; 00504 00505 if (numSock < MAX_NUM_WNC_SOCKETS) { 00506 if (m_sSock[numSock].open == true) { 00507 uint8_t i = m_sSock[numSock].readRetries; 00508 uint16_t to = m_sSock[numSock].readRetryWaitMs; 00509 bool foundData = false; 00510 uint16_t numRead; 00511 do { 00512 AtCmdErr_e cmdRes; 00513 if (maxReadBufLen < MAX_WNC_READ_BYTES) 00514 cmdRes = at_sockread_wnc(readBuf, &numRead, maxReadBufLen, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00515 else 00516 cmdRes = at_sockread_wnc(readBuf, &numRead, MAX_WNC_READ_BYTES, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00517 00518 if (WNC_AT_CMD_OK == cmdRes) { 00519 // This will let this loop read until the socket data is 00520 // empty. If no data, then wait the retry amount of time. 00521 if (numRead > 0) { 00522 foundData = true; 00523 i = 1; 00524 if (numRead <= maxReadBufLen) { 00525 maxReadBufLen -= numRead; 00526 numCopied += numRead; 00527 readBuf += numRead; 00528 } 00529 else { 00530 i = 0; // No more room for data! 00531 dbgPutsNoTime("No more room for read data!"); 00532 } 00533 } 00534 else { 00535 // Once data is found start returning it asap 00536 if (foundData == false) 00537 waitMs(to); 00538 } 00539 } 00540 else { 00541 dbgPuts("Sockread failed!"); 00542 if (WNC_NO_RESPONSE == getWncStatus()) { 00543 i = 0; 00544 } 00545 else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00546 { 00547 // This may throw away any data that hasn't been read out of the WNC 00548 // but at this point with the way the WNC currently works we have 00549 // no choice. 00550 closeOpenSocket(numSock); 00551 i = 0; 00552 } 00553 else 00554 waitMs(to); 00555 } 00556 } while ((i-- > 0) && (maxReadBufLen > 0)); 00557 } 00558 else { 00559 dbgPuts("Socket is closed for read"); 00560 } 00561 } 00562 else { 00563 dbgPuts("Bad socket num!"); 00564 } 00565 00566 return (numCopied); 00567 } 00568 00569 void WncController::setReadRetries(uint16_t numSock, uint16_t retries) 00570 { 00571 if (numSock < MAX_NUM_WNC_SOCKETS) 00572 m_sSock[numSock].readRetries = retries; 00573 else 00574 dbgPuts("Bad socket num!"); 00575 } 00576 00577 void WncController::setReadRetryWait(uint16_t numSock, uint16_t readRetryWaitMs) 00578 { 00579 if (numSock < MAX_NUM_WNC_SOCKETS) 00580 m_sSock[numSock].readRetryWaitMs = readRetryWaitMs; 00581 else 00582 dbgPuts("Bad socket num!"); 00583 } 00584 00585 bool WncController::closeSocket(uint16_t numSock) 00586 { 00587 if (numSock < MAX_NUM_WNC_SOCKETS) { 00588 00589 if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) 00590 dbgPuts("Sock close may not have closed!"); 00591 00592 // Even with an error the socket could have closed, 00593 // can't tell for sure so just soft close it for now. 00594 m_sSock[numSock].open = false; 00595 } 00596 else { 00597 dbgPuts("Bad socket num!"); 00598 } 00599 00600 return (m_sSock[numSock].open == false); 00601 } 00602 00603 size_t WncController::mdmGetline(string * buff, int timeout_ms) 00604 { 00605 char chin = '\0'; 00606 char chin_last; 00607 size_t len = 0; 00608 00609 startTimerB(); 00610 while ((len <= MAX_LEN_WNC_CMD_RESPONSE) && (getTimerTicksB_mS() < timeout_ms)) { 00611 if (charReady()) { 00612 chin_last = chin; 00613 chin = getc(); 00614 if (isprint(chin)) { 00615 *buff += chin; 00616 len++; // Bound the copy length to something reaonable just in case 00617 continue; 00618 } 00619 else if ((('\r' == chin_last) && ('\n' == chin)) || (('\n' == chin_last) && ('\r' == chin))) { 00620 break; 00621 } 00622 } 00623 } 00624 stopTimerB(); 00625 00626 if (len > MAX_LEN_WNC_CMD_RESPONSE) 00627 dbgPuts("Max cmd length reply exceeded!"); 00628 00629 return (len); 00630 } 00631 00632 bool WncController::softwareInitMdm(void) 00633 { 00634 static bool reportStatus = true; 00635 unsigned i; 00636 00637 if (checkCellLink() == true) { 00638 if (reportStatus == false) { 00639 dbgPuts("Re-connected to cellular network!"); 00640 reportStatus = true; 00641 } 00642 00643 // WNC has SIM and registered on network so 00644 // soft initialize the WNC. 00645 for (i = 0; i < WNC_SOFT_INIT_RETRY_COUNT; i++) 00646 if (at_init_wnc() == true) 00647 break; 00648 00649 // If it did not respond try a hardware init 00650 if (i == WNC_SOFT_INIT_RETRY_COUNT) 00651 { 00652 at_reinitialize_mdm(); 00653 return (at_init_wnc(true)); // Hard reset occurred so make it go through the software init(); 00654 } 00655 else 00656 return (true); 00657 } 00658 else 00659 { 00660 if (reportStatus == true) { 00661 dbgPuts("Not connected to cellular network!"); 00662 reportStatus = false; 00663 } 00664 return (false); 00665 } 00666 } 00667 00668 WncController::AtCmdErr_e WncController::sendWncCmd(const char * const s, string ** r, int ms_timeout) 00669 { 00670 if (checkCellLink() == false) { 00671 static string noRespStr; 00672 00673 // Save some run-time! 00674 if (m_sDebugEnabled) 00675 { 00676 dbgPuts("FAIL send cmd: ", false); 00677 if (m_sMoreDebugEnabled && m_sDebugEnabled) { 00678 dbgPutsNoTime(s); 00679 } 00680 else { 00681 size_t n = strlen(s); 00682 if (n <= WNC_TRUNC_DEBUG_LENGTH) { 00683 dbgPutsNoTime(s); 00684 } 00685 else { 00686 string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); 00687 truncStr += ".."; 00688 truncStr += &s[n-(WNC_TRUNC_DEBUG_LENGTH/2)]; 00689 dbgPutsNoTime(truncStr.c_str()); 00690 } 00691 } 00692 } 00693 00694 noRespStr.erase(); 00695 *r = &noRespStr; 00696 00697 return (WNC_AT_CMD_NO_CELL_LINK); 00698 } 00699 00700 if (m_sCheckNetStatus) 00701 { 00702 if (m_sMoreDebugEnabled) 00703 dbgPuts("[---------- Network Status -------------"); 00704 string * pRespStr; 00705 at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, m_sCmdTimeoutMs); 00706 if (m_sMoreDebugEnabled) 00707 dbgPuts("---------------------------------------]"); 00708 } 00709 00710 // If WNC ready, send user command 00711 return (at_send_wnc_cmd(s, r, ms_timeout)); 00712 } 00713 00714 WncController::AtCmdErr_e WncController::at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) 00715 { 00716 // Save some run-time! 00717 if (m_sDebugEnabled) 00718 { 00719 if (m_sMoreDebugEnabled) { 00720 dbgPuts("TX: ", false); dbgPutsNoTime(s); 00721 } 00722 else { 00723 if (m_sDebugEnabled) { // Save some run-time! 00724 size_t n = strlen(s); 00725 if (n <= WNC_TRUNC_DEBUG_LENGTH) { 00726 dbgPuts("TX: ", false); dbgPutsNoTime(s); 00727 } 00728 else { 00729 string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); 00730 truncStr += ".."; 00731 truncStr += &s[n - (WNC_TRUNC_DEBUG_LENGTH/2)]; 00732 dbgPuts("TX: ", false); dbgPutsNoTime(truncStr.c_str()); 00733 } 00734 } 00735 } 00736 } 00737 00738 AtCmdErr_e atResult = mdmSendAtCmdRsp(s, ms_timeout, &m_sWncStr); 00739 *r = &m_sWncStr; // Return a pointer to the static string 00740 00741 if (atResult != WNC_AT_CMD_TIMEOUT) { 00742 // If a prior command timed out but a new one works then 00743 // change the state back to ON. We don't know here in this 00744 // method if the Cell Link is good so assume it is. When a command 00745 // that depends on the cell link is made it will update the state. 00746 if (m_sState == WNC_NO_RESPONSE) 00747 m_sState = WNC_ON; 00748 00749 // Save some run-time! 00750 if (m_sDebugEnabled) 00751 { 00752 dbgPuts("RX: ", false); 00753 if (m_sMoreDebugEnabled) { 00754 dbgPutsNoTime(m_sWncStr.c_str()); 00755 } 00756 else { 00757 if (m_sWncStr.size() <= WNC_TRUNC_DEBUG_LENGTH) { 00758 dbgPutsNoTime(m_sWncStr.c_str()); 00759 } 00760 else { 00761 string truncStr = m_sWncStr.substr(0,WNC_TRUNC_DEBUG_LENGTH/2) + ".."; 00762 truncStr += m_sWncStr.substr(m_sWncStr.size() - (WNC_TRUNC_DEBUG_LENGTH/2), WNC_TRUNC_DEBUG_LENGTH/2); 00763 dbgPutsNoTime(truncStr.c_str()); 00764 } 00765 } 00766 } 00767 } 00768 else { 00769 m_sState = WNC_NO_RESPONSE; 00770 dbgPuts("AT Cmd TIMEOUT!"); 00771 dbgPuts("RX: ", false); dbgPutsNoTime(m_sWncStr.c_str()); 00772 } 00773 00774 return (atResult); 00775 } 00776 00777 void WncController::closeOpenSocket(uint16_t numSock) 00778 { 00779 // Try to open and close the socket 00780 do { 00781 dbgPuts("Try to close and re-open socket"); 00782 if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) { 00783 if (WNC_NO_RESPONSE == getWncStatus()) { 00784 dbgPuts("No response for closeOpenSocket1"); 00785 return ; 00786 } 00787 } 00788 00789 int numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), m_sSock[numSock].myPort, numSock, m_sSock[numSock].isTcp, m_sSock[numSock].timeOutSec); 00790 m_sSock[numSock].numWncSock = numWncSock; 00791 if (numWncSock > 0 && numWncSock <= (int)MAX_NUM_WNC_SOCKETS) 00792 m_sSock[numSock].open = true; 00793 else { 00794 m_sSock[numSock].open = false; 00795 dbgPuts("Failed to re-open socket!"); 00796 } 00797 00798 if (WNC_NO_RESPONSE == getWncStatus()) { 00799 dbgPuts("No response for closeOpenSocket2"); 00800 return ; 00801 } 00802 } while (m_sSock[numSock].open == false); 00803 } 00804 00805 bool WncController::getICCID(string * iccid) 00806 { 00807 if (at_geticcid_wnc(iccid) == false) { 00808 dbgPuts("getICCID error!"); 00809 return (false); 00810 } 00811 00812 return (true); 00813 } 00814 00815 bool WncController::at_geticcid_wnc(string * iccid) 00816 { 00817 string * respStr; 00818 00819 iccid->erase(); 00820 00821 AtCmdErr_e r = at_send_wnc_cmd("AT%CCID", &respStr, m_sCmdTimeoutMs); 00822 00823 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 00824 return (false); 00825 00826 // New Firmware versions respond to the %CCID command with "%CCID:" 00827 // but old version respond with "AT%CCID", so check to see which we have 00828 size_t pos = respStr->find(":"); 00829 if (pos == string::npos) 00830 pos = respStr->find("AT%CCID"); 00831 else 00832 pos = respStr->find("%CCID"); 00833 00834 if (pos == string::npos) 00835 return (false); 00836 00837 pos += 7; // Advanced to the number 00838 00839 size_t posOK = respStr->rfind("OK"); 00840 if (posOK == string::npos) 00841 return (false); 00842 00843 *iccid = respStr->substr(pos, posOK - pos); 00844 00845 return (true); 00846 } 00847 00848 bool WncController::convertICCIDtoMSISDN(const string & iccid, string * msisdn) 00849 { 00850 msisdn->erase(); 00851 00852 if (iccid.size() != 20 && iccid.size() != 19) { 00853 dbgPuts("Invalid ICCID length!"); 00854 return (false); 00855 } 00856 00857 *msisdn = "882350"; 00858 00859 if (iccid.size() == 20) 00860 *msisdn += iccid.substr(10,iccid.size() - 11); 00861 else 00862 *msisdn += iccid.substr(10,iccid.size() - 10); 00863 00864 return (true); 00865 } 00866 00867 bool WncController::sendSMSText(const char * const phoneNum, const char * const text) 00868 { 00869 if (at_sendSMStext_wnc(phoneNum, text) == true) 00870 return (true); 00871 else { 00872 dbgPuts("sendSMSText: Failed!"); 00873 return (false); 00874 } 00875 } 00876 00877 bool WncController::readSMSLog(struct WncSmsList * log) 00878 { 00879 string * logStr; 00880 uint16_t i; 00881 00882 if (at_readSMSlog_wnc(&logStr) == false) { 00883 dbgPuts("readSMSLog: Failed!"); 00884 return (false); 00885 } 00886 00887 // Clean slate 00888 log->msgCount = 0; 00889 00890 if (logStr->size() == 0) 00891 return (false); 00892 00893 // Pick out the stuff from the string and convert to struct 00894 string s; 00895 size_t pos2; 00896 size_t pos = logStr->find("+CMGL:"); 00897 00898 for(i=0; i<MAX_WNC_SMS_MSG_SLOTS; i++) { 00899 // Start with a clean slate, let parsing fill out later. 00900 log->e[i].unread = false; 00901 log->e[i].incoming = false; 00902 log->e[i].unsent = false; 00903 log->e[i].pduMode = false; 00904 log->e[i].msgReceipt = false; 00905 00906 log->e[i].idx = logStr->at(pos + 7); 00907 if (pos == string::npos) 00908 return (false); 00909 pos2 = logStr->find(",\"", pos); 00910 if (pos2 == string::npos) { 00911 // If the WNC acts wrong and receives a PDU mode 00912 // SMS there will not be any quotes in the response, 00913 // just take the whole reply and make it the message body for 00914 // now, mark it as an unread message, set the pdu flag! 00915 log->e[log->msgCount].unread = true; 00916 log->e[log->msgCount].pduMode = true; 00917 log->msgCount++; 00918 00919 pos2 = logStr->find("+CMGL", pos + 5); 00920 if (pos2 == string::npos) { 00921 pos2 = logStr->find("OK", pos + 5); 00922 if (pos2 == string::npos) { 00923 dbgPuts("Strange SMS Log Ending!"); 00924 return (false); 00925 } 00926 i = MAX_WNC_SMS_MSG_SLOTS; 00927 } 00928 log->e[log->msgCount].msg = logStr->substr(0, pos2 - pos); 00929 pos = pos2; // for loop starts off expecting pos to point to next log msg 00930 continue; 00931 } 00932 pos += 2; // Advance to the text we want 00933 pos2 = logStr->find("\",", pos); 00934 if ((pos2 == string::npos) || (pos >= pos2)) 00935 return (false); 00936 00937 // Setup attributes 00938 s = logStr->substr(pos, pos2 - pos); 00939 if (s.find("REC READ") != string::npos) 00940 log->e[i].incoming = true; 00941 if (s.find("REC UNREAD") != string::npos) { 00942 log->e[i].unread = true; 00943 log->e[i].incoming = true; 00944 } 00945 if (s.find("STO UNSENT") != string::npos) 00946 log->e[i].unsent = true; 00947 if (logStr->find(",,") == string::npos) 00948 log->e[i].msgReceipt = true; 00949 00950 // Tele number 00951 pos2 = logStr->find(",\"", pos2); 00952 if (pos2 == string::npos) 00953 return (false); 00954 pos2 += 2; // Advance to next field 00955 pos = logStr->find("\",", pos2); 00956 if ((pos == string::npos) || (pos2 > pos)) 00957 return (false); 00958 if (pos == pos2) 00959 log->e[i].number.erase(); 00960 else 00961 log->e[i].number = logStr->substr(pos2, pos - pos2); 00962 00963 // Date 00964 pos = logStr->find(",\"", pos); 00965 if (pos == string::npos) 00966 return (false); 00967 pos += 2; // Beginning of date field 00968 pos2 = logStr->find(",", pos); // End of timestamp field 00969 if ((pos2 == string::npos) || (pos > pos2)) 00970 return (false); 00971 if (pos == pos2) 00972 log->e[i].date.erase(); 00973 else 00974 log->e[i].date = logStr->substr(pos, pos2 - pos); 00975 00976 // Timestamp 00977 pos = logStr->find("\",", pos2); // End of timestamp 00978 if (pos == string::npos) 00979 return (false); 00980 pos2 += 1; // Beginning of time field 00981 if (pos < pos2) 00982 return (false); 00983 if (pos == pos2) 00984 log->e[i].time.erase(); 00985 else 00986 log->e[i].time = logStr->substr(pos2, pos - pos2); 00987 00988 // Message field 00989 00990 // We don't know how many messages we have so the next search 00991 // could end with +CMGL or OK. 00992 pos += 2; // Advanced to message text 00993 pos2 = logStr->find("+CMGL", pos); 00994 if (pos2 == string::npos) { 00995 pos2 = logStr->find("OK", pos); 00996 if (pos2 == string::npos) { 00997 dbgPuts("Strange SMS Log Ending!"); 00998 return (false); 00999 } 01000 i = MAX_WNC_SMS_MSG_SLOTS; // break 01001 } 01002 if (pos > pos2) 01003 return (false); 01004 if (pos == pos2) 01005 log->e[log->msgCount].msg.erase(); 01006 else 01007 log->e[log->msgCount].msg = logStr->substr(pos, pos2 - pos); 01008 01009 log->msgCount++; // Message complete 01010 } 01011 01012 return (true); 01013 } 01014 01015 bool WncController::readUnreadSMSText(struct WncSmsList * w, bool deleteRead) 01016 { 01017 struct WncController::WncSmsList tmp; 01018 01019 if (readSMSLog(&tmp) == false) 01020 return (false); 01021 01022 w->msgCount = 0; 01023 for(uint16_t i = 0; i < tmp.msgCount; i++) { 01024 if (tmp.e[i].unread == true) { 01025 w->e[w->msgCount] = tmp.e[i]; 01026 w->msgCount++; 01027 if (deleteRead == true) { 01028 // Clean up message that was copied out and read 01029 deleteSMSTextFromMem(w->e[i].idx); 01030 } 01031 } 01032 } 01033 01034 return (w->msgCount > 0); 01035 } 01036 01037 size_t WncController::getSignalQuality(const char ** log) 01038 { 01039 size_t n; 01040 01041 n = at_getSignalQuality_wnc(log); 01042 if (n == 0) 01043 dbgPuts("readSMSText: Failed!"); 01044 01045 return (n); 01046 } 01047 01048 size_t WncController::at_getSignalQuality_wnc(const char ** log) 01049 { 01050 string * pRespStr; 01051 static string logStr; 01052 01053 logStr.erase(); 01054 01055 if (at_send_wnc_cmd("AT%MEAS=\"0\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01056 logStr = *pRespStr; 01057 logStr += "\r\n"; 01058 } 01059 else 01060 dbgPuts("AT%MEAS=0: failed!"); 01061 01062 if (at_send_wnc_cmd("AT%MEAS=\"1\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01063 logStr += *pRespStr; 01064 logStr += "\r\n"; 01065 } 01066 else 01067 dbgPuts("AT%MEAS=1: failed!"); 01068 01069 if (at_send_wnc_cmd("AT%MEAS=\"2\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01070 logStr += *pRespStr; 01071 logStr += "\r\n"; 01072 } 01073 else 01074 dbgPuts("AT%MEAS=2: failed!"); 01075 01076 if (at_send_wnc_cmd("AT%MEAS=\"3\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01077 logStr += *pRespStr; 01078 logStr += "\r\n"; 01079 } 01080 else 01081 dbgPuts("AT%MEAS=3: failed!"); 01082 01083 if (at_send_wnc_cmd("AT%MEAS=\"4\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01084 logStr += *pRespStr; 01085 logStr += "\r\n"; 01086 } 01087 else 01088 dbgPuts("AT%MEAS=4: failed!"); 01089 01090 if (at_send_wnc_cmd("AT%MEAS=\"5\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01091 logStr += *pRespStr; 01092 logStr += "\r\n"; 01093 } 01094 else 01095 dbgPuts("AT%MEAS=5: failed!"); 01096 01097 if (at_send_wnc_cmd("AT%MEAS=\"8\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01098 logStr += *pRespStr; 01099 logStr += "\r\n"; 01100 } 01101 else 01102 dbgPuts("AT%MEAS=8: failed!"); 01103 01104 if (at_send_wnc_cmd("AT%MEAS=\"98\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01105 logStr += *pRespStr; 01106 logStr += "\r\n"; 01107 } 01108 else 01109 dbgPuts("AT%MEAS=98: failed!"); 01110 01111 *log = logStr.c_str(); 01112 01113 return (logStr.size()); 01114 } 01115 01116 bool WncController::getTimeDate(struct WncDateTime * tod) 01117 { 01118 if (at_gettimedate_wnc(tod) == true) 01119 return (true); 01120 else { 01121 dbgPuts("Get time date failed!"); 01122 return (false); 01123 } 01124 } 01125 01126 bool WncController::at_ping_wnc(const char * ip) 01127 { 01128 string * pRespStr; 01129 string cmdStr = "AT@PINGREQ=\""; 01130 cmdStr += ip; 01131 cmdStr += "\""; 01132 return (at_send_wnc_cmd(cmdStr.c_str(), &pRespStr, WNC_PING_CMD_TIMEOUT_MS) == WNC_AT_CMD_OK); 01133 } 01134 01135 bool WncController::at_gettimedate_wnc(struct WncDateTime * tod) 01136 { 01137 string * pRespStr; 01138 char * pEnd; 01139 01140 if (at_send_wnc_cmd("AT+CCLK?", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01141 if (pRespStr->size() > 0) { 01142 size_t pos1 = pRespStr->find("+CCLK:"); 01143 if (pos1 != string::npos) { 01144 pEnd = (char *)pRespStr->c_str() + pos1 + 8; 01145 tod->year = strtol(pEnd, &pEnd, 10); 01146 tod->month = strtol(pEnd+1, &pEnd, 10); 01147 tod->day = strtol(pEnd+1, &pEnd, 10); 01148 tod->hour = strtol(pEnd+1, &pEnd, 10); 01149 tod->min = strtol(pEnd+1, &pEnd, 10); 01150 tod->sec = strtol(pEnd+1, &pEnd, 10); 01151 return (true); 01152 } 01153 } 01154 } 01155 01156 return (false); 01157 } 01158 01159 bool WncController::at_get_wnc_net_stats(WncIpStats * s) 01160 { 01161 string * pRespStr; 01162 AtCmdErr_e cmdRes = at_send_wnc_cmd("AT+CGCONTRDP=1", &pRespStr, m_sCmdTimeoutMs); 01163 01164 if (WNC_AT_CMD_OK == cmdRes) { 01165 if (pRespStr->size() > 0) { 01166 memset((void*)s, '\0', sizeof(*s)); // Clean-up 01167 string ss; 01168 size_t pe; 01169 size_t ps = pRespStr->rfind("\""); 01170 if (ps != string::npos) { 01171 ps += 2; // Skip the , after the " 01172 pe = ps; 01173 01174 pe = pRespStr->find(".", pe); 01175 if (pe == string::npos) 01176 return (false); 01177 else 01178 pe += 1; 01179 pe = pRespStr->find(".", pe); 01180 if (pe == string::npos) 01181 return (false); 01182 else 01183 pe += 1; 01184 pe = pRespStr->find(".", pe); 01185 if (pe == string::npos) 01186 return (false); 01187 else 01188 pe += 1; 01189 pe = pRespStr->find(".", pe); 01190 if (pe == string::npos) 01191 return (false); 01192 else 01193 pe += 1; 01194 01195 ss = pRespStr->substr(ps, pe - 1 - ps); 01196 strncpy(s->ip, ss.c_str(), MAX_LEN_IP_STR); 01197 s->ip[MAX_LEN_IP_STR - 1] = '\0'; 01198 ps = pe; 01199 01200 pe = pRespStr->find(".", pe); 01201 if (pe == string::npos) 01202 return (false); 01203 else 01204 pe += 1; 01205 pe = pRespStr->find(".", pe); 01206 if (pe == string::npos) 01207 return (false); 01208 else 01209 pe += 1; 01210 pe = pRespStr->find(".", pe); 01211 if (pe == string::npos) 01212 return (false); 01213 else 01214 pe += 1; 01215 pe = pRespStr->find(",", pe); 01216 01217 ss = pRespStr->substr(ps, pe - ps); 01218 strncpy(s->mask, ss.c_str(), MAX_LEN_IP_STR); 01219 s->mask[MAX_LEN_IP_STR - 1] = '\0'; 01220 ps = pe + 1; 01221 01222 pe = pRespStr->find(".", pe); 01223 if (pe == string::npos) 01224 return (false); 01225 else 01226 pe += 1; 01227 pe = pRespStr->find(".", pe); 01228 if (pe == string::npos) 01229 return (false); 01230 else 01231 pe += 1; 01232 pe = pRespStr->find(".", pe); 01233 if (pe == string::npos) 01234 return (false); 01235 else 01236 pe += 1; 01237 pe = pRespStr->find(",", pe); 01238 01239 ss = pRespStr->substr(ps, pe - ps); 01240 strncpy(s->gateway, ss.c_str(), MAX_LEN_IP_STR); 01241 s->gateway[MAX_LEN_IP_STR - 1] = '\0'; 01242 ps = pe + 1; 01243 01244 pe = pRespStr->find(".", pe); 01245 if (pe == string::npos) 01246 return (false); 01247 else 01248 pe += 1; 01249 pe = pRespStr->find(".", pe); 01250 if (pe == string::npos) 01251 return (false); 01252 else 01253 pe += 1; 01254 pe = pRespStr->find(".", pe); 01255 if (pe == string::npos) 01256 return (false); 01257 else 01258 pe += 1; 01259 pe = pRespStr->find(",", pe); 01260 01261 01262 ss = pRespStr->substr(ps, pe - ps); 01263 strncpy(s->dnsPrimary, ss.c_str(), MAX_LEN_IP_STR); 01264 s->dnsPrimary[MAX_LEN_IP_STR - 1] = '\0'; 01265 ps = pe + 1; 01266 01267 pe = pRespStr->find(".", pe); 01268 if (pe == string::npos) 01269 return (false); 01270 else 01271 pe += 1; 01272 pe = pRespStr->find(".", pe); 01273 if (pe == string::npos) 01274 return (false); 01275 else 01276 pe += 1; 01277 pe = pRespStr->find(".", pe); 01278 if (pe == string::npos) 01279 return (false); 01280 else 01281 pe += 1; 01282 pe = pRespStr->find(",", pe); 01283 01284 01285 ss = pRespStr->substr(ps, pe - ps); 01286 strncpy(s->dnsSecondary, ss.c_str(), MAX_LEN_IP_STR); 01287 s->dnsSecondary[MAX_LEN_IP_STR - 1] = '\0'; 01288 01289 dbgPuts("~~~~~~~~~~ WNC IP Stats ~~~~~~~~~~~~"); 01290 dbgPuts("ip: ", false); dbgPutsNoTime(s->ip); 01291 dbgPuts("mask: ", false); dbgPutsNoTime(s->mask); 01292 dbgPuts("gateway: ", false); dbgPutsNoTime(s->gateway); 01293 dbgPuts("dns pri: ", false); dbgPutsNoTime(s->dnsPrimary); 01294 dbgPuts("dns sec: ", false); dbgPutsNoTime(s->dnsSecondary); 01295 dbgPuts("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 01296 01297 return (true); 01298 } 01299 } 01300 } 01301 01302 return (false); 01303 } 01304 01305 bool WncController::deleteSMSTextFromMem(char msgIdx) 01306 { 01307 const char * err = "deleteSMSTextFromMem: Failed!"; 01308 01309 switch (msgIdx) 01310 { 01311 case '*': 01312 at_deleteSMSTextFromMem_wnc('1'); 01313 at_deleteSMSTextFromMem_wnc('2'); 01314 at_deleteSMSTextFromMem_wnc('3'); 01315 return (true); // WNC may error if slot empty, just ignore! 01316 01317 case '1': 01318 case '2': 01319 case '3': 01320 if (true == at_deleteSMSTextFromMem_wnc(msgIdx)) 01321 return (true); 01322 else { 01323 dbgPuts(err); 01324 return (false); 01325 } 01326 01327 default: 01328 dbgPuts(err); 01329 return (false); 01330 } 01331 } 01332 01333 bool WncController::sendSMSTextFromMem(char msgIdx) 01334 { 01335 const char * err = "deleteSMSTextFromMem: Failed!"; 01336 01337 switch (msgIdx) 01338 { 01339 case '*': 01340 at_sendSMStextMem_wnc('1'); 01341 at_sendSMStextMem_wnc('2'); 01342 at_sendSMStextMem_wnc('3'); 01343 return (true); // WNC may error if slot is empty, just ignore! 01344 01345 case '1': 01346 case '2': 01347 case '3': 01348 if (at_sendSMStextMem_wnc(msgIdx) == true) 01349 return (true); 01350 else { 01351 dbgPuts(err); 01352 return (false); 01353 } 01354 01355 default: 01356 dbgPuts(err); 01357 return (false); 01358 } 01359 } 01360 01361 bool WncController::at_deleteSMSTextFromMem_wnc(char n) 01362 { 01363 string cmdStr, respStr; 01364 // Message is stored in WNC, now send it! 01365 cmdStr = "AT+CMGD="; 01366 cmdStr += n; 01367 cmdStr += "\r\n"; 01368 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); 01369 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); 01370 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01371 return (r == WNC_AT_CMD_OK); 01372 } 01373 01374 bool WncController::at_sendSMStextMem_wnc(char n) 01375 { 01376 string cmdStr, respStr; 01377 // Message is stored in WNC, now send it! 01378 cmdStr = "AT+CMSS="; 01379 cmdStr += n; 01380 cmdStr += "\r\n"; 01381 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); 01382 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); 01383 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01384 return (r == WNC_AT_CMD_OK); 01385 } 01386 01387 bool WncController::at_sendSMStext_wnc(const char * const phoneNum, const char * const text) 01388 { 01389 string respStr; 01390 string * pRespStr; 01391 size_t l = strlen(text); 01392 01393 if (l <= MAX_WNC_SMS_LENGTH) 01394 { 01395 // Check to see if the SMS service is available 01396 checkCellLink(); 01397 if (m_sReadyForSMS == true) { 01398 at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); 01399 string cmdStr("AT+CMGS=\""); 01400 cmdStr += phoneNum; 01401 cmdStr += "\""; 01402 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 01403 cmdStr += "\x0d"; // x0d = <ENTER> 01404 // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! 01405 // And we want a delay before sending the actual text part of the string! 01406 mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) 01407 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01408 if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { 01409 // Part 2 of the text, this is the actual text part: 01410 cmdStr = text; 01411 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 01412 cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to send! 01413 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); 01414 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01415 if (respStr.size() == 0) 01416 return (false); 01417 else 01418 return (r == WNC_AT_CMD_OK); 01419 } 01420 } 01421 } 01422 01423 return (false); 01424 } 01425 01426 bool WncController::saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx) 01427 { 01428 if (at_saveSMStext_wnc(phoneNum, text, msgIdx) == true) 01429 return (true); 01430 else { 01431 dbgPuts("saveSMSTextToMem: failed!\r\n"); 01432 return (false); 01433 } 01434 } 01435 01436 bool WncController::at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx) 01437 { 01438 string respStr; 01439 size_t l = strlen(text); 01440 01441 if (l <= MAX_WNC_SMS_LENGTH) 01442 { 01443 // Check to see if the SMS service is available 01444 checkCellLink(); 01445 if (m_sReadyForSMS == true) { 01446 string cmdStr("AT+CMGW=\""); 01447 cmdStr += phoneNum; 01448 cmdStr += "\""; 01449 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 01450 cmdStr += "\x0d"; // x0d = <ENTER> 01451 // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! 01452 // And we want a delay before sending the actual text part of the string! 01453 mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) 01454 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01455 if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { 01456 // Part 2 of the text, this is the actual text part: 01457 cmdStr = text; 01458 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 01459 cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to save! 01460 mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); 01461 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01462 if (respStr.size() > 0) { 01463 // respStr will have the SMS index 01464 size_t pos1 = respStr.find("+CMGW: "); 01465 size_t pos2 = respStr.rfind("OK"); 01466 if (pos1 != string::npos && pos2 != string::npos) { 01467 *msgIdx = *string(respStr.substr(pos1+7, 1)).c_str(); 01468 return (true); 01469 } 01470 else { 01471 *msgIdx = '!'; 01472 } 01473 } 01474 } 01475 } 01476 } 01477 01478 return (false); 01479 } 01480 01481 bool WncController::at_readSMSlog_wnc(string ** log) 01482 { 01483 return (at_send_wnc_cmd("AT+CMGL", log, m_sCmdTimeoutMs) == WNC_AT_CMD_OK); 01484 } 01485 01486 size_t WncController::at_readSMStext_wnc(const char n, const char ** log) 01487 { 01488 static string smsReadTxtStr; 01489 string * pRespStr; 01490 string cmdStr; 01491 01492 smsReadTxtStr.erase(); 01493 cmdStr = "AT+CMGR"; 01494 cmdStr += '1'; 01495 if (at_send_wnc_cmd("AT+CMGR", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) 01496 *log = pRespStr->c_str(); 01497 else 01498 *log = "\0"; 01499 01500 return (pRespStr->size()); 01501 } 01502 01503 bool WncController::at_at_wnc(void) 01504 { 01505 string * pRespStr; 01506 return (WNC_AT_CMD_OK == at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS)); // Heartbeat? 01507 } 01508 01509 bool WncController::at_init_wnc(bool hardReset) 01510 { 01511 string * pRespStr; 01512 AtCmdErr_e cmdRes; 01513 01514 if (hardReset == true) 01515 dbgPuts("Hard Soft Reset!"); 01516 01517 dbgPuts("Start AT init of WNC:"); 01518 01519 // Kick it twice to perhaps remove cued responses from an incomplete 01520 // power cycle. 01521 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 01522 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 01523 01524 // Dump the firmware revision on the debug log: 01525 at_send_wnc_cmd("AT+GMR", &pRespStr, m_sCmdTimeoutMs); 01526 01527 // Quick commands below do not need to check cellular connectivity 01528 at_send_wnc_cmd("ATE0", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Echo Off 01529 at_send_wnc_cmd("AT+CMEE=2", &pRespStr, m_sCmdTimeoutMs); // 2 - verbose error, 1 - numeric error, 0 - just ERROR 01530 01531 // Setup 3 memory slots in the WNC SIM for SMS usage. 01532 at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); 01533 at_send_wnc_cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", &pRespStr, m_sCmdTimeoutMs); 01534 01535 cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Heartbeat? 01536 01537 // If the simple commands are not working, no chance of more complex. 01538 // I have seen re-trying commands make it worse. 01539 if (cmdRes != WNC_AT_CMD_OK) 01540 return (false); 01541 01542 // Disable unsolicited RRCSTATE responses. These are supposed to be off 01543 // by default but have been found to be active. 01544 // This problem introduced in: NQ_MPSS_IMA3_v10.58.174043 LTE-M firmware 01545 cmdRes = at_send_wnc_cmd("AT%NOTIFYEV=\"ALL\",0", &pRespStr, m_sCmdTimeoutMs); 01546 if (cmdRes != WNC_AT_CMD_OK) 01547 return (false); 01548 01549 cmdRes = at_send_wnc_cmd("AT@INTERNET=1", &pRespStr, m_sCmdTimeoutMs); 01550 if (cmdRes != WNC_AT_CMD_OK) 01551 return (false); 01552 01553 cmdRes = at_send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, m_sCmdTimeoutMs); 01554 if (cmdRes != WNC_AT_CMD_OK) 01555 return (false); 01556 01557 dbgPuts("SUCCESS: AT init of WNC!"); 01558 01559 return (true); 01560 } 01561 01562 int16_t WncController::at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec) 01563 { 01564 string * pRespStr; 01565 string cmd_str("AT@SOCKCREAT="); 01566 AtCmdErr_e res; 01567 01568 if (tcp) cmd_str += "1"; // TCP 01569 else cmd_str += "2"; // else UDP 01570 01571 cmd_str += ",0"; 01572 res = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01573 if (res == WNC_AT_CMD_OK && pRespStr->size() > 0) 01574 { 01575 size_t pos1 = pRespStr->find("T:"); 01576 size_t pos2 = pRespStr->rfind("OK"); 01577 if ((pos1 != string::npos) && (pos2 != string::npos)) { 01578 size_t numLen = pos2 - (pos1 + 2); 01579 string sockStr = pRespStr->substr(pos1 + 2, numLen); 01580 cmd_str = "AT@SOCKCONN="; 01581 cmd_str += sockStr; 01582 cmd_str += ",\""; 01583 cmd_str += ip; 01584 cmd_str += "\","; 01585 cmd_str += _to_string(port); 01586 cmd_str += ","; 01587 if (timeOutSec < 30) 01588 timeOutSec = 30; 01589 else if (timeOutSec > 360) 01590 timeOutSec = 360; 01591 cmd_str += _to_string(timeOutSec); 01592 res = sendWncCmd(cmd_str.c_str(), &pRespStr, 1000 * timeOutSec + 1000); 01593 if (m_sMoreDebugEnabled) { 01594 at_send_wnc_cmd("AT@SOCKCREAT?", &pRespStr, m_sCmdTimeoutMs); 01595 at_send_wnc_cmd("AT@SOCKCONN?", &pRespStr, m_sCmdTimeoutMs); 01596 } 01597 return (strtol(sockStr.c_str(), NULL, 10)); 01598 } 01599 else { 01600 dbgPuts("Invalid sockcreat response!"); 01601 return (0); 01602 } 01603 } 01604 else 01605 return (0); 01606 } 01607 01608 bool WncController::at_sockclose_wnc(uint16_t numSock) 01609 { 01610 string * pRespStr; 01611 string cmd_str("AT@SOCKCLOSE="); 01612 01613 cmd_str += _to_string(numSock); 01614 01615 // Don't check the cell status to close the socket 01616 AtCmdErr_e res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01617 01618 if ((res != WNC_AT_CMD_TIMEOUT) && (res != WNC_AT_CMD_OK)) { 01619 for (unsigned i = 0; i < WNC_SOCK_CLOSE_RETRY_CNT; i++) { 01620 res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01621 if ((res == WNC_AT_CMD_TIMEOUT) || (res == WNC_AT_CMD_OK)) 01622 break; 01623 } 01624 } 01625 01626 return (res == WNC_AT_CMD_OK); 01627 } 01628 01629 bool WncController::at_dnsresolve_wnc(const char * s, string * ipStr) 01630 { 01631 string * pRespStr; 01632 string str(s); 01633 AtCmdErr_e r; 01634 01635 ipStr->erase(); // Clear out string until resolved! 01636 str = "AT@DNSRESVDON=\"" + str; 01637 str += "\""; 01638 r = sendWncCmd(str.c_str(), &pRespStr, WNC_DNS_RESOLVE_WAIT_MS); 01639 if (r == WNC_AT_CMD_OK && pRespStr->size() > 0) { 01640 size_t pos_start = pRespStr->find("ON:\""); 01641 size_t pos_end = pRespStr->find("\"", (pos_start + 4)); 01642 if ((pos_start != string::npos) && (pos_end != string::npos)) { 01643 pos_start += 4; 01644 pos_end -= 1; 01645 01646 if (pos_end > pos_start) { 01647 // Make a copy for use later (the source string is re-used) 01648 *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1); 01649 return (true); 01650 } 01651 } 01652 } 01653 01654 *ipStr = INVALID_IP_STR; 01655 01656 return (false); 01657 } 01658 01659 bool WncController::waitForPowerOnModemToRespond(uint8_t timeoutSecs) 01660 { 01661 // Now, give the modem x seconds to start responding by 01662 // sending simple 'AT' commands to modem once per second. 01663 if (timeoutSecs > 0) { 01664 do { 01665 timeoutSecs--; 01666 dbgPutsNoTime("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 01667 dbgPutsNoTime(" ", false); 01668 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 01669 if (rc == WNC_AT_CMD_OK) { 01670 dbgPutsNoTime(""); // CR LF 01671 return true; //timer.read(); 01672 } 01673 waitMs(500); 01674 } 01675 while (timeoutSecs > 0); 01676 dbgPutsNoTime(""); // CR LF 01677 } 01678 01679 return (false); 01680 } 01681 01682 WncController::AtCmdErr_e WncController::at_sockwrite_wnc(const uint8_t * s, uint16_t n, uint16_t numSock, bool isTcp) 01683 { 01684 AtCmdErr_e result; 01685 01686 if ((n > 0) && (n <= MAX_WNC_WRITE_BYTES)) { 01687 string * pRespStr; 01688 const char * num2str; 01689 string cmd_str; 01690 01691 if (isTcp == true) 01692 cmd_str="AT@SOCKWRITE="; 01693 else 01694 cmd_str="AT@SOCKWRITE="; // "AT@SOCKSEND="; 01695 01696 cmd_str += _to_string(numSock); 01697 cmd_str += ","; 01698 cmd_str += _to_string(n); 01699 cmd_str += ",\""; 01700 while(n > 0) { 01701 n--; 01702 num2str = _to_hex_string(*s++); 01703 // Always 2-digit ascii hex: 01704 if (num2str[1] == '\0') 01705 cmd_str += '0'; 01706 cmd_str += num2str; 01707 } 01708 cmd_str += "\""; 01709 result = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01710 } 01711 else { 01712 dbgPuts("sockwrite Err, string len bad!"); 01713 result = WNC_AT_CMD_ERR; 01714 } 01715 01716 return (result); 01717 } 01718 01719 WncController::AtCmdErr_e WncController::at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp) 01720 { 01721 AtCmdErr_e result = WNC_AT_CMD_OK; 01722 01723 string * pRespStr; 01724 string cmd_str; 01725 size_t pos_start=0, pos_end=0; 01726 int i; 01727 01728 pS->erase(); // Start with a fresh string 01729 01730 if (isTcp == true) 01731 cmd_str="AT@SOCKREAD="; 01732 else 01733 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 01734 01735 cmd_str += _to_string(numSock); 01736 cmd_str += ","; 01737 cmd_str += _to_string(MAX_WNC_READ_BYTES); 01738 01739 // Experimental: read should not need to check cell net status 01740 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01741 if (result == WNC_AT_CMD_OK) { 01742 if (pRespStr->size() > 0) { 01743 pos_start = pRespStr->find("\""); 01744 pos_end = pRespStr->rfind("\""); 01745 // Make sure search finds what it's looking for! 01746 if (pos_start != string::npos && pos_end != string::npos) { 01747 pos_start++; 01748 i = pos_end - pos_start; // Num hex chars, 2 per byte 01749 } 01750 else 01751 i = 0; 01752 } 01753 else 01754 i = 0; 01755 01756 if ((i < 0) || ((i % 2) == 1)) 01757 dbgPuts("Invalid READ string!"); 01758 01759 if (i > 2*MAX_WNC_READ_BYTES) { 01760 i = 2*MAX_WNC_READ_BYTES; 01761 dbgPuts("DANGER WNC read data does not match length!"); 01762 } 01763 01764 // If data, convert the hex string into byte values 01765 while (i > 0) { 01766 i -= 2; 01767 *pS += (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 01768 pos_start += 2; 01769 } 01770 } 01771 01772 return (result); 01773 } 01774 01775 WncController::AtCmdErr_e WncController::at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp) 01776 { 01777 AtCmdErr_e result = WNC_AT_CMD_OK; 01778 *numRead = 0; 01779 01780 if ((n > 0) && (n <= MAX_WNC_READ_BYTES)) { 01781 string * pRespStr; 01782 string cmd_str; 01783 size_t pos_start=0, pos_end=0; 01784 int i; 01785 01786 if (isTcp == true) 01787 cmd_str="AT@SOCKREAD="; 01788 else 01789 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 01790 01791 cmd_str += _to_string(numSock); 01792 cmd_str += ","; 01793 cmd_str += _to_string(n); 01794 01795 // Experimental: read should not need to check cell net status 01796 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01797 if (result == WNC_AT_CMD_OK) { 01798 if (pRespStr->size() > 0) { 01799 pos_start = pRespStr->find("\""); 01800 pos_end = pRespStr->rfind("\""); 01801 // Make sure search finds what it's looking for! 01802 if (pos_start != string::npos && pos_end != string::npos) { 01803 pos_start++; 01804 i = pos_end - pos_start; // Num hex chars, 2 per byte 01805 } 01806 else 01807 i = 0; 01808 } 01809 else 01810 i = 0; 01811 01812 if ((i < 0) || ((i % 2) == 1)) 01813 dbgPuts("Invalid READ string!"); 01814 01815 if (i > 2*n) { 01816 // Bound the ill formated WNC read string! 01817 i = 2*n; 01818 dbgPuts("TRUNCATING read data!"); 01819 } 01820 01821 // If data, convert the hex string into byte values 01822 i /= 2; 01823 *numRead = i; 01824 while (i > 0) { 01825 i--; 01826 *pS++ = (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 01827 pos_start += 2; 01828 } 01829 } 01830 } 01831 else { 01832 dbgPuts("sockread Err, to many to read!"); 01833 result = WNC_AT_CMD_ERR; 01834 } 01835 01836 return (result); 01837 } 01838 01839 bool WncController::at_reinitialize_mdm(void) 01840 { 01841 // Atempt to re-register 01842 // string * pRespStr; 01843 // dbgPuts("Force re-register!"); 01844 // at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, m_sCmdTimeoutMs); 01845 // waitMs(31000); 01846 // at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, m_sCmdTimeoutMs); 01847 // waitMs(31000); 01848 01849 // Initialize the modem 01850 dbgPuts("Modem RE-initializing with SOFT Reset..."); 01851 01852 string * pRespStr; 01853 at_send_wnc_cmd("AT@DMREBOOT", &pRespStr, m_sCmdTimeoutMs); 01854 waitMs(5000); 01855 01856 // Now, give the modem time to start responding by 01857 // sending simple 'AT' commands to the modem once per second. 01858 int timeoutSecs = WNC_REINIT_MAX_TIME_MS; 01859 do { 01860 dbgPuts("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 01861 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 01862 if (rc == WNC_AT_CMD_OK) { 01863 dbgPutsNoTime(""); // CR LF 01864 break; 01865 } 01866 waitMs(500); 01867 timeoutSecs--; 01868 } 01869 while (timeoutSecs > 0); 01870 01871 if (timeoutSecs <= 0) 01872 dbgPuts("\r\nModem RE-init FAILED!"); 01873 else 01874 dbgPuts("\r\nModem RE-init complete!"); 01875 01876 return (timeoutSecs > 0); 01877 } 01878 01879 WncController::AtCmdErr_e WncController::mdmSendAtCmdRsp(const char *cmd, int timeout_ms, string * rsp, bool crLf) 01880 { 01881 rsp->erase(); // Clean up from possible prior cmd response 01882 01883 // Don't bother the WNC if user hasn't turned it on. 01884 if (m_sState == WNC_OFF) 01885 return (WNC_AT_CMD_WNC_NOT_ON); 01886 01887 size_t n = strlen(cmd); 01888 01889 // Wait per WNC advise 01890 waitMs(WNC_WAIT_FOR_AT_CMD_MS); 01891 01892 if (cmd && n > 0) { 01893 sendCmd(cmd, crLf); 01894 // sendCmd(cmd, n, 1000, crLf); // 3rd arg is micro seconds between chars sent 01895 } 01896 01897 startTimerA(); 01898 while (getTimerTicksA_mS() < timeout_ms) { 01899 n = mdmGetline(rsp, timeout_ms - getTimerTicksA_mS()); 01900 01901 if (n == 0) 01902 continue; 01903 01904 if (rsp->rfind("OK") != string::npos) { 01905 stopTimerA(); 01906 return (WNC_AT_CMD_OK); 01907 } 01908 01909 if (rsp->rfind("+CME ERROR") != string::npos) { 01910 stopTimerA(); 01911 return (WNC_AT_CMD_ERRCME); 01912 } 01913 01914 if (rsp->rfind("@EXTERR") != string::npos) { 01915 stopTimerA(); 01916 return (WNC_AT_CMD_ERREXT); 01917 } 01918 01919 if (rsp->rfind("ERROR") != string::npos) { 01920 stopTimerA(); 01921 return (WNC_AT_CMD_ERR); 01922 } 01923 } 01924 stopTimerA(); 01925 01926 return (WNC_AT_CMD_TIMEOUT); 01927 } 01928 01929 bool WncController::at_setapn_wnc(const char * const apnStr) 01930 { 01931 string * pRespStr; 01932 01933 string cmd_str("AT%PDNSET=1,"); 01934 cmd_str += apnStr; 01935 cmd_str += ",IP"; 01936 if (WNC_AT_CMD_OK == at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_APNSET_TIMEOUT_MS)) // Set APN, cmd seems to take a little longer sometimes 01937 return (true); 01938 else 01939 return (false); 01940 } 01941 01942 bool WncController::at_getrssiber_wnc(int16_t * dBm, int16_t * ber) 01943 { 01944 string * pRespStr; 01945 AtCmdErr_e cmdRes; 01946 cmdRes = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 01947 if (cmdRes != WNC_AT_CMD_OK) 01948 return (false); 01949 01950 if (pRespStr->size() == 0) { 01951 dbgPuts("Strange RSSI result!"); 01952 return (false); 01953 } 01954 else { 01955 size_t pos1 = pRespStr->find("SQ:"); 01956 size_t pos2 = pRespStr->rfind(","); 01957 // Sanity check 01958 if ((pos1 != string::npos) && (pos2 != string::npos) && (pos2 > pos1)) { 01959 string subStr = pRespStr->substr(pos1 + 4, pos2 - pos1 ); 01960 int rawRssi = atoi(subStr.c_str()); 01961 01962 // Convert WNC RSSI into dBm range: 01963 // 0 - -113 dBm 01964 // 1 - -111 dBm 01965 // 2..30 - -109 to -53 dBm 01966 // 31 - -51dBm or > 01967 // 99 - not known or not detectable 01968 if (rawRssi == 99) 01969 *dBm = -199; 01970 else if (rawRssi == 0) 01971 *dBm = -113; 01972 else if (rawRssi == 1) 01973 *dBm = -111; 01974 else if (rawRssi == 31) 01975 *dBm = -51; 01976 else if (rawRssi >= 2 && rawRssi <= 30) 01977 *dBm = -113 + 2 * rawRssi; 01978 else { 01979 dbgPuts("Invalid RSSI!"); 01980 return (false); 01981 } 01982 // Parse out BER: 0..7 as RXQUAL values in the table 3GPP TS 45.008 subclause 8.2.4 01983 // 99 - unknown or undetectable 01984 subStr = pRespStr->substr(pos2 + 1, pRespStr->length() - (pos2 + 1)); 01985 *ber = atoi(subStr.c_str()); 01986 } 01987 else { 01988 dbgPuts("Strange RSSI result2!"); 01989 return (false); 01990 } 01991 } 01992 01993 return (true); 01994 } 01995 01996 bool WncController::checkCellLink(void) 01997 { 01998 string * pRespStr; 01999 size_t pos; 02000 int regSts; 02001 int cmdRes1, cmdRes2; 02002 02003 if (m_sState == WNC_OFF) 02004 return (false); 02005 02006 m_sState = WNC_ON_NO_CELL_LINK; 02007 02008 if (m_sMoreDebugEnabled) 02009 dbgPuts("<-------- Begin Cell Status ------------"); 02010 02011 cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 02012 02013 // If no response, don't bother with more commands 02014 if (cmdRes1 != WNC_AT_CMD_TIMEOUT) 02015 cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, m_sCmdTimeoutMs); // Check if SIM locked 02016 else { 02017 if (m_sMoreDebugEnabled) 02018 dbgPuts("------------ WNC No Response! --------->"); 02019 02020 return (false); 02021 } 02022 02023 if ((cmdRes1 != WNC_AT_CMD_OK) || (cmdRes2 != WNC_AT_CMD_OK) || (pRespStr->size() == 0)) 02024 { 02025 if (m_sMoreDebugEnabled) 02026 { 02027 if ((cmdRes1 == WNC_AT_CMD_TIMEOUT) || (cmdRes2 == WNC_AT_CMD_TIMEOUT)) 02028 dbgPuts("------------ WNC No Response! --------->"); 02029 else 02030 dbgPuts("------------ WNC Cmd Error! ----------->"); 02031 } 02032 02033 // If by a miracle it responds to the 2nd after the 1st, keep going 02034 if ((cmdRes2 == WNC_AT_CMD_TIMEOUT) || (pRespStr->size() == 0)) 02035 return (false); 02036 } 02037 02038 // If SIM Card not ready don't bother with commands! 02039 if (pRespStr->find("CPIN: READY") == string::npos) 02040 { 02041 if (m_sMoreDebugEnabled) 02042 dbgPuts("------------ WNC SIM Problem! --------->"); 02043 02044 return (false); 02045 } 02046 02047 // SIM card OK, now check for signal and cellular network registration 02048 cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, m_sCmdTimeoutMs); // Check if registered on network 02049 if (cmdRes1 != WNC_AT_CMD_OK || pRespStr->size() == 0) 02050 { 02051 if (m_sMoreDebugEnabled) 02052 dbgPuts("------------ WNC +CREG? Fail! --------->"); 02053 02054 return (false); 02055 } 02056 else 02057 { 02058 pos = pRespStr->find("CREG: "); 02059 if (pos != string::npos) 02060 { 02061 // The registration is the 2nd arg in the comma separated list 02062 *pRespStr = pRespStr->substr(pos+8, 1); 02063 regSts = atoi(pRespStr->c_str()); 02064 switch (regSts) { 02065 case 1: 02066 case 5: 02067 case 6: 02068 case 7: 02069 m_sReadyForSMS = true; 02070 break; 02071 default: 02072 m_sReadyForSMS = false; 02073 dbgPuts("SMS Service Down!"); 02074 } 02075 02076 // 1 - registered home, 5 - registered roaming 02077 if ((regSts != 1) && (regSts != 5)) 02078 { 02079 if (m_sMoreDebugEnabled) 02080 dbgPuts("------ WNC Cell Link Down for Data! --->"); 02081 02082 return (false); 02083 } 02084 } 02085 02086 if (m_sMoreDebugEnabled) 02087 dbgPuts("------------ WNC Ready ---------------->"); 02088 } 02089 02090 // If we made it this far and the WNC did respond, keep the ON state 02091 if (m_sState != WNC_NO_RESPONSE) 02092 m_sState = WNC_ON; 02093 02094 return (true); 02095 } 02096 02097 int WncController::dbgPutsNoTime(const char * s, bool crlf) 02098 { 02099 if (m_sDebugEnabled == true) { 02100 int r = dbgWriteChars(s); 02101 if (crlf == true) 02102 return (dbgWriteChars("\r\n")); 02103 else 02104 return (r); 02105 } 02106 else 02107 return 0; 02108 }; 02109 02110 int WncController::dbgPuts(const char * s, bool crlf) 02111 { 02112 dbgPutsNoTime("[*] ", false); 02113 dbgPutsNoTime(_to_string(getLogTimerTicks()), false); 02114 dbgPutsNoTime(" ", false); 02115 02116 int r = dbgPutsNoTime(s, false); 02117 02118 if (crlf == true) 02119 return (dbgPutsNoTime("", true)); 02120 else 02121 return (r); 02122 }; 02123 02124 void WncController::sendCmd(const char * cmd, bool crLf) 02125 { 02126 puts(cmd); 02127 if (crLf == true) 02128 puts("\r\n"); 02129 } 02130 02131 void WncController::sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf) 02132 { 02133 while (n--) { 02134 putc(*cmd++); 02135 waitUs(wait_uS); 02136 }; 02137 if (crLf == true) { 02138 putc('\r'); 02139 waitUs(wait_uS); 02140 putc('\n'); 02141 waitUs(wait_uS); 02142 } 02143 } 02144 02145 }; // End namespace WncController_fk 02146
Generated on Sat Jul 16 2022 16:26:31 by
1.7.2