I added functionality to get the RSSI, BER, and Cell Neighbor for reporting connection issues to M2X
Embed:
(wiki syntax)
Show/hide line numbers
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 string * WncController::at_readCellNeighbor_wnc() 01477 { 01478 string * pRespStr; 01479 at_send_wnc_cmd("$QCRSRP?", &pRespStr, m_sCmdTimeoutMs); 01480 return pRespStr; 01481 } 01482 01483 size_t WncController::at_readSMStext_wnc(const char n, const char ** log) 01484 { 01485 static string smsReadTxtStr; 01486 string * pRespStr; 01487 string cmdStr; 01488 01489 smsReadTxtStr.erase(); 01490 cmdStr = "AT+CMGR"; 01491 cmdStr += '1'; 01492 if (at_send_wnc_cmd("AT+CMGR", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) 01493 *log = pRespStr->c_str(); 01494 else 01495 *log = "\0"; 01496 01497 return (pRespStr->size()); 01498 } 01499 01500 bool WncController::at_at_wnc(void) 01501 { 01502 string * pRespStr; 01503 return (WNC_AT_CMD_OK == at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS)); // Heartbeat? 01504 } 01505 01506 bool WncController::at_init_wnc(bool hardReset) 01507 { 01508 string * pRespStr; 01509 AtCmdErr_e cmdRes; 01510 01511 if (hardReset == true) 01512 dbgPuts("Hard Soft Reset!"); 01513 01514 dbgPuts("Start AT init of WNC:"); 01515 01516 // Kick it twice to perhaps remove cued responses from an incomplete 01517 // power cycle. 01518 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 01519 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 01520 01521 // Dump the firmware revision on the debug log: 01522 at_send_wnc_cmd("AT+GMR", &pRespStr, m_sCmdTimeoutMs); 01523 01524 // Quick commands below do not need to check cellular connectivity 01525 at_send_wnc_cmd("ATE0", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Echo Off 01526 at_send_wnc_cmd("AT+CMEE=2", &pRespStr, m_sCmdTimeoutMs); // 2 - verbose error, 1 - numeric error, 0 - just ERROR 01527 01528 // Setup 3 memory slots in the WNC SIM for SMS usage. 01529 at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); 01530 at_send_wnc_cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", &pRespStr, m_sCmdTimeoutMs); 01531 01532 cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Heartbeat? 01533 01534 // If the simple commands are not working, no chance of more complex. 01535 // I have seen re-trying commands make it worse. 01536 if (cmdRes != WNC_AT_CMD_OK) 01537 return (false); 01538 01539 cmdRes = at_send_wnc_cmd("AT@INTERNET=1", &pRespStr, m_sCmdTimeoutMs); 01540 if (cmdRes != WNC_AT_CMD_OK) 01541 return (false); 01542 01543 cmdRes = at_send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, m_sCmdTimeoutMs); 01544 if (cmdRes != WNC_AT_CMD_OK) 01545 return (false); 01546 01547 dbgPuts("SUCCESS: AT init of WNC!"); 01548 01549 return (true); 01550 } 01551 01552 int16_t WncController::at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec) 01553 { 01554 string * pRespStr; 01555 string cmd_str("AT@SOCKCREAT="); 01556 AtCmdErr_e res; 01557 01558 if (tcp) cmd_str += "1"; // TCP 01559 else cmd_str += "2"; // else UDP 01560 01561 cmd_str += ",0"; 01562 res = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01563 if (res == WNC_AT_CMD_OK && pRespStr->size() > 0) 01564 { 01565 size_t pos1 = pRespStr->find("T:"); 01566 size_t pos2 = pRespStr->rfind("OK"); 01567 if ((pos1 != string::npos) && (pos2 != string::npos)) { 01568 size_t numLen = pos2 - (pos1 + 2); 01569 string sockStr = pRespStr->substr(pos1 + 2, numLen); 01570 cmd_str = "AT@SOCKCONN="; 01571 cmd_str += sockStr; 01572 cmd_str += ",\""; 01573 cmd_str += ip; 01574 cmd_str += "\","; 01575 cmd_str += _to_string(port); 01576 cmd_str += ","; 01577 if (timeOutSec < 30) 01578 timeOutSec = 30; 01579 else if (timeOutSec > 360) 01580 timeOutSec = 360; 01581 cmd_str += _to_string(timeOutSec); 01582 res = sendWncCmd(cmd_str.c_str(), &pRespStr, 1000 * timeOutSec + 1000); 01583 if (m_sMoreDebugEnabled) { 01584 at_send_wnc_cmd("AT@SOCKCREAT?", &pRespStr, m_sCmdTimeoutMs); 01585 at_send_wnc_cmd("AT@SOCKCONN?", &pRespStr, m_sCmdTimeoutMs); 01586 } 01587 return (strtol(sockStr.c_str(), NULL, 10)); 01588 } 01589 else { 01590 dbgPuts("Invalid sockcreat response!"); 01591 return (0); 01592 } 01593 } 01594 else 01595 return (0); 01596 } 01597 01598 bool WncController::at_sockclose_wnc(uint16_t numSock) 01599 { 01600 string * pRespStr; 01601 string cmd_str("AT@SOCKCLOSE="); 01602 01603 cmd_str += _to_string(numSock); 01604 01605 // Don't check the cell status to close the socket 01606 AtCmdErr_e res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01607 01608 if ((res != WNC_AT_CMD_TIMEOUT) && (res != WNC_AT_CMD_OK)) { 01609 for (unsigned i = 0; i < WNC_SOCK_CLOSE_RETRY_CNT; i++) { 01610 res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01611 if ((res == WNC_AT_CMD_TIMEOUT) || (res == WNC_AT_CMD_OK)) 01612 break; 01613 } 01614 } 01615 01616 return (res == WNC_AT_CMD_OK); 01617 } 01618 01619 bool WncController::at_dnsresolve_wnc(const char * s, string * ipStr) 01620 { 01621 string * pRespStr; 01622 string str(s); 01623 AtCmdErr_e r; 01624 01625 ipStr->erase(); // Clear out string until resolved! 01626 str = "AT@DNSRESVDON=\"" + str; 01627 str += "\""; 01628 r = sendWncCmd(str.c_str(), &pRespStr, WNC_DNS_RESOLVE_WAIT_MS); 01629 if (r == WNC_AT_CMD_OK && pRespStr->size() > 0) { 01630 size_t pos_start = pRespStr->find(":\"") + 2; 01631 if (pos_start != string::npos) { 01632 size_t pos_end = pRespStr->find("\"", pos_start) - 1; 01633 if (pos_end != string::npos) { 01634 if (pos_end > pos_start) { 01635 // Make a copy for use later (the source string is re-used) 01636 *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1); 01637 return (true); 01638 } 01639 } 01640 } 01641 } 01642 01643 *ipStr = INVALID_IP_STR; 01644 01645 return (false); 01646 } 01647 01648 bool WncController::waitForPowerOnModemToRespond(uint8_t timeoutSecs) 01649 { 01650 // Now, give the modem x seconds to start responding by 01651 // sending simple 'AT' commands to modem once per second. 01652 if (timeoutSecs > 0) { 01653 do { 01654 timeoutSecs--; 01655 dbgPutsNoTime("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 01656 dbgPutsNoTime(" ", false); 01657 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 01658 if (rc == WNC_AT_CMD_OK) { 01659 dbgPutsNoTime(""); // CR LF 01660 return true; //timer.read(); 01661 } 01662 waitMs(500); 01663 } 01664 while (timeoutSecs > 0); 01665 dbgPutsNoTime(""); // CR LF 01666 } 01667 01668 return (false); 01669 } 01670 01671 WncController::AtCmdErr_e WncController::at_sockwrite_wnc(const uint8_t * s, uint16_t n, uint16_t numSock, bool isTcp) 01672 { 01673 AtCmdErr_e result; 01674 01675 if ((n > 0) && (n <= MAX_WNC_WRITE_BYTES)) { 01676 string * pRespStr; 01677 const char * num2str; 01678 string cmd_str; 01679 01680 if (isTcp == true) 01681 cmd_str="AT@SOCKWRITE="; 01682 else 01683 cmd_str="AT@SOCKWRITE="; // "AT@SOCKSEND="; 01684 01685 cmd_str += _to_string(numSock); 01686 cmd_str += ","; 01687 cmd_str += _to_string(n); 01688 cmd_str += ",\""; 01689 while(n > 0) { 01690 n--; 01691 num2str = _to_hex_string(*s++); 01692 // Always 2-digit ascii hex: 01693 if (num2str[1] == '\0') 01694 cmd_str += '0'; 01695 cmd_str += num2str; 01696 } 01697 cmd_str += "\""; 01698 result = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01699 } 01700 else { 01701 dbgPuts("sockwrite Err, string len bad!"); 01702 result = WNC_AT_CMD_ERR; 01703 } 01704 01705 return (result); 01706 } 01707 01708 WncController::AtCmdErr_e WncController::at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp) 01709 { 01710 AtCmdErr_e result = WNC_AT_CMD_OK; 01711 01712 string * pRespStr; 01713 string cmd_str; 01714 size_t pos_start, pos_end; 01715 int i; 01716 01717 pS->erase(); // Start with a fresh string 01718 01719 if (isTcp == true) 01720 cmd_str="AT@SOCKREAD="; 01721 else 01722 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 01723 01724 cmd_str += _to_string(numSock); 01725 cmd_str += ","; 01726 cmd_str += _to_string(MAX_WNC_READ_BYTES); 01727 01728 // Experimental: read should not need to check cell net status 01729 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01730 if (result == WNC_AT_CMD_OK) { 01731 if (pRespStr->size() > 0) { 01732 pos_start = pRespStr->find("\""); 01733 pos_end = pRespStr->rfind("\""); 01734 // Make sure search finds what it's looking for! 01735 if (pos_start != string::npos && pos_end != string::npos) { 01736 pos_start++; 01737 i = pos_end - pos_start; // Num hex chars, 2 per byte 01738 } 01739 else 01740 i = 0; 01741 } 01742 else 01743 i = 0; 01744 01745 if ((i < 0) || ((i % 2) == 1)) 01746 dbgPuts("Invalid READ string!"); 01747 01748 if (i > 2*MAX_WNC_READ_BYTES) { 01749 i = 2*MAX_WNC_READ_BYTES; 01750 dbgPuts("DANGER WNC read data does not match length!"); 01751 } 01752 01753 // If data, convert the hex string into byte values 01754 while (i > 0) { 01755 i -= 2; 01756 *pS += (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 01757 pos_start += 2; 01758 } 01759 } 01760 01761 return (result); 01762 } 01763 01764 WncController::AtCmdErr_e WncController::at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp) 01765 { 01766 AtCmdErr_e result = WNC_AT_CMD_OK; 01767 *numRead = 0; 01768 01769 if ((n > 0) && (n <= MAX_WNC_READ_BYTES)) { 01770 string * pRespStr; 01771 string cmd_str; 01772 size_t pos_start, pos_end; 01773 int i; 01774 01775 if (isTcp == true) 01776 cmd_str="AT@SOCKREAD="; 01777 else 01778 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 01779 01780 cmd_str += _to_string(numSock); 01781 cmd_str += ","; 01782 cmd_str += _to_string(n); 01783 01784 // Experimental: read should not need to check cell net status 01785 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 01786 if (result == WNC_AT_CMD_OK) { 01787 if (pRespStr->size() > 0) { 01788 pos_start = pRespStr->find("\""); 01789 pos_end = pRespStr->rfind("\""); 01790 // Make sure search finds what it's looking for! 01791 if (pos_start != string::npos && pos_end != string::npos) { 01792 pos_start++; 01793 i = pos_end - pos_start; // Num hex chars, 2 per byte 01794 } 01795 else 01796 i = 0; 01797 } 01798 else 01799 i = 0; 01800 01801 if ((i < 0) || ((i % 2) == 1)) 01802 dbgPuts("Invalid READ string!"); 01803 01804 if (i > 2*n) { 01805 // Bound the ill formated WNC read string! 01806 i = 2*n; 01807 dbgPuts("TRUNCATING read data!"); 01808 } 01809 01810 // If data, convert the hex string into byte values 01811 i /= 2; 01812 *numRead = i; 01813 while (i > 0) { 01814 i--; 01815 *pS++ = (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 01816 pos_start += 2; 01817 } 01818 } 01819 } 01820 else { 01821 dbgPuts("sockread Err, to many to read!"); 01822 result = WNC_AT_CMD_ERR; 01823 } 01824 01825 return (result); 01826 } 01827 01828 bool WncController::at_reinitialize_mdm(void) 01829 { 01830 // Atempt to re-register 01831 // string * pRespStr; 01832 // dbgPuts("Force re-register!"); 01833 // at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, m_sCmdTimeoutMs); 01834 // waitMs(31000); 01835 // at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, m_sCmdTimeoutMs); 01836 // waitMs(31000); 01837 01838 // Initialize the modem 01839 dbgPuts("Modem RE-initializing with SOFT Reset..."); 01840 01841 string * pRespStr; 01842 at_send_wnc_cmd("AT@DMREBOOT", &pRespStr, m_sCmdTimeoutMs); 01843 waitMs(5000); 01844 01845 // Now, give the modem time to start responding by 01846 // sending simple 'AT' commands to the modem once per second. 01847 int timeoutSecs = WNC_REINIT_MAX_TIME_MS; 01848 do { 01849 dbgPuts("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 01850 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 01851 if (rc == WNC_AT_CMD_OK) { 01852 dbgPutsNoTime(""); // CR LF 01853 break; 01854 } 01855 waitMs(500); 01856 timeoutSecs--; 01857 } 01858 while (timeoutSecs > 0); 01859 01860 if (timeoutSecs <= 0) 01861 dbgPuts("\r\nModem RE-init FAILED!"); 01862 else 01863 dbgPuts("\r\nModem RE-init complete!"); 01864 01865 return (timeoutSecs > 0); 01866 } 01867 01868 WncController::AtCmdErr_e WncController::mdmSendAtCmdRsp(const char *cmd, int timeout_ms, string * rsp, bool crLf) 01869 { 01870 rsp->erase(); // Clean up from possible prior cmd response 01871 01872 // Don't bother the WNC if user hasn't turned it on. 01873 if (m_sState == WNC_OFF) 01874 return (WNC_AT_CMD_WNC_NOT_ON); 01875 01876 size_t n = strlen(cmd); 01877 01878 // Wait per WNC advise 01879 waitMs(WNC_WAIT_FOR_AT_CMD_MS); 01880 01881 if (cmd && n > 0) { 01882 sendCmd(cmd, crLf); 01883 // sendCmd(cmd, n, 1000, crLf); // 3rd arg is micro seconds between chars sent 01884 } 01885 01886 startTimerA(); 01887 while (getTimerTicksA_mS() < timeout_ms) { 01888 n = mdmGetline(rsp, timeout_ms - getTimerTicksA_mS()); 01889 01890 if (n == 0) 01891 continue; 01892 01893 if (rsp->rfind("OK") != string::npos) { 01894 stopTimerA(); 01895 return (WNC_AT_CMD_OK); 01896 } 01897 01898 if (rsp->rfind("+CME ERROR") != string::npos) { 01899 stopTimerA(); 01900 return (WNC_AT_CMD_ERRCME); 01901 } 01902 01903 if (rsp->rfind("@EXTERR") != string::npos) { 01904 stopTimerA(); 01905 return (WNC_AT_CMD_ERREXT); 01906 } 01907 01908 if (rsp->rfind("ERROR") != string::npos) { 01909 stopTimerA(); 01910 return (WNC_AT_CMD_ERR); 01911 } 01912 } 01913 stopTimerA(); 01914 01915 return (WNC_AT_CMD_TIMEOUT); 01916 } 01917 01918 bool WncController::at_setapn_wnc(const char * const apnStr) 01919 { 01920 string * pRespStr; 01921 01922 string cmd_str("AT%PDNSET=1,"); 01923 cmd_str += apnStr; 01924 cmd_str += ",IP"; 01925 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 01926 return (true); 01927 else 01928 return (false); 01929 } 01930 01931 bool WncController::at_getrssiber_wnc(int16_t * dBm, int16_t * ber) 01932 { 01933 string * pRespStr; 01934 AtCmdErr_e cmdRes; 01935 cmdRes = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 01936 if (cmdRes != WNC_AT_CMD_OK) 01937 return (false); 01938 01939 if (pRespStr->size() == 0) { 01940 dbgPuts("Strange RSSI result!"); 01941 return (false); 01942 } 01943 else { 01944 size_t pos1 = pRespStr->find("SQ:"); 01945 size_t pos2 = pRespStr->rfind(","); 01946 // Sanity check 01947 if ((pos1 != string::npos) && (pos2 != string::npos) && (pos2 > pos1)) { 01948 string subStr = pRespStr->substr(pos1 + 4, pos2 - pos1 ); 01949 int rawRssi = atoi(subStr.c_str()); 01950 01951 // Convert WNC RSSI into dBm range: 01952 // 0 - -113 dBm 01953 // 1 - -111 dBm 01954 // 2..30 - -109 to -53 dBm 01955 // 31 - -51dBm or > 01956 // 99 - not known or not detectable 01957 if (rawRssi == 99) 01958 *dBm = -199; 01959 else if (rawRssi == 0) 01960 *dBm = -113; 01961 else if (rawRssi == 1) 01962 *dBm = -111; 01963 else if (rawRssi == 31) 01964 *dBm = -51; 01965 else if (rawRssi >= 2 && rawRssi <= 30) 01966 *dBm = -113 + 2 * rawRssi; 01967 else { 01968 dbgPuts("Invalid RSSI!"); 01969 return (false); 01970 } 01971 // Parse out BER: 0..7 as RXQUAL values in the table 3GPP TS 45.008 subclause 8.2.4 01972 // 99 - unknown or undetectable 01973 subStr = pRespStr->substr(pos2 + 1, pRespStr->length() - (pos2 + 1)); 01974 *ber = atoi(subStr.c_str()); 01975 } 01976 else { 01977 dbgPuts("Strange RSSI result2!"); 01978 return (false); 01979 } 01980 } 01981 01982 return (true); 01983 } 01984 01985 bool WncController::checkCellLink(void) 01986 { 01987 string * pRespStr; 01988 size_t pos; 01989 int regSts; 01990 int cmdRes1, cmdRes2; 01991 01992 if (m_sState == WNC_OFF) 01993 return (false); 01994 01995 m_sState = WNC_ON_NO_CELL_LINK; 01996 01997 if (m_sMoreDebugEnabled) 01998 dbgPuts("<-------- Begin Cell Status ------------"); 01999 02000 cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 02001 02002 // If no response, don't bother with more commands 02003 if (cmdRes1 != WNC_AT_CMD_TIMEOUT) 02004 cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, m_sCmdTimeoutMs); // Check if SIM locked 02005 else { 02006 if (m_sMoreDebugEnabled) 02007 dbgPuts("------------ WNC No Response! --------->"); 02008 02009 return (false); 02010 } 02011 02012 if ((cmdRes1 != WNC_AT_CMD_OK) || (cmdRes2 != WNC_AT_CMD_OK) || (pRespStr->size() == 0)) 02013 { 02014 if (m_sMoreDebugEnabled) 02015 { 02016 if ((cmdRes1 == WNC_AT_CMD_TIMEOUT) || (cmdRes2 == WNC_AT_CMD_TIMEOUT)) 02017 dbgPuts("------------ WNC No Response! --------->"); 02018 else 02019 dbgPuts("------------ WNC Cmd Error! ----------->"); 02020 } 02021 02022 // If by a miracle it responds to the 2nd after the 1st, keep going 02023 if ((cmdRes2 == WNC_AT_CMD_TIMEOUT) || (pRespStr->size() == 0)) 02024 return (false); 02025 } 02026 02027 // If SIM Card not ready don't bother with commands! 02028 if (pRespStr->find("CPIN: READY") == string::npos) 02029 { 02030 if (m_sMoreDebugEnabled) 02031 dbgPuts("------------ WNC SIM Problem! --------->"); 02032 02033 return (false); 02034 } 02035 02036 // SIM card OK, now check for signal and cellular network registration 02037 cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, m_sCmdTimeoutMs); // Check if registered on network 02038 if (cmdRes1 != WNC_AT_CMD_OK || pRespStr->size() == 0) 02039 { 02040 if (m_sMoreDebugEnabled) 02041 dbgPuts("------------ WNC +CREG? Fail! --------->"); 02042 02043 return (false); 02044 } 02045 else 02046 { 02047 pos = pRespStr->find("CREG: "); 02048 if (pos != string::npos) 02049 { 02050 // The registration is the 2nd arg in the comma separated list 02051 *pRespStr = pRespStr->substr(pos+8, 1); 02052 regSts = atoi(pRespStr->c_str()); 02053 switch (regSts) { 02054 case 1: 02055 case 5: 02056 case 6: 02057 case 7: 02058 m_sReadyForSMS = true; 02059 break; 02060 default: 02061 m_sReadyForSMS = false; 02062 dbgPuts("SMS Service Down!"); 02063 } 02064 02065 // 1 - registered home, 5 - registered roaming 02066 if ((regSts != 1) && (regSts != 5)) 02067 { 02068 if (m_sMoreDebugEnabled) 02069 dbgPuts("------ WNC Cell Link Down for Data! --->"); 02070 02071 return (false); 02072 } 02073 } 02074 02075 if (m_sMoreDebugEnabled) 02076 dbgPuts("------------ WNC Ready ---------------->"); 02077 } 02078 02079 // If we made it this far and the WNC did respond, keep the ON state 02080 if (m_sState != WNC_NO_RESPONSE) 02081 m_sState = WNC_ON; 02082 02083 return (true); 02084 } 02085 02086 int WncController::dbgPutsNoTime(const char * s, bool crlf) 02087 { 02088 if (m_sDebugEnabled == true) { 02089 int r = dbgWriteChars(s); 02090 if (crlf == true) 02091 return (dbgWriteChars("\r\n")); 02092 else 02093 return (r); 02094 } 02095 else 02096 return 0; 02097 }; 02098 02099 int WncController::dbgPuts(const char * s, bool crlf) 02100 { 02101 dbgPutsNoTime("[*] ", false); 02102 dbgPutsNoTime(_to_string(getLogTimerTicks()), false); 02103 dbgPutsNoTime(" ", false); 02104 02105 int r = dbgPutsNoTime(s, false); 02106 02107 if (crlf == true) 02108 return (dbgPutsNoTime("", true)); 02109 else 02110 return (r); 02111 }; 02112 02113 void WncController::sendCmd(const char * cmd, bool crLf) 02114 { 02115 puts(cmd); 02116 if (crLf == true) 02117 puts("\r\n"); 02118 } 02119 02120 void WncController::sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf) 02121 { 02122 while (n--) { 02123 putc(*cmd++); 02124 waitUs(wait_uS); 02125 }; 02126 if (crLf == true) { 02127 putc('\r'); 02128 waitUs(wait_uS); 02129 putc('\n'); 02130 waitUs(wait_uS); 02131 } 02132 } 02133 02134 }; // End namespace WncController_fk
Generated on Thu Jul 28 2022 18:34:02 by 1.7.2