This library controls the WNC. There is a derived class for usage from the K64F board.

Fork of WncControllerLibrary by Fred Kellerman

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WncController.cpp Source File

WncController.cpp

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