V.06 11/3

Dependencies:   FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts

Fork of ATT_AWS_IoT_demo by attiot

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 
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