V.06 11/3
Dependencies: FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts
Fork of ATT_AWS_IoT_demo by
WncController.cpp
00001 /* 00002 Copyright (c) 2016 Fred Kellerman 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 THE SOFTWARE. 00021 00022 @file WncController.cpp 00023 @purpose Controls WNC 14A2A Cellular Modem 00024 @version 1.0 00025 @date July 2016 00026 @author Fred Kellerman 00027 */ 00028 00029 00030 #include <cstdlib> 00031 #include <cctype> 00032 #include "WncController.h" 00033 00034 // Links to our certs from certs.cpp 00035 extern const unsigned char AWS_IOT_ROOT_CA[]; 00036 extern const unsigned char AWS_IOT_CERTIFICATE[]; 00037 extern const unsigned char AWS_IOT_PRIVATE_KEY[]; 00038 00039 extern int AWS_IOT_ROOT_CA_LENGTH; 00040 extern int AWS_IOT_CERTIFICATE_LENGTH; 00041 extern int AWS_IOT_PRIVATE_KEY_LENGTH; 00042 00043 namespace WncController_fk { 00044 00045 ///////////////////////////////////////////////////// 00046 // Static initializers 00047 ///////////////////////////////////////////////////// 00048 WncController::WncSocketInfo_s WncController::m_sSock[MAX_NUM_WNC_SOCKETS]; 00049 const WncController::WncSocketInfo_s WncController::defaultSockStruct = { 0, false, "192.168.0.1", 80, 0, 25, true, 30 }; 00050 00051 WncController::WncState_e WncController::m_sState = WNC_OFF; 00052 uint16_t WncController::m_sCmdTimeoutMs = WNC_CMD_TIMEOUT_MS; 00053 string WncController::m_sApnStr = "NULL"; 00054 string WncController::m_sWncStr; 00055 uint8_t WncController::m_sPowerUpTimeoutSecs = MAX_POWERUP_TIMEOUT; 00056 bool WncController::m_sDebugEnabled = false; 00057 bool WncController::m_sMoreDebugEnabled = false; 00058 bool WncController::m_sCheckNetStatus = false; // Turn on internet status check between every command 00059 const char * const WncController::INVALID_IP_STR = ""; 00060 bool WncController::m_sReadyForSMS = false; 00061 00062 string WncController::m_sChannelID; 00063 char WncController::sOutput[100]; 00064 char WncController::sCommand[256]; 00065 //unsigned char WncController::ucObject[2500]; 00066 string sObject; 00067 string sBlockObject, sByte; 00068 unsigned char sSubjectName[100]; 00069 00070 00071 /** 00072 * C++ version 0.4 char* style "itoa": 00073 * Written by Lukás Chmela 00074 * Released under GPLv3. 00075 */ 00076 00077 static char* itoa(int64_t value, char* result, int base) 00078 { 00079 // check that the base is valid 00080 if ( base < 2 || base > 36 ) { 00081 *result = '\0'; 00082 return result; 00083 } 00084 00085 char* ptr = result, *ptr1 = result, tmp_char; 00086 int64_t tmp_value; 00087 00088 do { 00089 tmp_value = value; 00090 value /= base; 00091 *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; 00092 } while ( value ); 00093 00094 // Apply negative sign 00095 if ( tmp_value < 0 ) 00096 *ptr++ = '-'; 00097 00098 *ptr-- = '\0'; 00099 00100 while ( ptr1 < ptr ) { 00101 tmp_char = *ptr; 00102 *ptr-- = *ptr1; 00103 *ptr1++ = tmp_char; 00104 } 00105 00106 return result; 00107 } 00108 00109 const char * WncController::_to_string(int64_t value) 00110 { 00111 static char str[21]; // room for signed 64-bit + null 00112 itoa(value, str, 10); 00113 return (str); 00114 } 00115 00116 const char * WncController::_to_hex_string(uint8_t value) 00117 { 00118 static char str[3]; // room for 8-bit + null 00119 itoa(value, str, 16); 00120 return (str); 00121 } 00122 00123 /** 00124 * \brief Constructor for UART controlled WNC 00125 * 00126 * \param [in] wnc_uart - Reference to a SerialBuffered object which will 00127 * be used as the bus to control the WNC. 00128 * 00129 * \return None. 00130 * 00131 * \details Adding another way to talk to the WNC, like I2C or USB, 00132 * a constructor should be added for each type just like the SerialBuffered 00133 * constructor below. 00134 */ 00135 WncController::WncController(void) 00136 { 00137 for(unsigned i; i<MAX_NUM_WNC_SOCKETS; i++) 00138 m_sSock[i] = defaultSockStruct; 00139 } 00140 00141 void WncController::enableDebug(bool on, bool moreDebugOn) 00142 { 00143 m_sDebugEnabled = on; 00144 m_sMoreDebugEnabled = moreDebugOn; 00145 } 00146 00147 /** 00148 * \brief Used internally but also make public for a user of the Class to interrogate state as well. 00149 * 00150 * \param [in] None. 00151 * 00152 * \return The state of the WNC Modem. 00153 * 00154 * \details None. 00155 */ 00156 WncController::WncState_e WncController::getWncStatus(void) 00157 { 00158 return (m_sState); 00159 } 00160 00161 /** 00162 * \brief Return signal quality dBm level 00163 * 00164 * \param [in] None. 00165 * 00166 * \return The dBm signal level at the time of the request. 00167 * 00168 * \details This polls (at the time of the call) the cell signal. 00169 */ 00170 int16_t WncController::getDbmRssi(void) 00171 { 00172 int16_t rssi, ber; 00173 if (at_getrssiber_wnc(&rssi, &ber) == true) 00174 return (rssi); 00175 else 00176 return (99); 00177 } 00178 00179 int16_t WncController::get3gBer(void) 00180 { 00181 int16_t rssi, ber; 00182 if (at_getrssiber_wnc(&rssi, &ber) == true) 00183 return (ber); 00184 else 00185 return (99); 00186 } 00187 00188 00189 /** 00190 * \brief Power up and down (down not implemented yet) 00191 * 00192 * \param [in] on - set true to power on, otherwise false 00193 * 00194 * \return None. 00195 * 00196 * \details Power-on works but not power-down. This will manipulate WNC Shield hardware 00197 * and bring it to life. It will also initialize the WNC enough to get it to be able to open sockets 00198 * (with AT commands) 00199 */ 00200 bool WncController::powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs) 00201 { 00202 dbgPuts("Waiting for WNC to Initialize..."); 00203 m_sPowerUpTimeoutSecs = powerUpTimeoutSecs; 00204 m_sState = WNC_ON_NO_CELL_LINK; // Turn soft on to allow "AT" for init to be sent! 00205 if (initWncModem(powerUpTimeoutSecs) == true) 00206 { 00207 //read certificates and keys 00208 00209 dbgPuts("Reading Object: Device Certificate"); 00210 if (getObject("00", (unsigned char *)AWS_IOT_CERTIFICATE, &AWS_IOT_CERTIFICATE_LENGTH) == false) 00211 { 00212 dbgPuts("Device Certificate Read Failed"); 00213 m_sState = WNC_OFF; 00214 return false; 00215 } 00216 //getObject("00", ucObject); 00217 dbgPuts("Reading Object: Device Private Key"); 00218 if (getObject("01", (unsigned char *)AWS_IOT_PRIVATE_KEY, &AWS_IOT_PRIVATE_KEY_LENGTH) == false) 00219 { 00220 dbgPuts("Device Private Key Read Failed"); 00221 m_sState = WNC_OFF; 00222 return false; 00223 } 00224 dbgPuts("Reading Object: Root CA Certificate"); 00225 if (getObject("02", (unsigned char *)AWS_IOT_ROOT_CA, &AWS_IOT_ROOT_CA_LENGTH) == false) 00226 { 00227 dbgPuts("Root CA Certificate Read Failed"); 00228 m_sState = WNC_OFF; 00229 return false; 00230 } 00231 00232 /* 00233 dbgPuts("Reading Subject Name"); 00234 int iSubjectLength; 00235 getSubjectName("03", sSubjectName, &iSubjectLength); 00236 00237 dbgPuts("Reading Update Status"); 00238 unsigned char cStatus; 00239 getUpdateStatus (&cStatus); 00240 */ 00241 00242 // Set the Apn 00243 setApnName(apn); 00244 if (false == softwareInitMdm()) 00245 { 00246 dbgPuts("Software init failed!"); 00247 m_sState = WNC_OFF; 00248 } 00249 00250 dbgPuts("Reading Signal Strength"); 00251 int16_t dbm = getDbmRssi(); 00252 int16_t ber = get3gBer(); 00253 sprintf (sOutput, "dbm = %d Ber = %d", dbm, ber); 00254 dbgPuts(sOutput); 00255 00256 00257 00258 } 00259 else { 00260 dbgPuts("Power up failed!"); 00261 m_sState = WNC_OFF; 00262 } 00263 00264 return ((m_sState == WNC_ON) || (m_sState == WNC_ON_NO_CELL_LINK)); 00265 } 00266 00267 bool WncController::getAllObjects() 00268 { 00269 //read certificates and keys 00270 00271 dbgPuts("Reading Object: Device Certificate"); 00272 if (getObject("00", (unsigned char *)AWS_IOT_CERTIFICATE, &AWS_IOT_CERTIFICATE_LENGTH) == false) 00273 { 00274 dbgPuts("Device Certificate Read Failed"); 00275 return false; 00276 } 00277 00278 dbgPuts("Reading Object: Device Private Key"); 00279 if (getObject("01", (unsigned char *)AWS_IOT_PRIVATE_KEY, &AWS_IOT_PRIVATE_KEY_LENGTH) == false) 00280 { 00281 dbgPuts("Device Private Key Read Failed"); 00282 return false; 00283 } 00284 dbgPuts("Reading Object: Root CA Certificate"); 00285 if (getObject("02", (unsigned char *)AWS_IOT_ROOT_CA, &AWS_IOT_ROOT_CA_LENGTH) == false) 00286 { 00287 dbgPuts("Root CA Certificate Read Failed"); 00288 return false; 00289 } 00290 00291 return true; 00292 } 00293 00294 size_t WncController::sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout) 00295 { 00296 string * respStr; 00297 00298 if (sizeRespBuf > 0) { 00299 AtCmdErr_e r = at_send_wnc_cmd(cmd, &respStr, ms_timeout); 00300 strncpy(resp, respStr->c_str(), sizeRespBuf); 00301 if (respStr->size() > sizeRespBuf) 00302 dbgPuts("sendCustomCmd truncated!"); 00303 00304 return (respStr->size()); 00305 } 00306 00307 dbgPuts("sendCustomCmd: would have overrun!"); 00308 00309 return (0); 00310 } 00311 00312 bool WncController::pingUrl(const char * url) 00313 { 00314 string ipAddr; 00315 00316 if (true == at_dnsresolve_wnc(url, &ipAddr)) 00317 return (pingIp(ipAddr.c_str())); 00318 else 00319 dbgPuts("pingUrl DNS resolve: failed!"); 00320 00321 return (false); 00322 } 00323 00324 bool WncController::pingIp(const char * ip) 00325 { 00326 if (true == at_ping_wnc(ip)) 00327 return (true); 00328 else 00329 dbgPuts("pingIp: failed!"); 00330 00331 return (false); 00332 } 00333 00334 bool WncController::getWncNetworkingStats(WncIpStats * s) 00335 { 00336 return (at_get_wnc_net_stats(s)); 00337 } 00338 00339 bool WncController::getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR]) 00340 { 00341 if (numSock < MAX_NUM_WNC_SOCKETS) { 00342 strncpy(myIpAddr, m_sSock[numSock].myIpAddressStr.c_str(), MAX_LEN_IP_STR); 00343 myIpAddr[MAX_LEN_IP_STR - 1] = '\0'; 00344 return (true); 00345 } 00346 else { 00347 myIpAddr[0] = '\0'; 00348 return (false); 00349 } 00350 } 00351 00352 bool WncController::setApnName(const char * const apnStr) 00353 { 00354 if (at_setapn_wnc(apnStr) == true) 00355 { 00356 m_sApnStr = apnStr; 00357 return (true); 00358 } 00359 else 00360 return (false); 00361 } 00362 00363 00364 /** 00365 * \brief Look-up a URL text string and convert into an IP Address string. 00366 * 00367 * \param [in] url - the URL to lookup. numSock - the socket number to resolve. 00368 * 00369 * \return true - if the IP address has been resolved. false - if the URL could not be resolved. 00370 * 00371 * \details None. 00372 */ 00373 bool WncController::resolveUrl(uint16_t numSock, const char * url) 00374 { 00375 bool cmdRes; 00376 00377 if (numSock < MAX_NUM_WNC_SOCKETS) { 00378 if (strlen(url) > 0) { 00379 cmdRes = at_dnsresolve_wnc(url, &m_sSock[numSock].myIpAddressStr); 00380 if (cmdRes == false) 00381 dbgPuts("Cannot resolve URL!"); 00382 return (cmdRes); 00383 } 00384 else 00385 dbgPuts("Invalid URL"); 00386 } 00387 else 00388 dbgPuts("Invalid Sock num!"); 00389 00390 return (false); 00391 } 00392 00393 /** 00394 * \brief Set IP Address string 00395 * 00396 * \param [in] numSock - socket reference to set the string for. ipStr - text string of the IP 00397 * address you want to talk to. There is no sanity check - beware!!! 00398 * 00399 * \return true - if the IP address has been set. false - if the IP could not be set. 00400 * 00401 * \details None. 00402 */ 00403 bool WncController::setIpAddr(uint16_t numSock, const char * ipStr) 00404 { 00405 if (numSock < MAX_NUM_WNC_SOCKETS) { 00406 m_sSock[numSock].myIpAddressStr = ipStr; 00407 return (true); 00408 } 00409 else { 00410 dbgPuts("Bad socket num!"); 00411 return (false); 00412 } 00413 } 00414 00415 void WncController::setWncCmdTimeout(uint16_t toMs) 00416 { 00417 m_sCmdTimeoutMs = toMs; 00418 } 00419 00420 /** 00421 * \brief Opens a WNC socket. 00422 * 00423 * \param [in] sockNum - the number of the socket to open. ipAddr - a string containing 00424 * the IP address. port - the IP port number to open the socket connection. 00425 * 00426 * \return true - if the socket is/was opened. false otherwise. 00427 * 00428 * \details None. 00429 */ 00430 00431 bool WncController::openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec) 00432 { 00433 if (resolveUrl(numSock, url) == true) 00434 return (openSocket(numSock, port, tcp, timeOutSec)); 00435 00436 return (false); 00437 } 00438 00439 bool WncController::openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec) 00440 { 00441 if (setIpAddr(numSock, ipAddr) == true) 00442 return (openSocket(numSock, port, tcp, timeOutSec)); 00443 00444 return (false); 00445 } 00446 00447 bool WncController::openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec) 00448 { 00449 if (numSock < MAX_NUM_WNC_SOCKETS) { 00450 // IPV4 ip addr sanity check! 00451 size_t lenIpStr = m_sSock[numSock].myIpAddressStr.size(); 00452 if (lenIpStr < 7 || lenIpStr > 15) { 00453 dbgPuts("Invalid IP Address!"); 00454 return (false); 00455 } 00456 00457 // Already open ? Must close if want to re-open with new settings. 00458 if (m_sSock[numSock].open == true) { 00459 dbgPuts("Socket already open, close then re-open!"); 00460 if (true == at_sockclose_wnc(m_sSock[numSock].numWncSock)) 00461 m_sSock[numSock].open = false; 00462 else 00463 return (false); 00464 } 00465 00466 m_sSock[numSock].myPort = port; 00467 m_sSock[numSock].isTcp = tcp; 00468 m_sSock[numSock].timeOutSec = timeOutSec; 00469 00470 int16_t numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), port, numSock, tcp, timeOutSec); 00471 m_sSock[numSock].numWncSock = numWncSock; 00472 if (numWncSock > 0 && numWncSock <= MAX_NUM_WNC_SOCKETS) 00473 m_sSock[numSock].open = true; 00474 else { 00475 m_sSock[numSock].open = false; 00476 dbgPuts("Socket open fail!!!!"); 00477 00478 // If the modem is not responding don't bother it. 00479 if (WNC_NO_RESPONSE != getWncStatus()) { 00480 // Work-around. If the sock open fails it needs to be told 00481 // to close. If 6 sock opens happen with a fail, it further 00482 // crashes the WNC. Not sure why the sock won't open. 00483 at_sockclose_wnc(m_sSock[numSock].numWncSock); 00484 } 00485 } 00486 } 00487 else { 00488 dbgPuts("Bad socket num or IP!"); 00489 return (false); 00490 } 00491 00492 return (m_sSock[numSock].open); 00493 } 00494 00495 /** 00496 * \brief Write bytes of data to an open socket 00497 * 00498 * \param [in] sockNum - the number of the socket to write. s - a string containing 00499 * the byte data to send must be less than = 1500. 00500 * 00501 * \return true - if the write was successful. false otherwise. 00502 * 00503 * \details The results of the write do not have anything to do with the data 00504 * arriving at the endpoint. 00505 */ 00506 00507 bool WncController::sockWrite(const char * const s, uint16_t n, uint16_t numSock, bool isTcp) 00508 { 00509 bool result = true; 00510 00511 AtCmdErr_e cmdRes = at_sockwrite_wnc(s, n, m_sSock[numSock].numWncSock, isTcp); 00512 if (cmdRes != WNC_AT_CMD_OK) { 00513 if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00514 { 00515 // This may throw away any data that hasn't been written out of the WNC 00516 // but at this point with the way the WNC currently works we have 00517 // no choice. 00518 closeOpenSocket(numSock); 00519 } 00520 result = false; 00521 } 00522 00523 return (result); 00524 } 00525 00526 bool WncController::write(uint16_t numSock, const char * s, uint32_t n) 00527 { 00528 bool result; 00529 00530 if (numSock < MAX_NUM_WNC_SOCKETS) { 00531 if (m_sSock[numSock].open == true) { 00532 if (n <= MAX_WNC_WRITE_BYTES) { 00533 result = sockWrite(s, n, numSock, m_sSock[numSock].isTcp); 00534 } 00535 else { 00536 uint16_t rem = n % MAX_WNC_WRITE_BYTES; 00537 while (n >= MAX_WNC_WRITE_BYTES) { 00538 n -= MAX_WNC_WRITE_BYTES; 00539 result = sockWrite(s, MAX_WNC_WRITE_BYTES, numSock, m_sSock[numSock].isTcp); 00540 if (result == false) { 00541 n = 0; 00542 rem = 0; 00543 dbgPuts("Sock write fail!"); 00544 } 00545 else 00546 s += MAX_WNC_WRITE_BYTES; 00547 } 00548 if (rem > 0) 00549 result = sockWrite(s, rem, numSock, m_sSock[numSock].isTcp); 00550 } 00551 } 00552 else { 00553 dbgPuts("Socket is closed for write!"); 00554 result = false; 00555 } 00556 } 00557 else { 00558 dbgPuts("Bad socket num!"); 00559 result = false; 00560 } 00561 00562 return (result); 00563 } 00564 00565 /** 00566 * \brief Poll and read back data from the WNC (if it has any) 00567 * If auto poll is enabled this read might fail (return with no data). 00568 * 00569 * \param [in] sockNum - the number of the socket to read. result - a string pointer containing 00570 * the byte data readback from the WNC. 00571 * 00572 * \return The number of bytes/chars that are read from the socket. 00573 * 00574 * \details DO NOT use the same string as is passed to the auto poll setup method! 00575 */ 00576 00577 size_t WncController::read(uint16_t numSock, const uint8_t ** readBuf) 00578 { 00579 static string theBuf; 00580 string readStr; 00581 00582 theBuf.erase(); // Clean-up from last time 00583 00584 if (numSock < MAX_NUM_WNC_SOCKETS) { 00585 if (m_sSock[numSock].open == true) { 00586 uint8_t i = m_sSock[numSock].readRetries; 00587 uint16_t to = m_sSock[numSock].readRetryWaitMs; 00588 bool foundData = false; 00589 do { 00590 AtCmdErr_e cmdRes; 00591 cmdRes = at_sockread_wnc(&readStr, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00592 if (WNC_AT_CMD_OK == cmdRes) { 00593 // This will let this loop read until the socket data is 00594 // empty. If no data, then wait the retry amount of time. 00595 if (readStr.size() > 0) { 00596 theBuf += readStr; 00597 foundData = true; 00598 i = 1; 00599 } 00600 else { 00601 // Once data is found start returning it asap 00602 if (foundData == false) 00603 waitMs(to); 00604 } 00605 } 00606 else { 00607 theBuf += readStr; // Append what if any we got before it errored. 00608 dbgPuts("Sockread failed!"); 00609 if (WNC_NO_RESPONSE == getWncStatus()) { 00610 i = 0; 00611 } 00612 else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00613 { 00614 // This may throw away any data that hasn't been read out of the WNC 00615 // but at this point with the way the WNC currently works we have 00616 // no choice. 00617 closeOpenSocket(numSock); 00618 i = 0; 00619 } 00620 else 00621 waitMs(to); 00622 } 00623 } while (i-- > 0); 00624 } 00625 else { 00626 dbgPuts("Socket is closed for read"); 00627 } 00628 } 00629 else { 00630 dbgPuts("Bad socket num!"); 00631 } 00632 00633 *readBuf = (const uint8_t *)theBuf.c_str(); 00634 00635 return (theBuf.size()); 00636 } 00637 00638 size_t WncController::read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen) 00639 { 00640 uint32_t numCopied = 0; 00641 00642 if (numSock < MAX_NUM_WNC_SOCKETS) { 00643 if (m_sSock[numSock].open == true) { 00644 uint8_t i = m_sSock[numSock].readRetries; 00645 uint16_t to = m_sSock[numSock].readRetryWaitMs; 00646 bool foundData = false; 00647 uint16_t numRead; 00648 do { 00649 AtCmdErr_e cmdRes; 00650 if (maxReadBufLen < MAX_WNC_READ_BYTES) 00651 cmdRes = at_sockread_wnc(readBuf, &numRead, maxReadBufLen, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00652 else 00653 cmdRes = at_sockread_wnc(readBuf, &numRead, MAX_WNC_READ_BYTES, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); 00654 00655 if (WNC_AT_CMD_OK == cmdRes) { 00656 // This will let this loop read until the socket data is 00657 // empty. If no data, then wait the retry amount of time. 00658 if (numRead > 0) { 00659 foundData = true; 00660 i = 1; 00661 if (numRead <= maxReadBufLen) { 00662 maxReadBufLen -= numRead; 00663 numCopied += numRead; 00664 readBuf += numRead; 00665 } 00666 else { 00667 i = 0; // No more room for data! 00668 dbgPutsNoTime("No more room for read data!"); 00669 } 00670 } 00671 else { 00672 // Once data is found start returning it asap 00673 if (foundData == false) 00674 waitMs(to); 00675 } 00676 } 00677 else { 00678 dbgPuts("Sockread failed!"); 00679 if (WNC_NO_RESPONSE == getWncStatus()) { 00680 i = 0; 00681 } 00682 else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) 00683 { 00684 // This may throw away any data that hasn't been read out of the WNC 00685 // but at this point with the way the WNC currently works we have 00686 // no choice. 00687 closeOpenSocket(numSock); 00688 i = 0; 00689 } 00690 else 00691 waitMs(to); 00692 } 00693 } while ((i-- > 0) && (maxReadBufLen > 0)); 00694 } 00695 else { 00696 dbgPuts("Socket is closed for read"); 00697 } 00698 } 00699 else { 00700 dbgPuts("Bad socket num!"); 00701 } 00702 00703 return (numCopied); 00704 } 00705 00706 /** 00707 * \brief Set how many times the above read method will retry if data is not returned. 00708 * 00709 * \param [in] sockNum - the number of the socket to set. retries - how many times to 00710 * poll until data is found. 00711 * 00712 * \return None. 00713 * 00714 * \details None. 00715 */ 00716 void WncController::setReadRetries(uint16_t numSock, uint16_t retries) 00717 { 00718 if (numSock < MAX_NUM_WNC_SOCKETS) 00719 m_sSock[numSock].readRetries = retries; 00720 else 00721 dbgPuts("Bad socket num!"); 00722 } 00723 00724 /** 00725 * \brief Set how long between retries to wait. 00726 * 00727 * \param [in] sockNum - the number of the socket to set. readRetryWaitMs - how long to wait 00728 * before doing the read poll (calling read(...)). 00729 * 00730 * \return None. 00731 * 00732 * \details None. 00733 */ 00734 void WncController::setReadRetryWait(uint16_t numSock, uint16_t readRetryWaitMs) 00735 { 00736 if (numSock < MAX_NUM_WNC_SOCKETS) 00737 m_sSock[numSock].readRetryWaitMs = readRetryWaitMs; 00738 else 00739 dbgPuts("Bad socket num!"); 00740 } 00741 00742 /** 00743 * \brief Close the socket. 00744 * 00745 * \param [in] sockNum - the number of the socket to close. 00746 * 00747 * \return None. 00748 * 00749 * \details None. 00750 */ 00751 bool WncController::closeSocket(uint16_t numSock) 00752 { 00753 if (numSock < MAX_NUM_WNC_SOCKETS) { 00754 00755 if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) 00756 dbgPuts("Sock close may not have closed!"); 00757 00758 // Even with an error the socket could have closed, 00759 // can't tell for sure so just soft close it for now. 00760 m_sSock[numSock].open = false; 00761 } 00762 else { 00763 dbgPuts("Bad socket num!"); 00764 } 00765 00766 return (m_sSock[numSock].open == false); 00767 } 00768 00769 // Note: If you want to make it more portable, create a 00770 // arecharsavailable() and readchar() 00771 size_t WncController::mdmGetline(string * buff, int timeout_ms) 00772 { 00773 char chin = '\0'; 00774 char chin_last; 00775 size_t len = 0; 00776 00777 startTimerB(); 00778 while ((len <= MAX_LEN_WNC_CMD_RESPONSE) && (getTimerTicksB_mS() < timeout_ms)) { 00779 if (charReady()) { 00780 chin_last = chin; 00781 chin = getc(); 00782 if (isprint(chin)) { 00783 *buff += chin; 00784 len++; // Bound the copy length to something reaonable just in case 00785 continue; 00786 } 00787 else if ((('\r' == chin_last) && ('\n' == chin)) || (('\n' == chin_last) && ('\r' == chin))) { 00788 break; 00789 } 00790 } 00791 } 00792 stopTimerB(); 00793 00794 if (len > MAX_LEN_WNC_CMD_RESPONSE) 00795 dbgPuts("Max cmd length reply exceeded!"); 00796 00797 return (len); 00798 } 00799 00800 // Eventually this should try to reinstate the sockets open 00801 bool WncController::softwareInitMdm(void) 00802 { 00803 static bool reportStatus = true; 00804 unsigned i; 00805 00806 if (checkCellLink() == true) { 00807 if (reportStatus == false) { 00808 dbgPuts("Re-connected to cellular network!"); 00809 reportStatus = true; 00810 } 00811 00812 // WNC has SIM and registered on network so 00813 // soft initialize the WNC. 00814 for (i = 0; i < WNC_SOFT_INIT_RETRY_COUNT; i++) 00815 if (at_init_wnc() == true) 00816 break; 00817 00818 // If it did not respond try a hardware init 00819 if (i == WNC_SOFT_INIT_RETRY_COUNT) 00820 { 00821 at_reinitialize_mdm(); 00822 return (at_init_wnc(true)); // Hard reset occurred so make it go through the software init(); 00823 } 00824 else 00825 return (true); 00826 } 00827 else 00828 { 00829 if (reportStatus == true) { 00830 dbgPuts("Not connected to cellular network!"); 00831 reportStatus = false; 00832 } 00833 return (false); 00834 } 00835 } 00836 00837 00838 // Sets a global with failure or success, assumes 1 thread all the time 00839 WncController::AtCmdErr_e WncController::sendWncCmd(const char * const s, string ** r, int ms_timeout) 00840 { 00841 if (checkCellLink() == false) { 00842 static string noRespStr; 00843 00844 // Save some run-time! 00845 if (m_sDebugEnabled) 00846 { 00847 dbgPuts("FAIL send cmd: ", false); 00848 if (m_sMoreDebugEnabled && m_sDebugEnabled) { 00849 dbgPutsNoTime(s); 00850 } 00851 else { 00852 size_t n = strlen(s); 00853 if (n <= WNC_TRUNC_DEBUG_LENGTH) { 00854 dbgPutsNoTime(s); 00855 } 00856 else { 00857 string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); 00858 truncStr += ".."; 00859 truncStr += &s[n-(WNC_TRUNC_DEBUG_LENGTH/2)]; 00860 dbgPutsNoTime(truncStr.c_str()); 00861 } 00862 } 00863 } 00864 00865 noRespStr.erase(); 00866 *r = &noRespStr; 00867 00868 return (WNC_AT_CMD_NO_CELL_LINK); 00869 } 00870 00871 if (m_sCheckNetStatus) 00872 { 00873 if (m_sMoreDebugEnabled) 00874 dbgPuts("[---------- Network Status -------------"); 00875 string * pRespStr; 00876 at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, m_sCmdTimeoutMs); 00877 if (m_sMoreDebugEnabled) 00878 dbgPuts("---------------------------------------]"); 00879 } 00880 00881 // If WNC ready, send user command 00882 return (at_send_wnc_cmd(s, r, ms_timeout)); 00883 } 00884 00885 WncController::AtCmdErr_e WncController::at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) 00886 { 00887 // Save some run-time! 00888 if (m_sDebugEnabled) 00889 { 00890 if (m_sMoreDebugEnabled) { 00891 dbgPuts("TX: ", false); dbgPutsNoTime(s); 00892 } 00893 else { 00894 if (m_sDebugEnabled) { // Save some run-time! 00895 size_t n = strlen(s); 00896 if (n <= WNC_TRUNC_DEBUG_LENGTH) { 00897 dbgPuts("TX: ", false); dbgPutsNoTime(s); 00898 } 00899 else { 00900 string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); 00901 truncStr += ".."; 00902 truncStr += &s[n - (WNC_TRUNC_DEBUG_LENGTH/2)]; 00903 dbgPuts("TX: ", false); dbgPutsNoTime(truncStr.c_str()); 00904 } 00905 } 00906 } 00907 } 00908 00909 AtCmdErr_e atResult = mdmSendAtCmdRsp(s, ms_timeout, &m_sWncStr); 00910 *r = &m_sWncStr; // Return a pointer to the static string 00911 00912 if (atResult != WNC_AT_CMD_TIMEOUT) { 00913 // If a prior command timed out but a new one works then 00914 // change the state back to ON. We don't know here in this 00915 // method if the Cell Link is good so assume it is. When a command 00916 // that depends on the cell link is made it will update the state. 00917 if (m_sState == WNC_NO_RESPONSE) 00918 m_sState = WNC_ON; 00919 00920 // Save some run-time! 00921 if (m_sDebugEnabled) 00922 { 00923 dbgPuts("RX: ", false); 00924 if (m_sMoreDebugEnabled) { 00925 dbgPutsNoTime(m_sWncStr.c_str()); 00926 } 00927 else { 00928 if (m_sWncStr.size() <= WNC_TRUNC_DEBUG_LENGTH) { 00929 dbgPutsNoTime(m_sWncStr.c_str()); 00930 } 00931 else { 00932 string truncStr = m_sWncStr.substr(0,WNC_TRUNC_DEBUG_LENGTH/2) + ".."; 00933 truncStr += m_sWncStr.substr(m_sWncStr.size() - (WNC_TRUNC_DEBUG_LENGTH/2), WNC_TRUNC_DEBUG_LENGTH/2); 00934 dbgPutsNoTime(truncStr.c_str()); 00935 } 00936 } 00937 } 00938 } 00939 else { 00940 m_sState = WNC_NO_RESPONSE; 00941 dbgPuts("AT Cmd TIMEOUT!"); 00942 dbgPuts("RX: ", false); dbgPutsNoTime(m_sWncStr.c_str()); 00943 } 00944 00945 return (atResult); 00946 } 00947 00948 void WncController::closeOpenSocket(uint16_t numSock) 00949 { 00950 // Try to open and close the socket 00951 do { 00952 dbgPuts("Try to close and re-open socket"); 00953 if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) { 00954 if (WNC_NO_RESPONSE == getWncStatus()) { 00955 dbgPuts("No response for closeOpenSocket1"); 00956 return ; 00957 } 00958 } 00959 00960 int numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), m_sSock[numSock].myPort, numSock, m_sSock[numSock].isTcp, m_sSock[numSock].timeOutSec); 00961 m_sSock[numSock].numWncSock = numWncSock; 00962 if (numWncSock > 0 && numWncSock <= MAX_NUM_WNC_SOCKETS) 00963 m_sSock[numSock].open = true; 00964 else { 00965 m_sSock[numSock].open = false; 00966 dbgPuts("Failed to re-open socket!"); 00967 } 00968 00969 if (WNC_NO_RESPONSE == getWncStatus()) { 00970 dbgPuts("No response for closeOpenSocket2"); 00971 return ; 00972 } 00973 } while (m_sSock[numSock].open == false); 00974 } 00975 00976 00977 bool WncController::getICCID(string * iccid) 00978 { 00979 if (at_geticcid_wnc(iccid) == false) { 00980 dbgPuts("getICCID error!"); 00981 return (false); 00982 } 00983 00984 return (true); 00985 } 00986 00987 bool WncController::at_geticcid_wnc(string * iccid) 00988 { 00989 string * respStr; 00990 00991 iccid->erase(); 00992 00993 AtCmdErr_e r = at_send_wnc_cmd("AT%CCID", &respStr, m_sCmdTimeoutMs); 00994 00995 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 00996 return (false); 00997 00998 size_t pos = respStr->find("AT%CCID"); 00999 if (pos == string::npos) 01000 return (false); 01001 01002 size_t posOK = respStr->rfind("OK"); 01003 if (posOK == string::npos) 01004 return (false); 01005 01006 pos += 7; // Advanced to the number 01007 *iccid = respStr->substr(pos, posOK - pos); 01008 01009 return (true); 01010 } 01011 01012 01013 bool WncController::convertICCIDtoMSISDN(const string & iccid, string * msisdn) 01014 { 01015 msisdn->erase(); 01016 01017 if (iccid.size() != 20 && iccid.size() != 19) { 01018 dbgPuts("Invalid ICCID length!"); 01019 return (false); 01020 } 01021 01022 *msisdn = "882350"; 01023 01024 if (iccid.size() == 20) 01025 *msisdn += iccid.substr(10,iccid.size() - 11); 01026 else 01027 *msisdn += iccid.substr(10,iccid.size() - 10); 01028 01029 return (true); 01030 } 01031 01032 01033 01034 bool WncController::getObject(string sObjectName, unsigned char *ucObject, int *iObjectTotalLength) 01035 { 01036 char cBlockOffset[7]; 01037 int iMaxBlockSize = 248; 01038 bool bChannelOpen = false; 01039 01040 int iObjectLength = 0, iObjectBlockLength = 0, iNumBlocks = 0, iRemainder = 0, iObjectStringLength = 0, iIndex = 0, k; 01041 //string sBlockObject, sByte; 01042 01043 01044 dbgPuts("openChannel..."); 01045 if (at_openChannel_wnc(&m_sChannelID) == false) 01046 { 01047 dbgPuts("openChannel error!"); 01048 return (false); 01049 } 01050 bChannelOpen = true; 01051 01052 dbgPuts("selectObject..."); 01053 if (at_selectObject_wnc(m_sChannelID, sObjectName, &iObjectLength) == false) 01054 { 01055 dbgPuts("selectObject error!"); 01056 if (bChannelOpen) 01057 { 01058 dbgPuts("closChannel..."); 01059 at_closeChannel_wnc(m_sChannelID); 01060 } 01061 return (false); 01062 } 01063 01064 01065 iRemainder = iObjectLength%iMaxBlockSize; 01066 iNumBlocks = iObjectLength/iMaxBlockSize; 01067 if (iRemainder > 0) 01068 iNumBlocks++; 01069 01070 sObject.erase(); 01071 01072 for (int i = 0; i < iNumBlocks; i++) 01073 { 01074 if (i == (iNumBlocks - 1)) 01075 sprintf (cBlockOffset, "%04X%02X", i*iMaxBlockSize, iRemainder); 01076 else 01077 sprintf (cBlockOffset, "%04X%02X", i*iMaxBlockSize, iMaxBlockSize); 01078 01079 dbgPuts(cBlockOffset); 01080 01081 dbgPuts("getObjectBlock...!"); 01082 if (at_getObjectBlock_wnc(m_sChannelID, sObjectName, cBlockOffset, &iObjectBlockLength, &sBlockObject) == false) 01083 { 01084 dbgPuts("getObjectBlock error!"); 01085 if (bChannelOpen) 01086 { 01087 dbgPuts("closChannel..."); 01088 at_closeChannel_wnc(m_sChannelID); 01089 } 01090 return (false); 01091 } 01092 sObject += sBlockObject; 01093 } 01094 //dbgPuts ("Object = "); 01095 //dbgPuts (sObject.c_str()); 01096 01097 if (bChannelOpen) 01098 { 01099 for (int j =0; j < 10; j++) 01100 { 01101 //waitMs(2000); 01102 dbgPuts("closeChannel..."); 01103 if (at_closeChannel_wnc(m_sChannelID) == true) 01104 break; 01105 } 01106 } 01107 01108 //convert the Object in string to unsigned char array 01109 iObjectStringLength = strlen(sObject.c_str()); 01110 sprintf (sOutput, "Object Length = %d", iObjectStringLength); 01111 dbgPuts(sOutput); 01112 iIndex = 0; 01113 k = 0; 01114 while (k < iObjectStringLength) 01115 { 01116 sByte = sObject.substr(k,2); 01117 ucObject[iIndex] = (unsigned char) strtoul (sByte.c_str(), NULL, 16); 01118 k +=2; 01119 iIndex++; 01120 } 01121 01122 sprintf (sOutput, "Buf Length = %d Object = ", iIndex); 01123 dbgPuts(sOutput); 01124 sObject.erase(); 01125 for (int i = 0; i < iIndex; i++) 01126 { 01127 sprintf (cBlockOffset, "%02X", ucObject[i]); 01128 sObject += string (cBlockOffset); 01129 01130 } 01131 dbgPuts(sObject.c_str()); 01132 01133 *iObjectTotalLength = iIndex; 01134 01135 return (true); 01136 } 01137 01138 bool WncController::getSubjectName(string sObjectName, unsigned char *ucObject, int *iObjectTotalLength) 01139 { 01140 char cBlockOffset[7]; 01141 bool bChannelOpen = false; 01142 01143 int iObjectLength = 0, iObjectStringLength = 0, iIndex = 0, k; 01144 //string sBlockObject, sByte; 01145 01146 01147 dbgPuts("openChannel..."); 01148 if (at_openChannel_wnc(&m_sChannelID) == false) 01149 { 01150 dbgPuts("openChannel error!"); 01151 return (false); 01152 } 01153 bChannelOpen = true; 01154 01155 01156 sObject.erase(); 01157 01158 dbgPuts("getSubjectName...!"); 01159 if (at_getSubjectName_wnc(m_sChannelID, &iObjectLength, &sObject) == false) 01160 { 01161 dbgPuts("getSubjectName error!"); 01162 if (bChannelOpen) 01163 { 01164 dbgPuts("closChannel..."); 01165 at_closeChannel_wnc(m_sChannelID); 01166 } 01167 return (false); 01168 } 01169 01170 if (bChannelOpen) 01171 { 01172 for (int j =0; j < 10; j++) 01173 { 01174 dbgPuts("closeChannel..."); 01175 if (at_closeChannel_wnc(m_sChannelID) == true) 01176 break; 01177 } 01178 } 01179 01180 //convert the Object in string to unsigned char array 01181 iObjectStringLength = strlen(sObject.c_str()); 01182 sprintf (sOutput, "Object Length = %d", iObjectStringLength); 01183 dbgPuts(sOutput); 01184 01185 iIndex = 0; 01186 k = 0; 01187 while (k < iObjectStringLength) 01188 { 01189 sByte = sObject.substr(k,2); 01190 ucObject[iIndex] = (unsigned char) strtoul (sByte.c_str(), NULL, 16); 01191 k +=2; 01192 iIndex++; 01193 } 01194 01195 sprintf (sOutput, "Buf Length = %d Object = ", iIndex); 01196 dbgPuts(sOutput); 01197 sObject.erase(); 01198 for (int i = 0; i < iIndex; i++) 01199 { 01200 sprintf (cBlockOffset, "%02X", ucObject[i]); 01201 sObject += string (cBlockOffset); 01202 01203 } 01204 dbgPuts(sObject.c_str()); 01205 01206 *iObjectTotalLength = iIndex; 01207 01208 return (true); 01209 } 01210 01211 bool WncController::getUpdateStatus(unsigned char *cStatus) 01212 { 01213 char cBlockOffset[7]; 01214 bool bChannelOpen = false; 01215 01216 int iObjectLength = 0, iObjectStringLength = 0, iIndex = 0, k; 01217 //string sBlockObject, sByte; 01218 01219 01220 dbgPuts("openChannel..."); 01221 if (at_openChannel_wnc(&m_sChannelID) == false) 01222 { 01223 dbgPuts("openChannel error!"); 01224 return (false); 01225 } 01226 bChannelOpen = true; 01227 01228 01229 sObject.erase(); 01230 01231 dbgPuts("getUpdateStatus...!"); 01232 if (at_getUpdateStatus_wnc(m_sChannelID, &iObjectLength, &sObject) == false) 01233 { 01234 dbgPuts("getUpdateStatus error!"); 01235 if (bChannelOpen) 01236 { 01237 dbgPuts("closChannel..."); 01238 at_closeChannel_wnc(m_sChannelID); 01239 } 01240 return (false); 01241 } 01242 01243 if (bChannelOpen) 01244 { 01245 for (int j =0; j < 10; j++) 01246 { 01247 dbgPuts("closeChannel..."); 01248 if (at_closeChannel_wnc(m_sChannelID) == true) 01249 break; 01250 } 01251 } 01252 01253 //convert the Object in string to unsigned char array 01254 iObjectStringLength = strlen(sObject.c_str()); 01255 sprintf (sOutput, "Object Length = %d", iObjectStringLength); 01256 dbgPuts(sOutput); 01257 01258 sByte = sObject.substr(0,2); 01259 *cStatus = (unsigned char) strtoul (sByte.c_str(), NULL, 16); 01260 01261 return (true); 01262 } 01263 01264 bool WncController::at_openChannel_wnc(string * sChannelID) 01265 { 01266 string * respStr; 01267 01268 01269 //open a channel to certificate management applet 01270 //AtCmdErr_e r = at_send_wnc_cmd("AT+CCHO=\"f0504b43533135\"", &respStr, m_sCmdTimeoutMs); 01271 AtCmdErr_e r = at_send_wnc_cmd("AT+CCHO=\"D2760001180002FFF1003D89\"", &respStr, m_sCmdTimeoutMs); 01272 01273 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01274 return (false); 01275 01276 size_t pos = respStr->find("AT+CCHO"); 01277 if (pos == string::npos) 01278 return (false); 01279 01280 size_t posOK = respStr->rfind("OK"); 01281 if (posOK == string::npos) 01282 return (false); 01283 01284 *sChannelID = respStr->substr(41, 1); 01285 01286 sprintf (sOutput, "Channel ID = %s", (*sChannelID).c_str()); 01287 dbgPuts(sOutput); 01288 01289 return (true); 01290 } 01291 01292 bool WncController::at_closeChannel_wnc(string sChannelID) 01293 { 01294 string * respStr; 01295 01296 01297 //close the channel to certificate management applet 01298 sprintf (sCommand, "AT+CCHC=%s", sChannelID.c_str()); 01299 AtCmdErr_e r = at_send_wnc_cmd(sCommand, &respStr, m_sCmdTimeoutMs); 01300 01301 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01302 return (false); 01303 01304 size_t pos = respStr->find("AT+CCHC"); 01305 if (pos == string::npos) 01306 return (false); 01307 01308 size_t posOK = respStr->rfind("OK"); 01309 if (posOK == string::npos) 01310 return (false); 01311 01312 dbgPuts("Channel Closed"); 01313 01314 return (true); 01315 } 01316 01317 bool WncController::at_selectObject_wnc(string sChannelID, string sObject, int *iObjectLength) 01318 { 01319 string * respStr; 01320 string sObjectLength; 01321 01322 //open a channel to certificate management applet 01323 sprintf (sCommand, "AT+CSIM=14,\"8%s58%s01024455\"", sChannelID.c_str(), sObject.c_str()); 01324 01325 AtCmdErr_e r = at_send_wnc_cmd(sCommand, &respStr, m_sCmdTimeoutMs); 01326 01327 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01328 return (false); 01329 01330 size_t pos = respStr->find("AT+CSIM=14"); 01331 if (pos == string::npos) 01332 return (false); 01333 01334 size_t posOK = respStr->rfind("OK"); 01335 if (posOK == string::npos) 01336 return (false); 01337 01338 size_t pos9000 = respStr->rfind("9000"); 01339 if (pos9000 == string::npos) 01340 return (false); 01341 01342 sObjectLength = respStr->substr(37, 4); 01343 *iObjectLength = (int) strtol (sObjectLength.c_str(), NULL, 16); 01344 01345 sprintf (sOutput, "Object Length = %s %d", sObjectLength.c_str(), *iObjectLength); 01346 dbgPuts(sOutput); 01347 01348 return (true); 01349 } 01350 01351 bool WncController::at_getObjectBlock_wnc(string sChannelID, string sObject, string sBlock, int *iObjectBlockLength, string *sData) 01352 { 01353 string * respStr; 01354 string sObjectBlockLength; 01355 01356 //read block from object specified in the sBlock String. The for mat of string is offset = XXXX, length ZZ. So the offset at 0000 and length of F8 witll be 0000F8. The string must be in ascii hex format 01357 01358 sprintf (sCommand, "AT+CSIM=16,\"8%s58%s0203%s\"", sChannelID.c_str(), sObject.c_str(), sBlock.c_str()); 01359 01360 AtCmdErr_e r = at_send_wnc_cmd(sCommand, &respStr, m_sCmdTimeoutMs); 01361 01362 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01363 return (false); 01364 01365 size_t pos = respStr->find("AT+CSIM=16"); 01366 if (pos == string::npos) 01367 return (false); 01368 01369 size_t posOK = respStr->rfind("OK"); 01370 if (posOK == string::npos) 01371 return (false); 01372 01373 size_t pos9000 = respStr->rfind("9000"); 01374 if (pos9000 == string::npos) 01375 return (false); 01376 01377 sObjectBlockLength = respStr->substr(36, 3); 01378 *iObjectBlockLength = (int) strtol (sObjectBlockLength.c_str(), NULL, 0); 01379 //without the status characters 01380 *iObjectBlockLength = *iObjectBlockLength - 4; 01381 *sData = respStr->substr(41, *iObjectBlockLength); 01382 01383 sprintf (sOutput, "Object Length = %s %d", sObjectBlockLength.c_str(), *iObjectBlockLength); 01384 dbgPuts(sOutput); 01385 dbgPuts((*sData).c_str()); 01386 01387 return (true); 01388 } 01389 01390 bool WncController::at_getSubjectName_wnc(string sChannelID, int *iObjectBlockLength, string *sData) 01391 { 01392 string * respStr; 01393 string sObjectBlockLength; 01394 01395 01396 sprintf (sCommand, "AT+CSIM=16,\"8%s58030003010101\"", sChannelID.c_str()); 01397 01398 AtCmdErr_e r = at_send_wnc_cmd(sCommand, &respStr, m_sCmdTimeoutMs); 01399 01400 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01401 return (false); 01402 01403 size_t pos = respStr->find("AT+CSIM=16"); 01404 if (pos == string::npos) 01405 return (false); 01406 01407 size_t posOK = respStr->rfind("OK"); 01408 if (posOK == string::npos) 01409 return (false); 01410 01411 size_t pos9000 = respStr->rfind("9000"); 01412 if (pos9000 == string::npos) 01413 return (false); 01414 01415 sObjectBlockLength = respStr->substr(36, 3); 01416 *iObjectBlockLength = (int) strtol (sObjectBlockLength.c_str(), NULL, 0); 01417 //without the status characters 01418 *iObjectBlockLength = *iObjectBlockLength - 4; 01419 *sData = respStr->substr(40, *iObjectBlockLength); 01420 01421 sprintf (sOutput, "Object Length = %s %d", sObjectBlockLength.c_str(), *iObjectBlockLength); 01422 dbgPuts(sOutput); 01423 dbgPuts((*sData).c_str()); 01424 01425 return (true); 01426 } 01427 01428 01429 bool WncController::at_getUpdateStatus_wnc(string sChannelID, int *iLength, string *sData) 01430 { 01431 string * respStr; 01432 string sObjectBlockLength; 01433 01434 01435 sprintf (sCommand, "AT+CSIM=10,\"8%s5A000001\"", sChannelID.c_str()); 01436 01437 AtCmdErr_e r = at_send_wnc_cmd(sCommand, &respStr, m_sCmdTimeoutMs); 01438 01439 if (r != WNC_AT_CMD_OK || respStr->size() == 0) 01440 return (false); 01441 01442 size_t pos = respStr->find("AT+CSIM=10"); 01443 if (pos == string::npos) 01444 return (false); 01445 01446 size_t posOK = respStr->rfind("OK"); 01447 if (posOK == string::npos) 01448 return (false); 01449 01450 size_t pos9000 = respStr->rfind("9000"); 01451 if (pos9000 == string::npos) 01452 return (false); 01453 01454 sObjectBlockLength = respStr->substr(29, 2); 01455 *iLength = (int) strtol (sObjectBlockLength.c_str(), NULL, 0); 01456 //without the status characters 01457 *iLength = *iLength - 4; 01458 *sData = respStr->substr(33, *iLength); 01459 01460 sprintf (sOutput, "Object Length = %s %d", sObjectBlockLength.c_str(), *iLength); 01461 dbgPuts(sOutput); 01462 dbgPuts((*sData).c_str()); 01463 01464 return (true); 01465 } 01466 01467 01468 bool WncController::sendSMSText(const char * const phoneNum, const char * const text) 01469 { 01470 if (at_sendSMStext_wnc(phoneNum, text) == true) 01471 return (true); 01472 else { 01473 dbgPuts("sendSMSText: Failed!"); 01474 return (false); 01475 } 01476 } 01477 01478 bool WncController::readSMSLog(struct WncSmsList * log) 01479 { 01480 string * logStr; 01481 uint16_t i; 01482 01483 if (at_readSMSlog_wnc(&logStr) == false) { 01484 dbgPuts("readSMSLog: Failed!"); 01485 return (false); 01486 } 01487 01488 // Clean slate 01489 log->msgCount = 0; 01490 01491 if (logStr->size() == 0) 01492 return (false); 01493 01494 // Pick out the stuff from the string and convert to struct 01495 string s; 01496 size_t pos2; 01497 size_t pos = logStr->find("+CMGL:"); 01498 01499 for(i=0; i<MAX_WNC_SMS_MSG_SLOTS; i++) { 01500 // Start with a clean slate, let parsing fill out later. 01501 log->e[i].unread = false; 01502 log->e[i].incoming = false; 01503 log->e[i].unsent = false; 01504 log->e[i].pduMode = false; 01505 log->e[i].msgReceipt = false; 01506 01507 log->e[i].idx = logStr->at(pos + 7); 01508 if (pos == string::npos) 01509 return (false); 01510 pos2 = logStr->find(",\"", pos); 01511 if (pos2 == string::npos) { 01512 // If the WNC acts wrong and receives a PDU mode 01513 // SMS there will not be any quotes in the response, 01514 // just take the whole reply and make it the message body for 01515 // now, mark it as an unread message, set the pdu flag! 01516 log->e[log->msgCount].unread = true; 01517 log->e[log->msgCount].pduMode = true; 01518 log->msgCount++; 01519 01520 pos2 = logStr->find("+CMGL", pos + 5); 01521 if (pos2 == string::npos) { 01522 pos2 = logStr->find("OK", pos + 5); 01523 if (pos2 == string::npos) { 01524 dbgPuts("Strange SMS Log Ending!"); 01525 return (false); 01526 } 01527 i = MAX_WNC_SMS_MSG_SLOTS; 01528 } 01529 log->e[log->msgCount].msg = logStr->substr(0, pos2 - pos); 01530 pos = pos2; // for loop starts off expecting pos to point to next log msg 01531 continue; 01532 } 01533 pos += 2; // Advance to the text we want 01534 pos2 = logStr->find("\",", pos); 01535 if ((pos2 == string::npos) || (pos >= pos2)) 01536 return (false); 01537 01538 // Setup attributes 01539 s = logStr->substr(pos, pos2 - pos); 01540 if (s.find("REC READ") != string::npos) 01541 log->e[i].incoming = true; 01542 if (s.find("REC UNREAD") != string::npos) { 01543 log->e[i].unread = true; 01544 log->e[i].incoming = true; 01545 } 01546 if (s.find("STO UNSENT") != string::npos) 01547 log->e[i].unsent = true; 01548 if (logStr->find(",,") == string::npos) 01549 log->e[i].msgReceipt = true; 01550 01551 // Tele number 01552 pos2 = logStr->find(",\"", pos2); 01553 if (pos2 == string::npos) 01554 return (false); 01555 pos2 += 2; // Advance to next field 01556 pos = logStr->find("\",", pos2); 01557 if ((pos == string::npos) || (pos2 > pos)) 01558 return (false); 01559 if (pos == pos2) 01560 log->e[i].number.erase(); 01561 else 01562 log->e[i].number = logStr->substr(pos2, pos - pos2); 01563 01564 // Date 01565 pos = logStr->find(",\"", pos); 01566 if (pos == string::npos) 01567 return (false); 01568 pos += 2; // Beginning of date field 01569 pos2 = logStr->find(",", pos); // End of timestamp field 01570 if ((pos2 == string::npos) || (pos > pos2)) 01571 return (false); 01572 if (pos == pos2) 01573 log->e[i].date.erase(); 01574 else 01575 log->e[i].date = logStr->substr(pos, pos2 - pos); 01576 01577 // Timestamp 01578 pos = logStr->find("\",", pos2); // End of timestamp 01579 if (pos == string::npos) 01580 return (false); 01581 pos2 += 1; // Beginning of time field 01582 if (pos < pos2) 01583 return (false); 01584 if (pos == pos2) 01585 log->e[i].time.erase(); 01586 else 01587 log->e[i].time = logStr->substr(pos2, pos - pos2); 01588 01589 // Message field 01590 01591 // We don't know how many messages we have so the next search 01592 // could end with +CMGL or OK. 01593 pos += 2; // Advanced to message text 01594 pos2 = logStr->find("+CMGL", pos); 01595 if (pos2 == string::npos) { 01596 pos2 = logStr->find("OK", pos); 01597 if (pos2 == string::npos) { 01598 dbgPuts("Strange SMS Log Ending!"); 01599 return (false); 01600 } 01601 i = MAX_WNC_SMS_MSG_SLOTS; // break 01602 } 01603 if (pos > pos2) 01604 return (false); 01605 if (pos == pos2) 01606 log->e[log->msgCount].msg.erase(); 01607 else 01608 log->e[log->msgCount].msg = logStr->substr(pos, pos2 - pos); 01609 01610 log->msgCount++; // Message complete 01611 } 01612 01613 return (true); 01614 } 01615 01616 bool WncController::readUnreadSMSText(struct WncSmsList * w, bool deleteRead) 01617 { 01618 struct WncController::WncSmsList tmp; 01619 01620 if (readSMSLog(&tmp) == false) 01621 return (false); 01622 01623 w->msgCount = 0; 01624 for(uint16_t i = 0; i < tmp.msgCount; i++) { 01625 if (tmp.e[i].unread == true) { 01626 w->e[w->msgCount] = tmp.e[i]; 01627 w->msgCount++; 01628 if (deleteRead == true) { 01629 // Clean up message that was copied out and read 01630 deleteSMSTextFromMem(w->e[i].idx); 01631 } 01632 } 01633 } 01634 01635 return (w->msgCount > 0); 01636 } 01637 01638 size_t WncController::getSignalQuality(const char ** log) 01639 { 01640 size_t n; 01641 01642 n = at_getSignalQuality_wnc(log); 01643 if (n == 0) 01644 dbgPuts("readSMSText: Failed!"); 01645 01646 return (n); 01647 } 01648 01649 size_t WncController::at_getSignalQuality_wnc(const char ** log) 01650 { 01651 string * pRespStr; 01652 static string logStr; 01653 01654 logStr.erase(); 01655 01656 if (at_send_wnc_cmd("AT%MEAS=\"0\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01657 logStr = *pRespStr; 01658 logStr += "\r\n"; 01659 } 01660 else 01661 dbgPuts("AT%MEAS=0: failed!"); 01662 01663 if (at_send_wnc_cmd("AT%MEAS=\"1\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01664 logStr += *pRespStr; 01665 logStr += "\r\n"; 01666 } 01667 else 01668 dbgPuts("AT%MEAS=1: failed!"); 01669 01670 if (at_send_wnc_cmd("AT%MEAS=\"2\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01671 logStr += *pRespStr; 01672 logStr += "\r\n"; 01673 } 01674 else 01675 dbgPuts("AT%MEAS=2: failed!"); 01676 01677 if (at_send_wnc_cmd("AT%MEAS=\"3\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01678 logStr += *pRespStr; 01679 logStr += "\r\n"; 01680 } 01681 else 01682 dbgPuts("AT%MEAS=3: failed!"); 01683 01684 if (at_send_wnc_cmd("AT%MEAS=\"4\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01685 logStr += *pRespStr; 01686 logStr += "\r\n"; 01687 } 01688 else 01689 dbgPuts("AT%MEAS=4: failed!"); 01690 01691 if (at_send_wnc_cmd("AT%MEAS=\"5\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01692 logStr += *pRespStr; 01693 logStr += "\r\n"; 01694 } 01695 else 01696 dbgPuts("AT%MEAS=5: failed!"); 01697 01698 if (at_send_wnc_cmd("AT%MEAS=\"8\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01699 logStr += *pRespStr; 01700 logStr += "\r\n"; 01701 } 01702 else 01703 dbgPuts("AT%MEAS=8: failed!"); 01704 01705 if (at_send_wnc_cmd("AT%MEAS=\"98\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01706 logStr += *pRespStr; 01707 logStr += "\r\n"; 01708 } 01709 else 01710 dbgPuts("AT%MEAS=98: failed!"); 01711 01712 *log = logStr.c_str(); 01713 01714 return (logStr.size()); 01715 } 01716 01717 bool WncController::getTimeDate(struct WncDateTime * tod) 01718 { 01719 if (at_gettimedate_wnc(tod) == true) 01720 return (true); 01721 else { 01722 dbgPuts("Get time date failed!"); 01723 return (false); 01724 } 01725 } 01726 01727 bool WncController::at_ping_wnc(const char * ip) 01728 { 01729 string * pRespStr; 01730 string cmdStr = "AT@PINGREQ=\""; 01731 cmdStr += ip; 01732 cmdStr += "\""; 01733 return (at_send_wnc_cmd(cmdStr.c_str(), &pRespStr, WNC_PING_CMD_TIMEOUT_MS) == WNC_AT_CMD_OK); 01734 } 01735 01736 bool WncController::at_gettimedate_wnc(struct WncDateTime * tod) 01737 { 01738 string * pRespStr; 01739 char * pEnd; 01740 01741 if (at_send_wnc_cmd("AT+CCLK?", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { 01742 if (pRespStr->size() > 0) { 01743 size_t pos1 = pRespStr->find("+CCLK:"); 01744 if (pos1 != string::npos) { 01745 pEnd = (char *)pRespStr->c_str() + pos1 + 8; 01746 tod->year = strtol(pEnd, &pEnd, 10); 01747 tod->month = strtol(pEnd+1, &pEnd, 10); 01748 tod->day = strtol(pEnd+1, &pEnd, 10); 01749 tod->hour = strtol(pEnd+1, &pEnd, 10); 01750 tod->min = strtol(pEnd+1, &pEnd, 10); 01751 tod->sec = strtol(pEnd+1, &pEnd, 10); 01752 return (true); 01753 } 01754 } 01755 } 01756 01757 return (false); 01758 } 01759 01760 bool WncController::at_get_wnc_net_stats(WncIpStats * s) 01761 { 01762 string * pRespStr; 01763 AtCmdErr_e cmdRes = at_send_wnc_cmd("AT+CGCONTRDP=1", &pRespStr, m_sCmdTimeoutMs); 01764 01765 if (WNC_AT_CMD_OK == cmdRes) { 01766 if (pRespStr->size() > 0) { 01767 memset((void*)s, '\0', sizeof(*s)); // Clean-up 01768 string ss; 01769 size_t pe; 01770 size_t ps = pRespStr->rfind("\""); 01771 if (ps != string::npos) { 01772 ps += 2; // Skip the , after the " 01773 pe = ps; 01774 01775 pe = pRespStr->find(".", pe); 01776 if (pe == string::npos) 01777 return (false); 01778 else 01779 pe += 1; 01780 pe = pRespStr->find(".", pe); 01781 if (pe == string::npos) 01782 return (false); 01783 else 01784 pe += 1; 01785 pe = pRespStr->find(".", pe); 01786 if (pe == string::npos) 01787 return (false); 01788 else 01789 pe += 1; 01790 pe = pRespStr->find(".", pe); 01791 if (pe == string::npos) 01792 return (false); 01793 else 01794 pe += 1; 01795 01796 ss = pRespStr->substr(ps, pe - 1 - ps); 01797 strncpy(s->ip, ss.c_str(), MAX_LEN_IP_STR); 01798 s->ip[MAX_LEN_IP_STR - 1] = '\0'; 01799 ps = pe; 01800 01801 pe = pRespStr->find(".", pe); 01802 if (pe == string::npos) 01803 return (false); 01804 else 01805 pe += 1; 01806 pe = pRespStr->find(".", pe); 01807 if (pe == string::npos) 01808 return (false); 01809 else 01810 pe += 1; 01811 pe = pRespStr->find(".", pe); 01812 if (pe == string::npos) 01813 return (false); 01814 else 01815 pe += 1; 01816 pe = pRespStr->find(",", pe); 01817 01818 ss = pRespStr->substr(ps, pe - ps); 01819 strncpy(s->mask, ss.c_str(), MAX_LEN_IP_STR); 01820 s->mask[MAX_LEN_IP_STR - 1] = '\0'; 01821 ps = pe + 1; 01822 01823 pe = pRespStr->find(".", pe); 01824 if (pe == string::npos) 01825 return (false); 01826 else 01827 pe += 1; 01828 pe = pRespStr->find(".", pe); 01829 if (pe == string::npos) 01830 return (false); 01831 else 01832 pe += 1; 01833 pe = pRespStr->find(".", pe); 01834 if (pe == string::npos) 01835 return (false); 01836 else 01837 pe += 1; 01838 pe = pRespStr->find(",", pe); 01839 01840 ss = pRespStr->substr(ps, pe - ps); 01841 strncpy(s->gateway, ss.c_str(), MAX_LEN_IP_STR); 01842 s->gateway[MAX_LEN_IP_STR - 1] = '\0'; 01843 ps = pe + 1; 01844 01845 pe = pRespStr->find(".", pe); 01846 if (pe == string::npos) 01847 return (false); 01848 else 01849 pe += 1; 01850 pe = pRespStr->find(".", pe); 01851 if (pe == string::npos) 01852 return (false); 01853 else 01854 pe += 1; 01855 pe = pRespStr->find(".", pe); 01856 if (pe == string::npos) 01857 return (false); 01858 else 01859 pe += 1; 01860 pe = pRespStr->find(",", pe); 01861 01862 01863 ss = pRespStr->substr(ps, pe - ps); 01864 strncpy(s->dnsPrimary, ss.c_str(), MAX_LEN_IP_STR); 01865 s->dnsPrimary[MAX_LEN_IP_STR - 1] = '\0'; 01866 ps = pe + 1; 01867 01868 pe = pRespStr->find(".", pe); 01869 if (pe == string::npos) 01870 return (false); 01871 else 01872 pe += 1; 01873 pe = pRespStr->find(".", pe); 01874 if (pe == string::npos) 01875 return (false); 01876 else 01877 pe += 1; 01878 pe = pRespStr->find(".", pe); 01879 if (pe == string::npos) 01880 return (false); 01881 else 01882 pe += 1; 01883 pe = pRespStr->find(",", pe); 01884 01885 01886 ss = pRespStr->substr(ps, pe - ps); 01887 strncpy(s->dnsSecondary, ss.c_str(), MAX_LEN_IP_STR); 01888 s->dnsSecondary[MAX_LEN_IP_STR - 1] = '\0'; 01889 01890 dbgPuts("~~~~~~~~~~ WNC IP Stats ~~~~~~~~~~~~"); 01891 dbgPuts("ip: ", false); dbgPutsNoTime(s->ip); 01892 dbgPuts("mask: ", false); dbgPutsNoTime(s->mask); 01893 dbgPuts("gateway: ", false); dbgPutsNoTime(s->gateway); 01894 dbgPuts("dns pri: ", false); dbgPutsNoTime(s->dnsPrimary); 01895 dbgPuts("dns sec: ", false); dbgPutsNoTime(s->dnsSecondary); 01896 dbgPuts("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 01897 01898 return (true); 01899 } 01900 } 01901 } 01902 01903 return (false); 01904 } 01905 01906 bool WncController::deleteSMSTextFromMem(char msgIdx) 01907 { 01908 const char * err = "deleteSMSTextFromMem: Failed!"; 01909 01910 switch (msgIdx) 01911 { 01912 case '*': 01913 at_deleteSMSTextFromMem_wnc('1'); 01914 at_deleteSMSTextFromMem_wnc('2'); 01915 at_deleteSMSTextFromMem_wnc('3'); 01916 return (true); // WNC may error if slot empty, just ignore! 01917 01918 case '1': 01919 case '2': 01920 case '3': 01921 if (true == at_deleteSMSTextFromMem_wnc(msgIdx)) 01922 return (true); 01923 else { 01924 dbgPuts(err); 01925 return (false); 01926 } 01927 01928 default: 01929 dbgPuts(err); 01930 return (false); 01931 } 01932 } 01933 01934 bool WncController::sendSMSTextFromMem(char msgIdx) 01935 { 01936 const char * err = "deleteSMSTextFromMem: Failed!"; 01937 01938 switch (msgIdx) 01939 { 01940 case '*': 01941 at_sendSMStextMem_wnc('1'); 01942 at_sendSMStextMem_wnc('2'); 01943 at_sendSMStextMem_wnc('3'); 01944 return (true); // WNC may error if slot is empty, just ignore! 01945 01946 case '1': 01947 case '2': 01948 case '3': 01949 if (at_sendSMStextMem_wnc(msgIdx) == true) 01950 return (true); 01951 else { 01952 dbgPuts(err); 01953 return (false); 01954 } 01955 01956 default: 01957 dbgPuts(err); 01958 return (false); 01959 } 01960 } 01961 01962 bool WncController::at_deleteSMSTextFromMem_wnc(char n) 01963 { 01964 string cmdStr, respStr; 01965 // Message is stored in WNC, now send it! 01966 cmdStr = "AT+CMGD="; 01967 cmdStr += n; 01968 cmdStr += "\r\n"; 01969 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); 01970 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); 01971 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01972 return (r == WNC_AT_CMD_OK); 01973 } 01974 01975 bool WncController::at_sendSMStextMem_wnc(char n) 01976 { 01977 string cmdStr, respStr; 01978 // Message is stored in WNC, now send it! 01979 cmdStr = "AT+CMSS="; 01980 cmdStr += n; 01981 cmdStr += "\r\n"; 01982 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); 01983 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); 01984 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 01985 return (r == WNC_AT_CMD_OK); 01986 } 01987 01988 bool WncController::at_sendSMStext_wnc(const char * const phoneNum, const char * const text) 01989 { 01990 string respStr; 01991 string * pRespStr; 01992 size_t l = strlen(text); 01993 01994 if (l <= MAX_WNC_SMS_LENGTH) 01995 { 01996 // Check to see if the SMS service is available 01997 checkCellLink(); 01998 if (m_sReadyForSMS == true) { 01999 at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); 02000 string cmdStr("AT+CMGS=\""); 02001 cmdStr += phoneNum; 02002 cmdStr += "\""; 02003 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 02004 cmdStr += "\x0d"; // x0d = <ENTER> 02005 // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! 02006 // And we want a delay before sending the actual text part of the string! 02007 mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) 02008 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 02009 if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { 02010 // Part 2 of the text, this is the actual text part: 02011 cmdStr = text; 02012 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 02013 cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to send! 02014 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); 02015 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 02016 if (respStr.size() == 0) 02017 return (false); 02018 else 02019 return (r == WNC_AT_CMD_OK); 02020 } 02021 } 02022 } 02023 02024 return (false); 02025 } 02026 02027 bool WncController::saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx) 02028 { 02029 if (at_saveSMStext_wnc(phoneNum, text, msgIdx) == true) 02030 return (true); 02031 else { 02032 dbgPuts("saveSMSTextToMem: failed!\r\n"); 02033 return (false); 02034 } 02035 } 02036 02037 bool WncController::at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx) 02038 { 02039 string respStr; 02040 size_t l = strlen(text); 02041 02042 if (l <= MAX_WNC_SMS_LENGTH) 02043 { 02044 // Check to see if the SMS service is available 02045 checkCellLink(); 02046 if (m_sReadyForSMS == true) { 02047 string cmdStr("AT+CMGW=\""); 02048 cmdStr += phoneNum; 02049 cmdStr += "\""; 02050 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 02051 cmdStr += "\x0d"; // x0d = <ENTER> 02052 // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! 02053 // And we want a delay before sending the actual text part of the string! 02054 mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) 02055 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 02056 if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { 02057 // Part 2 of the text, this is the actual text part: 02058 cmdStr = text; 02059 dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); 02060 cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to save! 02061 AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); 02062 dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); 02063 if (respStr.size() > 0) { 02064 // respStr will have the SMS index 02065 size_t pos1 = respStr.find("+CMGW: "); 02066 size_t pos2 = respStr.rfind("OK"); 02067 if (pos1 != string::npos && pos2 != string::npos) { 02068 *msgIdx = *string(respStr.substr(pos1+7, 1)).c_str(); 02069 return (true); 02070 } 02071 else { 02072 *msgIdx = '!'; 02073 } 02074 } 02075 } 02076 } 02077 } 02078 02079 return (false); 02080 } 02081 02082 bool WncController::at_readSMSlog_wnc(string ** log) 02083 { 02084 return (at_send_wnc_cmd("AT+CMGL", log, m_sCmdTimeoutMs) == WNC_AT_CMD_OK); 02085 } 02086 02087 size_t WncController::at_readSMStext_wnc(const char n, const char ** log) 02088 { 02089 static string smsReadTxtStr; 02090 string * pRespStr; 02091 string cmdStr; 02092 02093 smsReadTxtStr.erase(); 02094 cmdStr = "AT+CMGR"; 02095 cmdStr += '1'; 02096 if (at_send_wnc_cmd("AT+CMGR", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) 02097 *log = pRespStr->c_str(); 02098 else 02099 *log = "\0"; 02100 02101 return (pRespStr->size()); 02102 } 02103 02104 bool WncController::at_at_wnc(void) 02105 { 02106 string * pRespStr; 02107 return (WNC_AT_CMD_OK == at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS)); // Heartbeat? 02108 } 02109 02110 bool WncController::at_init_wnc(bool hardReset) 02111 { 02112 string * pRespStr; 02113 AtCmdErr_e cmdRes; 02114 02115 if (hardReset == true) 02116 dbgPuts("Hard Soft Reset!"); 02117 02118 dbgPuts("Start AT init of WNC:"); 02119 02120 // Kick it twice to perhaps remove cued responses from an incomplete 02121 // power cycle. 02122 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 02123 at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); 02124 02125 // Dump the firmware revision on the debug log: 02126 at_send_wnc_cmd("AT+GMR", &pRespStr, m_sCmdTimeoutMs); 02127 02128 // Quick commands below do not need to check cellular connectivity 02129 at_send_wnc_cmd("ATE0", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Echo Off 02130 at_send_wnc_cmd("AT+CMEE=2", &pRespStr, m_sCmdTimeoutMs); // 2 - verbose error, 1 - numeric error, 0 - just ERROR 02131 02132 // Setup 3 memory slots in the WNC SIM for SMS usage. 02133 at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); 02134 at_send_wnc_cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", &pRespStr, m_sCmdTimeoutMs); 02135 02136 cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Heartbeat? 02137 02138 // If the simple commands are not working, no chance of more complex. 02139 // I have seen re-trying commands make it worse. 02140 if (cmdRes != WNC_AT_CMD_OK) 02141 return (false); 02142 02143 cmdRes = at_send_wnc_cmd("AT@INTERNET=1", &pRespStr, m_sCmdTimeoutMs); 02144 if (cmdRes != WNC_AT_CMD_OK) 02145 return (false); 02146 02147 cmdRes = at_send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, m_sCmdTimeoutMs); 02148 if (cmdRes != WNC_AT_CMD_OK) 02149 return (false); 02150 02151 dbgPuts("SUCCESS: AT init of WNC!"); 02152 02153 return (true); 02154 } 02155 02156 02157 int16_t WncController::at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec) 02158 { 02159 string * pRespStr; 02160 string cmd_str("AT@SOCKCREAT="); 02161 AtCmdErr_e res; 02162 02163 if (tcp) cmd_str += "1"; // TCP 02164 else cmd_str += "2"; // else UDP 02165 02166 cmd_str += ",0"; 02167 res = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02168 if (res == WNC_AT_CMD_OK && pRespStr->size() > 0) 02169 { 02170 size_t pos1 = pRespStr->find("T:"); 02171 size_t pos2 = pRespStr->rfind("OK"); 02172 if ((pos1 != string::npos) && (pos2 != string::npos)) { 02173 size_t numLen = pos2 - (pos1 + 2); 02174 string sockStr = pRespStr->substr(pos1 + 2, numLen); 02175 cmd_str = "AT@SOCKCONN="; 02176 cmd_str += sockStr; 02177 cmd_str += ",\""; 02178 cmd_str += ip; 02179 cmd_str += "\","; 02180 cmd_str += _to_string(port); 02181 cmd_str += ","; 02182 if (timeOutSec < 30) 02183 timeOutSec = 30; 02184 else if (timeOutSec > 360) 02185 timeOutSec = 360; 02186 cmd_str += _to_string(timeOutSec); 02187 res = sendWncCmd(cmd_str.c_str(), &pRespStr, 1000 * timeOutSec + 1000); 02188 if (m_sMoreDebugEnabled) { 02189 at_send_wnc_cmd("AT@SOCKCREAT?", &pRespStr, m_sCmdTimeoutMs); 02190 at_send_wnc_cmd("AT@SOCKCONN?", &pRespStr, m_sCmdTimeoutMs); 02191 } 02192 return (strtol(sockStr.c_str(), NULL, 10)); 02193 } 02194 else { 02195 dbgPuts("Invalid sockcreat response!"); 02196 return (0); 02197 } 02198 } 02199 else 02200 return (0); 02201 } 02202 02203 bool WncController::at_sockclose_wnc(uint16_t numSock) 02204 { 02205 string * pRespStr; 02206 string cmd_str("AT@SOCKCLOSE="); 02207 02208 cmd_str += _to_string(numSock); 02209 02210 // Don't check the cell status to close the socket 02211 AtCmdErr_e res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02212 02213 if ((res != WNC_AT_CMD_TIMEOUT) && (res != WNC_AT_CMD_OK)) { 02214 for (unsigned i = 0; i < WNC_SOCK_CLOSE_RETRY_CNT; i++) { 02215 res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02216 if ((res == WNC_AT_CMD_TIMEOUT) || (res == WNC_AT_CMD_OK)) 02217 break; 02218 } 02219 } 02220 02221 return (res == WNC_AT_CMD_OK); 02222 } 02223 02224 bool WncController::at_dnsresolve_wnc(const char * s, string * ipStr) 02225 { 02226 string * pRespStr; 02227 string str(s); 02228 AtCmdErr_e r; 02229 02230 ipStr->erase(); // Clear out string until resolved! 02231 str = "AT@DNSRESVDON=\"" + str; 02232 str += "\""; 02233 r = sendWncCmd(str.c_str(), &pRespStr, WNC_DNS_RESOLVE_WAIT_MS); 02234 if (r == WNC_AT_CMD_OK && pRespStr->size() > 0) { 02235 size_t pos_start = pRespStr->find(":\"") + 2; 02236 if (pos_start != string::npos) { 02237 size_t pos_end = pRespStr->find("\"", pos_start) - 1; 02238 if (pos_end != string::npos) { 02239 if (pos_end > pos_start) { 02240 // Make a copy for use later (the source string is re-used) 02241 *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1); 02242 return (true); 02243 } 02244 } 02245 } 02246 } 02247 02248 *ipStr = INVALID_IP_STR; 02249 02250 return (false); 02251 } 02252 02253 bool WncController::waitForPowerOnModemToRespond(uint8_t timeoutSecs) 02254 { 02255 // Now, give the modem x seconds to start responding by 02256 // sending simple 'AT' commands to modem once per second. 02257 if (timeoutSecs > 0) { 02258 do { 02259 timeoutSecs--; 02260 dbgPutsNoTime("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 02261 dbgPutsNoTime(" ", false); 02262 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 02263 if (rc == WNC_AT_CMD_OK) { 02264 dbgPutsNoTime(""); // CR LF 02265 return true; //timer.read(); 02266 } 02267 waitMs(500); 02268 } 02269 while (timeoutSecs > 0); 02270 dbgPutsNoTime(""); // CR LF 02271 } 02272 02273 return (false); 02274 } 02275 02276 WncController::AtCmdErr_e WncController::at_sockwrite_wnc(const char * s, uint16_t n, uint16_t numSock, bool isTcp) 02277 { 02278 AtCmdErr_e result; 02279 02280 if ((n > 0) && (n <= MAX_WNC_WRITE_BYTES)) { 02281 string * pRespStr; 02282 const char * num2str; 02283 string cmd_str; 02284 02285 if (isTcp == true) 02286 cmd_str="AT@SOCKWRITE="; 02287 else 02288 cmd_str="AT@SOCKWRITE="; // "AT@SOCKSEND="; 02289 02290 cmd_str += _to_string(numSock); 02291 cmd_str += ","; 02292 cmd_str += _to_string(n); 02293 cmd_str += ",\""; 02294 while(n > 0) { 02295 n--; 02296 num2str = _to_hex_string((uint8_t)*s++); 02297 // Always 2-digit ascii hex: 02298 if (num2str[1] == '\0') 02299 cmd_str += '0'; 02300 cmd_str += num2str; 02301 } 02302 cmd_str += "\""; 02303 result = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02304 } 02305 else { 02306 dbgPuts("sockwrite Err, string len bad!"); 02307 result = WNC_AT_CMD_ERR; 02308 } 02309 02310 return (result); 02311 } 02312 02313 WncController::AtCmdErr_e WncController::at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp) 02314 { 02315 AtCmdErr_e result = WNC_AT_CMD_OK; 02316 02317 string * pRespStr; 02318 string cmd_str; 02319 size_t pos_start, pos_end; 02320 int i; 02321 02322 pS->erase(); // Start with a fresh string 02323 02324 if (isTcp == true) 02325 cmd_str="AT@SOCKREAD="; 02326 else 02327 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 02328 02329 cmd_str += _to_string(numSock); 02330 cmd_str += ","; 02331 cmd_str += _to_string(MAX_WNC_READ_BYTES); 02332 02333 // Experimental: read should not need to check cell net status 02334 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02335 if (result == WNC_AT_CMD_OK) { 02336 if (pRespStr->size() > 0) { 02337 pos_start = pRespStr->find("\""); 02338 pos_end = pRespStr->rfind("\""); 02339 // Make sure search finds what it's looking for! 02340 if (pos_start != string::npos && pos_end != string::npos) { 02341 pos_start++; 02342 i = pos_end - pos_start; // Num hex chars, 2 per byte 02343 } 02344 else 02345 i = 0; 02346 } 02347 else 02348 i = 0; 02349 02350 if ((i < 0) || ((i % 2) == 1)) 02351 dbgPuts("Invalid READ string!"); 02352 02353 if (i > 2*MAX_WNC_READ_BYTES) { 02354 i = 2*MAX_WNC_READ_BYTES; 02355 dbgPuts("DANGER WNC read data does not match length!"); 02356 } 02357 02358 // If data, convert the hex string into byte values 02359 while (i > 0) { 02360 i -= 2; 02361 *pS += (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 02362 pos_start += 2; 02363 } 02364 } 02365 02366 return (result); 02367 } 02368 02369 WncController::AtCmdErr_e WncController::at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp) 02370 { 02371 AtCmdErr_e result = WNC_AT_CMD_OK; 02372 *numRead = 0; 02373 02374 if ((n > 0) && (n <= MAX_WNC_READ_BYTES)) { 02375 string * pRespStr; 02376 string cmd_str; 02377 size_t pos_start, pos_end; 02378 int i; 02379 02380 if (isTcp == true) 02381 cmd_str="AT@SOCKREAD="; 02382 else 02383 cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; 02384 02385 cmd_str += _to_string(numSock); 02386 cmd_str += ","; 02387 cmd_str += _to_string(n); 02388 02389 // Experimental: read should not need to check cell net status 02390 result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); 02391 if (result == WNC_AT_CMD_OK) { 02392 if (pRespStr->size() > 0) { 02393 pos_start = pRespStr->find("\""); 02394 pos_end = pRespStr->rfind("\""); 02395 // Make sure search finds what it's looking for! 02396 if (pos_start != string::npos && pos_end != string::npos) { 02397 pos_start++; 02398 i = pos_end - pos_start; // Num hex chars, 2 per byte 02399 } 02400 else 02401 i = 0; 02402 } 02403 else 02404 i = 0; 02405 02406 if ((i < 0) || ((i % 2) == 1)) 02407 dbgPuts("Invalid READ string!"); 02408 02409 if (i > 2*n) { 02410 // Bound the ill formated WNC read string! 02411 i = 2*n; 02412 dbgPuts("TRUNCATING read data!"); 02413 } 02414 02415 // If data, convert the hex string into byte values 02416 i /= 2; 02417 *numRead = i; 02418 while (i > 0) { 02419 i--; 02420 *pS++ = (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); 02421 pos_start += 2; 02422 } 02423 } 02424 } 02425 else { 02426 dbgPuts("sockread Err, to many to read!"); 02427 result = WNC_AT_CMD_ERR; 02428 } 02429 02430 return (result); 02431 } 02432 02433 bool WncController::at_reinitialize_mdm(void) 02434 { 02435 // Atempt to re-register 02436 // string * pRespStr; 02437 // dbgPuts("Force re-register!"); 02438 // at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, m_sCmdTimeoutMs); 02439 // waitMs(31000); 02440 // at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, m_sCmdTimeoutMs); 02441 // waitMs(31000); 02442 02443 // Initialize the modem 02444 dbgPuts("Modem RE-initializing with SOFT Reset..."); 02445 02446 string * pRespStr; 02447 at_send_wnc_cmd("AT@DMREBOOT", &pRespStr, m_sCmdTimeoutMs); 02448 waitMs(5000); 02449 02450 // Now, give the modem time to start responding by 02451 // sending simple 'AT' commands to the modem once per second. 02452 int timeoutSecs = WNC_REINIT_MAX_TIME_MS; 02453 do { 02454 dbgPuts("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); 02455 AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); 02456 if (rc == WNC_AT_CMD_OK) { 02457 dbgPutsNoTime(""); // CR LF 02458 break; 02459 } 02460 waitMs(500); 02461 timeoutSecs--; 02462 } 02463 while (timeoutSecs > 0); 02464 02465 if (timeoutSecs <= 0) 02466 dbgPuts("\r\nModem RE-init FAILED!"); 02467 else 02468 dbgPuts("\r\nModem RE-init complete!"); 02469 02470 return (timeoutSecs > 0); 02471 } 02472 02473 WncController::AtCmdErr_e WncController::mdmSendAtCmdRsp(const char *cmd, int timeout_ms, string * rsp, bool crLf) 02474 { 02475 rsp->erase(); // Clean up from possible prior cmd response 02476 02477 // Don't bother the WNC if user hasn't turned it on. 02478 if (m_sState == WNC_OFF) 02479 return (WNC_AT_CMD_WNC_NOT_ON); 02480 02481 size_t n = strlen(cmd); 02482 02483 // Wait per WNC advise 02484 waitMs(WNC_WAIT_FOR_AT_CMD_MS); 02485 02486 if (cmd && n > 0) { 02487 sendCmd(cmd, crLf); 02488 // sendCmd(cmd, n, 1000, crLf); // 3rd arg is micro seconds between chars sent 02489 } 02490 02491 startTimerA(); 02492 while (getTimerTicksA_mS() < timeout_ms) { 02493 n = mdmGetline(rsp, timeout_ms - getTimerTicksA_mS()); 02494 02495 if (n == 0) 02496 continue; 02497 02498 if (rsp->rfind("OK") != string::npos) { 02499 stopTimerA(); 02500 return (WNC_AT_CMD_OK); 02501 } 02502 02503 if (rsp->rfind("+CME ERROR") != string::npos) { 02504 stopTimerA(); 02505 return (WNC_AT_CMD_ERRCME); 02506 } 02507 02508 if (rsp->rfind("@EXTERR") != string::npos) { 02509 stopTimerA(); 02510 return (WNC_AT_CMD_ERREXT); 02511 } 02512 02513 if (rsp->rfind("ERROR") != string::npos) { 02514 stopTimerA(); 02515 return (WNC_AT_CMD_ERR); 02516 } 02517 } 02518 stopTimerA(); 02519 02520 return (WNC_AT_CMD_TIMEOUT); 02521 } 02522 02523 bool WncController::at_setapn_wnc(const char * const apnStr) 02524 { 02525 string * pRespStr; 02526 02527 string cmd_str("AT%PDNSET=1,"); 02528 cmd_str += apnStr; 02529 cmd_str += ",IP"; 02530 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 02531 return (true); 02532 else 02533 return (false); 02534 } 02535 02536 bool WncController::at_getrssiber_wnc(int16_t * dBm, int16_t * ber) 02537 { 02538 string * pRespStr; 02539 AtCmdErr_e cmdRes; 02540 cmdRes = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 02541 if (cmdRes != WNC_AT_CMD_OK) 02542 return (false); 02543 02544 if (pRespStr->size() == 0) { 02545 dbgPuts("Strange RSSI result!"); 02546 return (false); 02547 } 02548 else { 02549 size_t pos1 = pRespStr->find("SQ:"); 02550 size_t pos2 = pRespStr->rfind(","); 02551 // Sanity check 02552 if ((pos1 != string::npos) && (pos2 != string::npos) && (pos2 > pos1)) { 02553 string subStr = pRespStr->substr(pos1 + 4, pos2 - pos1 ); 02554 int rawRssi = atoi(subStr.c_str()); 02555 02556 // Convert WNC RSSI into dBm range: 02557 // 0 - -113 dBm 02558 // 1 - -111 dBm 02559 // 2..30 - -109 to -53 dBm 02560 // 31 - -51dBm or > 02561 // 99 - not known or not detectable 02562 if (rawRssi == 99) 02563 *dBm = -199; 02564 else if (rawRssi == 0) 02565 *dBm = -113; 02566 else if (rawRssi == 1) 02567 *dBm = -111; 02568 else if (rawRssi == 31) 02569 *dBm = -51; 02570 else if (rawRssi >= 2 && rawRssi <= 30) 02571 *dBm = -113 + 2 * rawRssi; 02572 else { 02573 dbgPuts("Invalid RSSI!"); 02574 return (false); 02575 } 02576 // Parse out BER: 0..7 as RXQUAL values in the table 3GPP TS 45.008 subclause 8.2.4 02577 // 99 - unknown or undetectable 02578 subStr = pRespStr->substr(pos2 + 1, pRespStr->length() - (pos2 + 1)); 02579 *ber = atoi(subStr.c_str()); 02580 } 02581 else { 02582 dbgPuts("Strange RSSI result2!"); 02583 return (false); 02584 } 02585 } 02586 02587 return (true); 02588 } 02589 02590 bool WncController::checkCellLink(void) 02591 { 02592 string * pRespStr; 02593 size_t pos; 02594 int regSts; 02595 int cmdRes1, cmdRes2; 02596 02597 if (m_sState == WNC_OFF) 02598 return (false); 02599 02600 m_sState = WNC_ON_NO_CELL_LINK; 02601 02602 if (m_sMoreDebugEnabled) 02603 dbgPuts("<-------- Begin Cell Status ------------"); 02604 02605 cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER 02606 02607 // If no response, don't bother with more commands 02608 if (cmdRes1 != WNC_AT_CMD_TIMEOUT) 02609 cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, m_sCmdTimeoutMs); // Check if SIM locked 02610 else { 02611 if (m_sMoreDebugEnabled) 02612 dbgPuts("------------ WNC No Response! --------->"); 02613 02614 return (false); 02615 } 02616 02617 if ((cmdRes1 != WNC_AT_CMD_OK) || (cmdRes2 != WNC_AT_CMD_OK) || (pRespStr->size() == 0)) 02618 { 02619 if (m_sMoreDebugEnabled) 02620 { 02621 if ((cmdRes1 == WNC_AT_CMD_TIMEOUT) || (cmdRes2 == WNC_AT_CMD_TIMEOUT)) 02622 dbgPuts("------------ WNC No Response! --------->"); 02623 else 02624 dbgPuts("------------ WNC Cmd Error! ----------->"); 02625 } 02626 02627 // If by a miracle it responds to the 2nd after the 1st, keep going 02628 if ((cmdRes2 == WNC_AT_CMD_TIMEOUT) || (pRespStr->size() == 0)) 02629 return (false); 02630 } 02631 02632 // If SIM Card not ready don't bother with commands! 02633 if (pRespStr->find("CPIN: READY") == string::npos) 02634 { 02635 if (m_sMoreDebugEnabled) 02636 dbgPuts("------------ WNC SIM Problem! --------->"); 02637 02638 return (false); 02639 } 02640 02641 // SIM card OK, now check for signal and cellular network registration 02642 cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, m_sCmdTimeoutMs); // Check if registered on network 02643 if (cmdRes1 != WNC_AT_CMD_OK || pRespStr->size() == 0) 02644 { 02645 if (m_sMoreDebugEnabled) 02646 dbgPuts("------------ WNC +CREG? Fail! --------->"); 02647 02648 return (false); 02649 } 02650 else 02651 { 02652 pos = pRespStr->find("CREG: "); 02653 if (pos != string::npos) 02654 { 02655 // The registration is the 2nd arg in the comma separated list 02656 *pRespStr = pRespStr->substr(pos+8, 1); 02657 regSts = atoi(pRespStr->c_str()); 02658 switch (regSts) { 02659 case 1: 02660 case 5: 02661 case 6: 02662 case 7: 02663 m_sReadyForSMS = true; 02664 break; 02665 default: 02666 m_sReadyForSMS = false; 02667 dbgPuts("SMS Service Down!"); 02668 } 02669 02670 // 1 - registered home, 5 - registered roaming 02671 if ((regSts != 1) && (regSts != 5)) 02672 { 02673 if (m_sMoreDebugEnabled) 02674 dbgPuts("------ WNC Cell Link Down for Data! --->"); 02675 02676 return (false); 02677 } 02678 } 02679 02680 if (m_sMoreDebugEnabled) 02681 dbgPuts("------------ WNC Ready ---------------->"); 02682 } 02683 02684 // If we made it this far and the WNC did respond, keep the ON state 02685 if (m_sState != WNC_NO_RESPONSE) 02686 m_sState = WNC_ON; 02687 02688 return (true); 02689 } 02690 02691 int WncController::dbgPutsNoTime(const char * s, bool crlf) 02692 { 02693 if (m_sDebugEnabled == true) { 02694 int r = dbgWriteChars(s); 02695 if (crlf == true) 02696 return (dbgWriteChars("\r\n")); 02697 else 02698 return (r); 02699 } 02700 else 02701 return 0; 02702 }; 02703 02704 int WncController::dbgPuts(const char * s, bool crlf) 02705 { 02706 dbgPutsNoTime("[*] ", false); 02707 dbgPutsNoTime(_to_string(getLogTimerTicks()), false); 02708 dbgPutsNoTime(" ", false); 02709 02710 int r = dbgPutsNoTime(s, false); 02711 02712 if (crlf == true) 02713 return (dbgPutsNoTime("", true)); 02714 else 02715 return (r); 02716 }; 02717 02718 void WncController::sendCmd(const char * cmd, bool crLf) 02719 { 02720 puts(cmd); 02721 if (crLf == true) 02722 puts("\r\n"); 02723 } 02724 02725 // WNC used to have troubles handling full speed, seems to not need this now. 02726 void WncController::sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf) 02727 { 02728 while (n--) { 02729 putc(*cmd++); 02730 waitUs(wait_uS); 02731 }; 02732 if (crLf == true) { 02733 putc('\r'); 02734 waitUs(wait_uS); 02735 putc('\n'); 02736 waitUs(wait_uS); 02737 } 02738 } 02739 02740 02741 }; // End namespace WncController_fk 02742
Generated on Tue Jul 12 2022 14:16:20 by 1.7.2