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