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