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