support library for C027 helper functions for Buffer Pipes, Buffered Serial Port (rtos capable) and GPS parsing. It includes modem APIs for USSD, SMS and Sockets.

Dependents:   HTTPClient_Cellular_HelloWorld Cellular_HelloMQTT MbedSmartRestMain Car_Bon_car_module ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MDM.cpp Source File

MDM.cpp

00001 #include "mbed.h"
00002 #include "MDM.h"
00003 #ifdef TARGET_UBLOX_C027
00004  #include "C027_api.h"
00005 #endif
00006 #include "MDMAPN.h"
00007         
00008 #define PROFILE         "0"   //!< this is the psd profile used
00009 #define MAX_SIZE        128   //!< max expected messages
00010 // num sockets
00011 #define NUMSOCKETS      (sizeof(_sockets)/sizeof(*_sockets))
00012 //! test if it is a socket is ok to use
00013 #define ISSOCKET(s)     (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR))
00014 //! check for timeout
00015 #define TIMEOUT(t, ms)  ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 
00016 // num HTTP profiles
00017 #define NUMPROFILES      (sizeof(_httpProfiles)/sizeof(*_httpProfiles))
00018 //! test if it is an HTTP profile is ok to use
00019 #define ISPROFILE(p)     (((p) >= 0) && ((p) < NUMPROFILES) && (_httpProfiles[p].handle != HTTP_PROF_ERROR))
00020 //! registration ok check helper
00021 #define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
00022 //! registration done check helper (no need to poll further)
00023 #define REG_DONE(r)     ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 
00024 //! helper to make sure that lock unlock pair is always balaced 
00025 #define LOCK()         { lock() 
00026 //! helper to make sure that lock unlock pair is always balaced 
00027 #define UNLOCK()       } unlock()
00028 
00029 #ifdef MDM_DEBUG
00030  #if 1 // colored terminal output using ANSI escape sequences
00031   #define COL(c) "\033[" c
00032  #else
00033   #define COL(c) 
00034  #endif
00035  #define DEF COL("39m")
00036  #define BLA COL("30m")
00037  #define RED COL("31m")
00038  #define GRE COL("32m")
00039  #define YEL COL("33m")
00040  #define BLU COL("34m")
00041  #define MAG COL("35m")
00042  #define CYA COL("36m")
00043  #define WHY COL("37m")
00044  
00045 void dumpAtCmd(const char* buf, int len)
00046 {
00047     ::printf(" %3d \"", len);
00048     while (len --) {
00049         char ch = *buf++;
00050         if ((ch > 0x1F) && (ch != 0x7F)) { // is printable
00051             if      (ch == '%')  ::printf("%%");
00052             else if (ch == '"')  ::printf("\\\"");
00053             else if (ch == '\\') ::printf("\\\\");
00054             else putchar(ch);
00055         } else {
00056             if      (ch == '\a') ::printf("\\a"); // BEL (0x07)
00057             else if (ch == '\b') ::printf("\\b"); // Backspace (0x08)
00058             else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09)
00059             else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A)
00060             else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B)
00061             else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C)
00062             else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D)
00063             else                 ::printf("\\x%02x", (unsigned char)ch);
00064         }
00065     }
00066     ::printf("\"\r\n");
00067 }
00068  
00069 void MDMParser::_debugPrint(int level, const char* color, const char* format, ...)
00070 {
00071     if (_debugLevel >= level) 
00072     {
00073         va_list args;
00074         va_start (args, format);
00075         if (color) ::printf(color);
00076         ::vprintf(format, args);
00077         if (color) ::printf(DEF);
00078         va_end (args);
00079     }
00080 }
00081    
00082  #define ERROR(...)     _debugPrint(0, RED, __VA_ARGS__)
00083  #define INFO(...)      _debugPrint(1, GRE, __VA_ARGS__)
00084  #define TRACE(...)     _debugPrint(2, DEF, __VA_ARGS__)
00085  #define TEST(...)      _debugPrint(3, CYA, __VA_ARGS__)
00086  
00087 #else
00088  
00089  #define ERROR(...) (void)0 // no tracing
00090  #define TEST(...)  (void)0 // no tracing
00091  #define INFO(...)  (void)0 // no tracing
00092  #define TRACE(...) (void)0 // no tracing
00093 
00094 #endif
00095 
00096 MDMParser* MDMParser::inst;
00097 
00098 MDMParser::MDMParser(void)
00099 {
00100     inst = this;
00101     memset(&_dev, 0, sizeof(_dev));
00102     memset(&_net, 0, sizeof(_net));
00103     _net.lac = 0xFFFF;
00104     _net.ci = 0xFFFFFFFF;
00105     _ip        = NOIP;
00106     _init      = false;
00107     memset(_sockets, 0, sizeof(_sockets));
00108     for (int socket = 0; socket < NUMSOCKETS; socket ++)
00109         _sockets[socket].handle = SOCKET_ERROR;
00110     memset(_httpProfiles, 0, sizeof(_httpProfiles));
00111     for (int profile = 0; profile < NUMPROFILES; profile ++)
00112         _httpProfiles[profile].handle = HTTP_PROF_ERROR;
00113 #ifdef MDM_DEBUG
00114     _debugLevel = 1;
00115     _debugTime.start();
00116 #endif
00117 }
00118 
00119 int MDMParser::send(const char* buf, int len)
00120 {
00121 #ifdef MDM_DEBUG
00122     if (_debugLevel >= 3) {
00123         ::printf("%10.3f AT send    ", _debugTime.read_ms()*0.001);
00124         dumpAtCmd(buf,len);
00125     }
00126 #endif
00127     return _send(buf, len);
00128 }
00129 
00130 int MDMParser::sendFormated(const char* format, ...) {
00131     char buf[MAX_SIZE];
00132     va_list args;
00133     va_start(args, format);
00134     int len = vsnprintf(buf,sizeof(buf), format, args);
00135     va_end(args);
00136     return send(buf, len);
00137 }
00138 
00139 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/, 
00140                              void* param /* = NULL*/, 
00141                              int timeout_ms /*= 5000*/)
00142 {
00143     char buf[MAX_SIZE + 64 /* add some more space for framing */]; 
00144     Timer timer;
00145     timer.start();
00146     do {
00147         int ret = getLine(buf, sizeof(buf));
00148 #ifdef MDM_DEBUG
00149         if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
00150         {
00151             int len = LENGTH(ret);
00152             int type = TYPE(ret);
00153             const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 
00154                             (type == TYPE_TEXT)   ? MAG "TXT" DEF : 
00155                             (type == TYPE_OK   )  ? GRE "OK " DEF : 
00156                             (type == TYPE_ERROR)  ? RED "ERR" DEF : 
00157                             (type == TYPE_PLUS)   ? CYA " + " DEF : 
00158                             (type == TYPE_PROMPT) ? BLU " > " DEF : 
00159                                                         "..." ;
00160             ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
00161             dumpAtCmd(buf, len);
00162         }
00163 #endif        
00164         if ((ret != WAIT) && (ret != NOT_FOUND))
00165         {
00166             int type = TYPE(ret);
00167             // handle unsolicited commands here
00168             if (type == TYPE_PLUS) {
00169                 const char* cmd = buf+3;
00170                 int a, b, c, d, r;
00171                 char s[32];
00172                                                 
00173                 // SMS Command ---------------------------------
00174                 // +CNMI: <mem>,<index>
00175                 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 
00176                     TRACE("New SMS at index %d\r\n", a);
00177                 // Socket Specific Command ---------------------------------
00178                 // +UUSORD: <socket>,<length>
00179                 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2)) {
00180                     int socket = _findSocket(a);
00181                     TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
00182                     if (socket != SOCKET_ERROR)
00183                         _sockets[socket].pending = b;
00184                 // +UUSORF: <socket>,<length>
00185                 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) {
00186                     int socket = _findSocket(a);
00187                     TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
00188                     if (socket != SOCKET_ERROR)
00189                         _sockets[socket].pending = b;
00190                 // +UUSOCL: <socket>
00191                 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) {
00192                     int socket = _findSocket(a);
00193                     TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a);
00194                     if ((socket != SOCKET_ERROR) && _sockets[socket].connected)
00195                         _sockets[socket].connected = false;                                    
00196                 // +UULOC: <date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>, <direction>,<vertical_acc>,<sensor_used>,<SV_used>,<antenna_status>, <jamming_status>
00197                 }else if (sscanf(cmd, "UULOC: %d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d,%d,%d,%d,%d,%d,%*d,%*d",\
00198                         &_loc[0].time.tm_mday, &_loc[0].time.tm_mon, &_loc[0].time.tm_year, &_loc[0].time.tm_hour, &_loc[0].time.tm_min, &_loc[0].time.tm_sec,\
00199                         &_loc[0].latitude, &_loc[0].longitude, &_loc[0].altitutude, &_loc[0].uncertainty, &_loc[0].speed, &_loc[0].direction, &_loc[0].verticalAcc, \
00200                         &b, &_loc[0].svUsed) == 15) {
00201                     TRACE("Parsed UULOC position at index 0\r\n");                                        
00202                     _loc[0].sensor = (b==0)? CELL_LAST : (b==1)? CELL_GNSS : (b==2)? CELL_LOCATE : (b==3)? CELL_HYBRID : CELL_LAST;
00203                     _loc[0].time.tm_mon -= 1;
00204                     _loc[0].time.tm_wday=0;
00205                     _loc[0].time.tm_yday=0;
00206                     _loc[0].validData = true;
00207                     _locExpPos=1;
00208                     _locRcvPos++;
00209                // +UULOC: <sol>,<num>,<sensor_used>,<date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>, <direction>,<vertical_acc>,,<SV_used>,<antenna_status>, <jamming_status>                              
00210                }else if (sscanf(cmd, "UULOC: %d,%d,%d,%d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d,%d,%d,%d,%d,%*d,%*d",\
00211                         &a,&_locExpPos,&b, \
00212                         &_loc[CELL_MAX_HYP-1].time.tm_mday, &_loc[CELL_MAX_HYP-1].time.tm_mon, &_loc[CELL_MAX_HYP-1].time.tm_year, &_loc[CELL_MAX_HYP-1].time.tm_hour, &_loc[CELL_MAX_HYP-1].time.tm_min, &_loc[CELL_MAX_HYP-1].time.tm_sec,\
00213                         &_loc[CELL_MAX_HYP-1].latitude, &_loc[CELL_MAX_HYP-1].longitude, &_loc[CELL_MAX_HYP-1].altitutude, &_loc[CELL_MAX_HYP-1].uncertainty, &_loc[CELL_MAX_HYP-1].speed, &_loc[CELL_MAX_HYP-1].direction, &_loc[CELL_MAX_HYP-1].verticalAcc, \
00214                         &_loc[CELL_MAX_HYP-1].svUsed) == 17) {  
00215                     if (--a>=0){                         
00216                         TRACE("Parsed UULOC position at index %d\r\n",a);                    
00217                         memcpy(&_loc[a], &_loc[CELL_MAX_HYP-1], sizeof(*_loc)); 
00218                         _loc[a].sensor = (b==0)? CELL_LAST : (b==1)? CELL_GNSS : (b==2)? CELL_LOCATE : (b==3)? CELL_HYBRID : CELL_LAST;                                       
00219                         _loc[a].time.tm_mon -= 1;
00220                         _loc[a].time.tm_wday=0;
00221                         _loc[a].time.tm_yday=0;
00222                         _loc[a].validData = true;                    
00223                         _locRcvPos++;                                            
00224                     }
00225               //+UULOC: <sol>,<num>,<sensor_used>,<date>,<time>,<lat>,<long>,<alt>,<lat50>,<long50>,<major50>,<minor50>,<orientation50>,<confidence50>[,<lat95>,<long95>,<major95>,<minor95>,<orientation95>,<confidence95>]
00226                }else if (sscanf(cmd, "UULOC: %d,%d,%d,%d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%*f,%*f,%d,%*d,%*d,%*d",\
00227                         &a,&_locExpPos,&b, \
00228                         &_loc[CELL_MAX_HYP-1].time.tm_mday, &_loc[CELL_MAX_HYP-1].time.tm_mon, &_loc[CELL_MAX_HYP-1].time.tm_year, &_loc[CELL_MAX_HYP-1].time.tm_hour, &_loc[CELL_MAX_HYP-1].time.tm_min, &_loc[CELL_MAX_HYP-1].time.tm_sec,\
00229                         &_loc[CELL_MAX_HYP-1].latitude, &_loc[CELL_MAX_HYP-1].longitude, &_loc[CELL_MAX_HYP-1].altitutude, &_loc[CELL_MAX_HYP-1].uncertainty) == 13) {                    
00230                     if (--a>=0){    
00231                         TRACE("Parsed UULOC position at index %d\r\n",a);
00232                         memcpy(&_loc[a], &_loc[CELL_MAX_HYP-1], sizeof(*_loc));                                        
00233                         _loc[a].sensor = (b==0)? CELL_LAST : (b==1)? CELL_GNSS : (b==2)? CELL_LOCATE : (b==3)? CELL_HYBRID : CELL_LAST;
00234                         _loc[a].time.tm_mon -= 1;
00235                         _loc[a].time.tm_wday=0;
00236                         _loc[a].time.tm_yday=0;
00237                         _loc[a].validData = true;                    
00238                         _locRcvPos++;                    
00239                     }                              
00240                 // +UHTTPCR: <profile_id>,<op_code>,<param_val>
00241                 } else if ((sscanf(cmd, "UUHTTPCR: %d,%d,%d", &a, &b, &c) == 3)) {
00242                     _httpProfiles[a].cmd = b;          //command
00243                     _httpProfiles[a].result = c;       //result
00244                     TRACE("%s for profile %d: result code is %d\r\n", getHTTPcmd(b), a, c);
00245                 }
00246                 if (_dev.dev == DEV_LISA_C2) {
00247                     // CDMA Specific -------------------------------------------
00248                     // +CREG: <n><SID>,<NID>,<stat>
00249                     if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
00250                         // _net.sid = a;
00251                         // _net.nid = b;
00252                         if      (c == 0) _net.csd = REG_NONE;     // not registered, home network
00253                         else if (c == 1) _net.csd = REG_HOME;     // registered, home network
00254                         else if (c == 2) _net.csd = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
00255                         else if (c == 3) _net.csd = REG_DENIED;   // registration denied
00256                         else if (c == 5) _net.csd = REG_ROAMING;  // registered, roaming
00257                         _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
00258                         _net.act = ACT_CDMA;
00259                         // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
00260                     } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
00261                         //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
00262                     }
00263                 } else {
00264                     // GSM/UMTS Specific -------------------------------------------
00265                     // +UUPSDD: <profile_id> 
00266                     if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
00267                         if (*PROFILE == a) _ip = NOIP;
00268                     } else {
00269                         // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
00270                         // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]]     // URC
00271                         b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
00272                         r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
00273                         if (r <= 1)
00274                             r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
00275                         if (r >= 2) {
00276                             Reg *reg = !strcmp(s, "CREG:")  ? &_net.csd : 
00277                                        !strcmp(s, "CGREG:") ? &_net.psd : 
00278                                        !strcmp(s, "CEREG:") ? &_net.eps : NULL;
00279                             if (reg) {
00280                                 // network status
00281                                 if      (a == 0) *reg = REG_NONE;     // 0: not registered, home network
00282                                 else if (a == 1) *reg = REG_HOME;     // 1: registered, home network
00283                                 else if (a == 2) *reg = REG_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
00284                                 else if (a == 3) *reg = REG_DENIED;   // 3: registration denied
00285                                 else if (a == 4) *reg = REG_UNKNOWN;  // 4: unknown
00286                                 else if (a == 5) *reg = REG_ROAMING;  // 5: registered, roaming
00287                                 else if (a == 6) *reg = REG_HOME;     // 6: registered, sms only, home
00288                                 if ((r >= 3) && (b != 0xFFFF))      _net.lac = b; // location area code
00289                                 if ((r >= 4) && (c != 0xFFFFFFFF))  _net.ci  = c; // cell ID                                                                                                
00290                                 // access technology
00291                                 if (r >= 5) {
00292                                     if      (d == 0) _net.act = ACT_GSM;      // 0: GSM
00293                                     else if (d == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
00294                                     else if (d == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
00295                                     else if (d == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
00296                                     else if (d == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
00297                                     else if (d == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
00298                                     else if (d == 6) _net.act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
00299                                     else if (d == 7) _net.act = ACT_LTE;      // 7: LTE
00300                                 }
00301                             }
00302                         }
00303                     }
00304                 }
00305             }
00306             if (cb) {
00307                 int len = LENGTH(ret);
00308                 int ret = cb(type, buf, len, param);
00309                 if (WAIT != ret)
00310                     return ret; 
00311             }
00312             if (type == TYPE_OK)
00313                 return RESP_OK;
00314             if (type == TYPE_ERROR)
00315                 return RESP_ERROR;
00316             if (type == TYPE_ERROR_CME)
00317                 return RESP_ERROR_CME;                
00318             if (type == TYPE_PROMPT)    
00319                 return RESP_PROMPT;
00320         }
00321         // relax a bit
00322         wait_ms(10); 
00323     }
00324     while (!TIMEOUT(timer, timeout_ms));
00325     return WAIT;
00326 }
00327 
00328 int MDMParser::_cbString(int type, const char* buf, int len, char* str)
00329 {
00330     if (str && (type == TYPE_UNKNOWN)) {
00331         if (sscanf(buf, "\r\n%s\r\n", str) == 1)
00332             /*nothing*/;
00333     }
00334     return WAIT;
00335 }
00336 
00337 int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
00338 {
00339     if (val && (type == TYPE_UNKNOWN)) {
00340         if (sscanf(buf, "\r\n%d\r\n", val) == 1)
00341             /*nothing*/;
00342     }
00343     return WAIT;
00344 }
00345 
00346 // ----------------------------------------------------------------
00347 
00348 bool MDMParser::connect(
00349             const char* simpin, 
00350             const char* apn, const char* username, 
00351             const char* password, Auth auth,
00352             PinName pn)
00353 {
00354     bool ok = init(simpin, NULL, pn);  
00355 #ifdef MDM_DEBUG
00356     if (_debugLevel >= 1) dumpDevStatus(&_dev);
00357 #endif
00358     if (!ok)
00359         return false;
00360     ok = registerNet();
00361 #ifdef MDM_DEBUG
00362     if (_debugLevel >= 1) dumpNetStatus(&_net);
00363 #endif
00364     if (!ok)
00365         return false;
00366     IP ip = join(apn,username,password,auth);
00367 #ifdef MDM_DEBUG
00368     if (_debugLevel >= 1) dumpIp(ip);
00369 #endif
00370     if (ip == NOIP)
00371         return false; 
00372     return true;
00373 }
00374 
00375 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
00376 {
00377     int i = 10;
00378     LOCK();
00379     memset(&_dev, 0, sizeof(_dev));
00380     if (pn != NC) {
00381         INFO("Modem::wakeup\r\n");
00382         DigitalOut pin(pn, 1);
00383         while (i--) {
00384             // SARA-U2/LISA-U2 50..80us
00385             pin = 0; ::wait_us(50);
00386             pin = 1; ::wait_ms(10); 
00387             
00388             // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms
00389             pin = 0; ::wait_ms(150);
00390             pin = 1; ::wait_ms(100);
00391             
00392             // purge any messages 
00393             purge();
00394             
00395             // check interface
00396             sendFormated("AT\r\n");
00397             int r = waitFinalResp(NULL,NULL,1000);
00398             if(RESP_OK == r) break;
00399         }
00400         if (i < 0) {
00401             ERROR("No Reply from Modem\r\n");
00402             goto failure;
00403         }
00404     }
00405     _init = true;
00406     
00407     INFO("Modem::init\r\n");
00408     // echo off
00409     sendFormated("AT E0\r\n");
00410     if(RESP_OK != waitFinalResp())
00411         goto failure; 
00412     // enable verbose error messages
00413     sendFormated("AT+CMEE=2\r\n");
00414     if(RESP_OK != waitFinalResp())
00415         goto failure;
00416     // set baud rate
00417     sendFormated("AT+IPR=115200\r\n");
00418     if (RESP_OK != waitFinalResp())
00419         goto failure;
00420     // wait some time until baudrate is applied
00421     wait_ms(200); // SARA-G > 40ms
00422     // identify the module 
00423     sendFormated("ATI\r\n");
00424     if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
00425         goto failure;
00426     if (_dev.dev == DEV_UNKNOWN)
00427         goto failure;
00428     // device specific init
00429     if (_dev.dev == DEV_LISA_C2) {
00430         // get the manufacturer
00431         sendFormated("AT+GMI\r\n");
00432         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
00433             goto failure;
00434         // get the model identification
00435         sendFormated("AT+GMM\r\n");
00436         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
00437             goto failure;
00438         // get the sw version
00439         sendFormated("AT+GMR\r\n");
00440         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
00441             goto failure;
00442         // get the pseudo ESN or MEID
00443         sendFormated("AT+GSN\r\n");
00444         if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
00445             goto failure;
00446 #if 0
00447         // enable power saving
00448         if (_dev.lpm != LPM_DISABLED) {
00449              // enable power saving (requires flow control, cts at least)
00450             sendFormated("AT+UPSV=1,1280\r\n");
00451             if (RESP_OK != waitFinalResp())
00452                 goto failure;  
00453             _dev.lpm = LPM_ACTIVE;
00454         }
00455 #endif
00456     } else {
00457         if ((_dev.dev == DEV_LISA_U2) || (_dev.dev == DEV_LEON_G2) || 
00458             (_dev.dev == DEV_TOBY_L2)) {
00459             // enable the network identification feature 
00460             sendFormated("AT+UGPIOC=20,2\r\n");
00461             if (RESP_OK != waitFinalResp())
00462                 goto failure;
00463         } else if ((_dev.dev == DEV_SARA_U2) || (_dev.dev == DEV_SARA_G35)) {
00464             // enable the network identification feature 
00465             sendFormated("AT+UGPIOC=16,2\r\n");
00466             if (RESP_OK != waitFinalResp())
00467                 goto failure;
00468         }
00469         // check the sim card
00470         for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
00471             sendFormated("AT+CPIN?\r\n");
00472             int ret = waitFinalResp(_cbCPIN, &_dev.sim);
00473             // having an error here is ok (sim may still be initializing)
00474             if ((RESP_OK != ret) && (RESP_ERROR != ret))
00475                 goto failure;
00476             // Enter PIN if needed
00477             if (_dev.sim == SIM_PIN) {
00478                 if (!simpin) {
00479                     ERROR("SIM PIN not available\r\n");
00480                     goto failure;
00481                 }
00482                 sendFormated("AT+CPIN=\"%s\"\r\n", simpin);
00483                 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
00484                     goto failure;
00485             } else if (_dev.sim != SIM_READY) {
00486                 wait_ms(1000);
00487             }
00488         }
00489         if (_dev.sim != SIM_READY) {
00490             if (_dev.sim == SIM_MISSING)
00491                 ERROR("SIM not inserted\r\n");
00492             goto failure;
00493         }
00494         // get the manufacturer
00495         sendFormated("AT+CGMI\r\n");
00496         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
00497             goto failure;
00498         // get the model identification
00499         sendFormated("AT+CGMM\r\n");
00500         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
00501             goto failure;
00502         // get the version
00503         sendFormated("ATI9\r\n");
00504         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
00505             goto failure;
00506         // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 
00507         // ICCID is a serial number identifying the SIM.
00508         sendFormated("AT+CCID\r\n");
00509         if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
00510             goto failure;
00511         // Returns the product serial number, IMEI (International Mobile Equipment Identity)
00512         sendFormated("AT+CGSN\r\n");
00513         if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
00514             goto failure;
00515         // enable power saving
00516         if (_dev.lpm != LPM_DISABLED) {
00517              // enable power saving (requires flow control, cts at least)
00518             sendFormated("AT+UPSV=1\r\n");
00519             if (RESP_OK != waitFinalResp())
00520                 goto failure;  
00521             _dev.lpm = LPM_ACTIVE;
00522         }
00523         // enable the psd registration unsolicited result code
00524         sendFormated("AT+CGREG=2\r\n");
00525         if (RESP_OK != waitFinalResp())
00526             goto failure;
00527     } 
00528     // enable the network registration unsolicited result code
00529     sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C2) ? 1 : 2);
00530     if (RESP_OK != waitFinalResp())
00531         goto failure;
00532     // Setup SMS in text mode 
00533     sendFormated("AT+CMGF=1\r\n");
00534     if (RESP_OK != waitFinalResp())
00535         goto failure;
00536     // setup new message indication
00537     sendFormated("AT+CNMI=2,1\r\n");
00538     if (RESP_OK != waitFinalResp())
00539         goto failure;
00540     // Request IMSI (International Mobile Subscriber Identification)
00541     sendFormated("AT+CIMI\r\n");
00542     if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
00543         goto failure;
00544     if (status)
00545         memcpy(status, &_dev, sizeof(DevStatus));
00546     UNLOCK();
00547     return true; 
00548 failure:
00549     unlock();
00550     return false; 
00551 }
00552 
00553 bool MDMParser::powerOff(void)
00554 {
00555     bool ok = false;
00556     if (_init) {
00557         LOCK();
00558         INFO("Modem::powerOff\r\n");
00559         sendFormated("AT+CPWROFF\r\n");
00560         if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) {
00561             _init = false;
00562             ok = true;
00563         }
00564         UNLOCK();
00565     }
00566     return ok;
00567 }
00568 
00569 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
00570 {
00571     if ((type == TYPE_UNKNOWN) && dev) {
00572         if      (strstr(buf, "SARA-G35"))   *dev = DEV_SARA_G35;
00573         else if (strstr(buf, "LISA-U200-03S")) *dev = DEV_LISA_U2_03S;
00574         else if (strstr(buf, "LISA-U2"))    *dev = DEV_LISA_U2;        
00575         else if (strstr(buf, "LISA-C2"))    *dev = DEV_LISA_C2;
00576         else if (strstr(buf, "SARA-U2"))    *dev = DEV_SARA_U2;
00577         else if (strstr(buf, "LEON-G2"))    *dev = DEV_LEON_G2;
00578         else if (strstr(buf, "TOBY-L2"))    *dev = DEV_TOBY_L2;
00579         else if (strstr(buf, "MPCI-L2"))    *dev = DEV_MPCI_L2;
00580     }
00581     return WAIT;
00582 }
00583 
00584 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
00585 {
00586     if (sim) {
00587         if (type == TYPE_PLUS){
00588             char s[16];
00589             if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1)
00590                 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN;
00591         } else if (type == TYPE_ERROR) {
00592             if (strstr(buf, "+CME ERROR: SIM not inserted"))
00593                 *sim = SIM_MISSING;
00594         }
00595     }
00596     return WAIT;
00597 }
00598 
00599 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
00600 {
00601     if ((type == TYPE_PLUS) && ccid){
00602         if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
00603             /*TRACE("Got CCID: %s\r\n", ccid)*/;
00604     }
00605     return WAIT;
00606 }
00607 
00608 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/) 
00609 {
00610     Timer timer;
00611     timer.start();
00612     INFO("Modem::register\r\n");
00613     while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
00614         wait_ms(1000);
00615     if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
00616     if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
00617     if (_net.eps == REG_DENIED) ERROR("EPS Registration Denied\r\n");
00618     return REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps);
00619 }
00620 
00621 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
00622 {
00623     bool ok = false;
00624     LOCK();
00625     memset(&_net, 0, sizeof(_net));
00626     _net.lac = 0xFFFF;
00627     _net.ci = 0xFFFFFFFF;
00628     // check registration
00629     sendFormated("AT+CREG?\r\n");
00630     waitFinalResp();     // don't fail as service could be not subscribed 
00631     if (_dev.dev != DEV_LISA_C2) {
00632         // check PSD registration
00633         sendFormated("AT+CGREG?\r\n");
00634         waitFinalResp(); // don't fail as service could be not subscribed 
00635         if ((_dev.dev == DEV_TOBY_L2) ||  (_dev.dev == DEV_MPCI_L2)) {
00636             // check EPS network registration
00637             sendFormated("AT+CEREG?\r\n");
00638             waitFinalResp(); // don't fail as service could be not subscribed
00639         }
00640     }
00641     if (REG_OK(_net.csd) || REG_OK(_net.psd) || REG_OK(_net.eps))
00642     {
00643         // check modem specific status messages 
00644         if (_dev.dev == DEV_LISA_C2) {
00645             sendFormated("AT+CSS?\r\n");
00646             if (RESP_OK != waitFinalResp())
00647                 goto failure;
00648             while (1) {
00649                 // get the Telephone number
00650                 sendFormated("AT$MDN?\r\n");
00651                 if (RESP_OK != waitFinalResp(_cbString, _net.num))
00652                     goto failure;
00653                 // check if we have a Mobile Directory Number
00654                 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
00655                     break;
00656                     
00657                 INFO("Device not yet activated\r\n");
00658                 INFO("Make sure you have a valid contract with the network operator for this device.\r\n");
00659                 // Check if the the version contains a V for Verizon 
00660                 // Verizon: E0.V.xx.00.xxR, 
00661                 // Sprint E0.S.xx.00.xxR
00662                 if (_dev.ver[3] == 'V') { 
00663                     int i;
00664                     INFO("Start device over-the-air activation (this can take a few minutes)\r\n");
00665                     sendFormated("AT+CDV=*22899\r\n");
00666                     i = 1;
00667                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
00668                         ERROR("Device over-the-air activation failed\r\n");
00669                         goto failure;
00670                     }
00671                     INFO("Device over-the-air activation successful\r\n");
00672                     
00673                     INFO("Start PRL over-the-air update (this can take a few minutes)\r\n");
00674                     sendFormated("AT+CDV=*22891\r\n");
00675                     i = 1;
00676                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
00677                         ERROR("PRL over-the-air update failed\r\n");
00678                         goto failure;
00679                     }
00680                     INFO("PRL over-the-air update successful\r\n");
00681                     
00682                 } else { 
00683                     // Sprint or Aeris 
00684                     INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
00685                     wait_ms(120*1000);
00686                 }
00687             }
00688             // get the the Network access identifier string
00689             char nai[64];
00690             sendFormated("AT$QCMIPNAI?\r\n");
00691             if (RESP_OK != waitFinalResp(_cbString, nai))
00692                 goto failure;
00693         } else {
00694             sendFormated("AT+COPS?\r\n");
00695             if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
00696                 goto failure;
00697             // get the MSISDNs related to this subscriber
00698             sendFormated("AT+CNUM\r\n");
00699             if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
00700                 goto failure;
00701         }  
00702         // get the signal strength indication
00703         sendFormated("AT+CSQ\r\n");
00704         if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
00705             goto failure;
00706     }
00707     if (status) {
00708         memcpy(status, &_net, sizeof(NetStatus));
00709     }
00710     ok = REG_DONE(_net.csd) && 
00711         (REG_DONE(_net.psd) || REG_DONE(_net.eps));
00712     UNLOCK();
00713     return ok;
00714 failure:
00715     unlock();
00716     return false;
00717 }
00718 
00719 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
00720 {
00721     if ((type == TYPE_PLUS) && status){
00722         int act = 99;
00723         int mode = 99;
00724         // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
00725        if (sscanf(buf, "\r\n+COPS: %d,%*d,\"%[^\"]\",%d",&mode,status->opr,&act) >= 1) {
00726             if      (act == 0) status->act = ACT_GSM;      // 0: GSM, 
00727             else if (act == 2) status->act = ACT_UTRAN;    // 2: UTRAN
00728             else if (act == 7) status->act = ACT_LTE;    // 2: UTRAN
00729             if (mode == 0)  status->regStatus = COPS_AUTOMATIC_REG;
00730             else if (mode == 1) status->regStatus = COPS_MANUAL_REG;
00731             else if (mode == 2) status->regStatus = COPS_DISABLED_REG;
00732         }
00733     }
00734     return WAIT;
00735 }
00736 
00737 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
00738 {
00739     if ((type == TYPE_PLUS) && num){
00740         int a;
00741         if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 
00742             ((a == 129) || (a == 145))) {
00743         }
00744     }
00745     return WAIT;
00746 }
00747                     
00748 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status)
00749 {
00750     if ((type == TYPE_PLUS) && status){
00751         int a,b;
00752         char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4
00753         // +CSQ: <rssi>,<qual>
00754         if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) {
00755             if (a != 99) status->rssi = -113 + 2*a;  // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps, 31: >-51 dBm
00756             if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b];  // 
00757         }
00758     }
00759     return WAIT;
00760 }
00761 
00762 
00763 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i)
00764 {
00765     if ((type == TYPE_PLUS) && i){
00766         int a;
00767         if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) {
00768             *i = a;
00769         }
00770     }
00771     return WAIT;
00772 }
00773 
00774 // ----------------------------------------------------------------
00775 // internet connection 
00776 
00777 bool MDMParser::_activateProfile(const char* apn, const char* username, const char* password, Auth auth)
00778 {
00779     // Set up the APN
00780     if (*apn) {
00781         sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
00782         if (RESP_OK != waitFinalResp())
00783             return false;
00784     }
00785     if (*username) {
00786         sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
00787         if (RESP_OK != waitFinalResp())
00788             return false;
00789     }
00790     if (*password) {
00791         sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
00792         if (RESP_OK != waitFinalResp())
00793             return false;
00794     }
00795     // Set up the dynamic IP address assignment.
00796     sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
00797     if (RESP_OK != waitFinalResp())
00798         return false;
00799     // try different Authentication Protocols
00800     // 0 = none 
00801     // 1 = PAP (Password Authentication Protocol)
00802     // 2 = CHAP (Challenge Handshake Authentication Protocol)
00803     for (int i = AUTH_NONE; i <= AUTH_CHAP; i ++) {
00804         if ((auth == AUTH_DETECT) || (auth == i)) {
00805             // Set up the Authentication Protocol
00806             sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n",i);
00807             if (RESP_OK != waitFinalResp())
00808                 return false;
00809             // Activate the profile and make connection
00810             sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
00811             if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
00812                 return true;
00813         }
00814     }
00815     return false;
00816 }
00817 
00818 bool MDMParser::_activateProfileReuseExternal(void)
00819 {
00820     int cid = -1;
00821     sendFormated("AT+CGDCONT?\r\n");
00822     if (RESP_OK != waitFinalResp(_cbCGDCONT, &cid))
00823         return false;
00824     if (cid == -1)
00825         return false;
00826     // we found a context that provides us a valid IP so lets reuse it for the internal IP stack
00827     sendFormated("AT+UPSD=" PROFILE ",100,%d\r\n", cid);
00828     if (RESP_OK != waitFinalResp())
00829         return false;
00830     // Activate the profile and make connection
00831     sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
00832     return (RESP_OK == waitFinalResp(NULL,NULL,150*1000));
00833 }
00834 
00835 bool MDMParser::_activateProfileByCid(int cid, const char* apn, const char* username, const char* password, Auth auth)
00836 {
00837     sendFormated("AT+CGDCONT=%d,\"IP\",\"%s\"\r\n", cid, apn);
00838     if (RESP_OK != waitFinalResp())
00839         return false;
00840     sendFormated("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"\r\n", cid, auth, username, password);
00841     if (RESP_OK != waitFinalResp())
00842         return false;
00843     sendFormated("AT+UPSD=" PROFILE ",100,%d\r\n", cid);
00844     if (RESP_OK != waitFinalResp())
00845         return false;
00846     // Activate the profile and make connection
00847     sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
00848     return (RESP_OK == waitFinalResp(NULL,NULL,150*1000));
00849 }
00850  
00851 int MDMParser::_cbCGDCONT(int type, const char* buf, int len, int* cid)
00852 {
00853     // accept with and without leading \r\n in +CGDCONT:
00854     if ((type == TYPE_PLUS) && (buf[0] == '\r') && (buf[1] == '\n') && (len >= 2))
00855         buf += 2, len -= 2, type = TYPE_UNKNOWN;
00856     if (type == TYPE_UNKNOWN) {
00857         int a,b,c,d,t;
00858         //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0
00859         if (sscanf(buf, "+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"" IPSTR "\",%*d,%*d,%*d,%*d,%*d,%*d", &t, &a,&b,&c,&d) == 5) {
00860             if (IPADR(a,b,c,d) != NOIP) 
00861                 *cid = t;
00862         }
00863     }
00864     return WAIT;
00865 }
00866 
00867 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 
00868                               const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
00869 {
00870     LOCK();
00871     INFO("Modem::join\r\n");
00872     _ip = NOIP;
00873     if (_dev.dev == DEV_LISA_C2) {
00874         // make a dumy dns lookup (which will fail, so ignore the result) 
00875         sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n");
00876         waitFinalResp(); 
00877         // This fake lookup will enable the IP connection and we 
00878         // should have an IP after this, so we check it
00879         
00880         //Get local IP address
00881         sendFormated("AT+CMIP?\r\n");
00882         if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
00883             goto failure;
00884     
00885     } else { 
00886         // check gprs attach status 
00887         sendFormated("AT+CGATT=1\r\n");
00888         if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 
00889             goto failure;
00890         // Check the profile
00891         int a = 0;
00892         bool force = true;
00893         sendFormated("AT+UPSND=" PROFILE ",8\r\n");
00894         if (RESP_OK != waitFinalResp(_cbUPSND, &a))
00895             goto failure;
00896         if (a == 1 && force) {
00897             // disconnect the profile already if it is connected 
00898             sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
00899             if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
00900                 goto failure;
00901             a = 0;
00902         }
00903         if (a == 0) {
00904             bool ok = false;
00905             // try to lookup the apn settings from our local database by mccmnc
00906             const char* config = NULL;
00907             if (!apn && !username && !password)
00908                 config = apnconfig(_dev.imsi);
00909             do {
00910                 if (config) {
00911                     apn      = _APN_GET(config);
00912                     username = _APN_GET(config);
00913                     password = _APN_GET(config);
00914                 }
00915                 // convert pointer to empty strings
00916                 apn      = apn      ? apn      : "";
00917                 username = username ? username : "";
00918                 password = password ? password : "";
00919                 auth = (*username && *password) ? auth : AUTH_NONE;
00920                 TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\",%d)\r\n", apn, username, password, auth);
00921                 if ((_dev.dev != DEV_TOBY_L2) && (_dev.dev != DEV_MPCI_L2))
00922                     ok = _activateProfile(apn, username, password, auth);
00923                 else {
00924                     ok = _activateProfileReuseExternal();
00925                     if (ok) 
00926                         TRACE("Reusing External Context\r\n");
00927                     else
00928                         ok = _activateProfileByCid(1, apn, username, password, auth);
00929                 }
00930             } while (!ok && config && *config); // maybe use next setting ? 
00931             if (!ok) {
00932                 ERROR("Your modem APN/password/username may be wrong\r\n");
00933                 goto failure;
00934             }
00935         }
00936         //Get local IP address
00937         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
00938         if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
00939             goto failure;
00940     }
00941     UNLOCK();
00942     return _ip;
00943 failure: 
00944     unlock();
00945     return NOIP;
00946 }
00947 
00948 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc)
00949 {
00950     if ((type == TYPE_PLUS) && mccmnc) {
00951         if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1)
00952             ;
00953     }
00954     return WAIT;
00955 }
00956 
00957 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip)
00958 {
00959     if ((type == TYPE_UNKNOWN) && ip) {
00960         int a,b,c,d;
00961         if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4)
00962             *ip = IPADR(a,b,c,d);
00963     }
00964     return WAIT;
00965 }
00966         
00967 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
00968 {
00969     if ((type == TYPE_PLUS) && act) {
00970         if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
00971             /*nothing*/;
00972     }
00973     return WAIT;
00974 }
00975 
00976 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
00977 {
00978     if ((type == TYPE_PLUS) && ip) {
00979         int a,b,c,d;
00980         // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
00981         if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
00982             *ip = IPADR(a,b,c,d);
00983     }
00984     return WAIT;
00985 }
00986 
00987 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
00988 {
00989     if ((type == TYPE_PLUS) && ip) {
00990         int a,b,c,d;
00991         if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4)
00992             *ip = IPADR(a,b,c,d);
00993     }
00994     return WAIT;
00995 }
00996 
00997 bool MDMParser::disconnect(void)
00998 {
00999     bool ok = false;
01000     LOCK();
01001     INFO("Modem::disconnect\r\n");
01002     if (_ip != NOIP) {
01003         if (_dev.dev == DEV_LISA_C2) {
01004             // There something to do here
01005             _ip = NOIP;
01006             ok = true;
01007         } else { 
01008             sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
01009             if (RESP_OK != waitFinalResp()) {
01010                 _ip = NOIP;
01011                 ok = true;
01012             }
01013         }
01014     }
01015     UNLOCK();
01016     return ok;
01017 }
01018 
01019 MDMParser::IP MDMParser::gethostbyname(const char* host)
01020 {
01021     IP ip = NOIP; 
01022     int a,b,c,d;
01023     if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
01024         ip = IPADR(a,b,c,d);
01025     else {
01026         LOCK();
01027         sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
01028         if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
01029             ip = NOIP;
01030         UNLOCK();
01031     }
01032     return ip;
01033 }
01034 
01035 // ----------------------------------------------------------------
01036 // sockets
01037 
01038 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle)
01039 {
01040     if ((type == TYPE_PLUS) && handle) {
01041         // +USOCR: socket
01042         if (sscanf(buf, "\r\n+USOCR: %d", handle) == 1)
01043             /*nothing*/;  
01044     }
01045     return WAIT;
01046 }
01047 
01048 int MDMParser::socketSocket(IpProtocol ipproto, int port)
01049 {
01050     int socket;
01051     LOCK();
01052     // find an free socket
01053     socket = _findSocket();
01054     TRACE("socketSocket(%d)\r\n", ipproto);
01055     if (socket != SOCKET_ERROR) {
01056         if (ipproto == IPPROTO_UDP) {
01057             // sending port can only be set on 2G/3G modules
01058             if ((port != -1) && (_dev.dev != DEV_LISA_C2)) {
01059                 sendFormated("AT+USOCR=17,%d\r\n", port);
01060             } else {
01061                 sendFormated("AT+USOCR=17\r\n");
01062             }
01063         } else /*(ipproto == IPPROTO_TCP)*/ {
01064             sendFormated("AT+USOCR=6\r\n");
01065         } 
01066         int handle = SOCKET_ERROR;
01067         if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) && 
01068             (handle != SOCKET_ERROR)) {
01069             TRACE("Socket %d: handle %d was created\r\n", socket, handle);
01070             _sockets[socket].handle     = handle;
01071             _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
01072             _sockets[socket].connected  = false;
01073             _sockets[socket].pending    = 0;
01074         }
01075         else
01076             socket = SOCKET_ERROR;
01077     }
01078     UNLOCK();
01079     return socket;
01080 }
01081 
01082 bool MDMParser::socketConnect(int socket, const char * host, int port)
01083 {
01084     IP ip = gethostbyname(host);
01085     if (ip == NOIP)
01086         return false;
01087     // connect to socket
01088     bool ok = false; 
01089     LOCK();
01090     if (ISSOCKET(socket) && (!_sockets[socket].connected)) {
01091         TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port);
01092         sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port);
01093         if (RESP_OK == waitFinalResp())
01094             ok = _sockets[socket].connected = true;
01095     }
01096     UNLOCK();
01097     return ok;
01098 }
01099 
01100 bool MDMParser::socketIsConnected(int socket)
01101 {
01102     bool ok = false;
01103     LOCK();
01104     ok = ISSOCKET(socket) && _sockets[socket].connected;
01105     TRACE("socketIsConnected(%d) %s\r\n", socket, ok?"yes":"no");
01106     UNLOCK();
01107     return ok;
01108 }
01109 
01110 bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
01111 {
01112     bool ok = false;
01113     LOCK();
01114     TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms);
01115     if (ISSOCKET(socket)) {
01116         _sockets[socket].timeout_ms = timeout_ms;
01117         ok = true;
01118     }
01119     UNLOCK();
01120     return ok;
01121 }
01122 
01123 bool  MDMParser::socketClose(int socket)
01124 {
01125     bool ok = false;
01126     LOCK();
01127     if (ISSOCKET(socket) && _sockets[socket].connected) {
01128         TRACE("socketClose(%d)\r\n", socket);
01129         sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle);
01130         if (RESP_OK == waitFinalResp()) {
01131             _sockets[socket].connected = false;
01132             ok = true;
01133         }
01134     }
01135     UNLOCK();
01136     return ok;
01137 }
01138 
01139 bool  MDMParser::socketFree(int socket)
01140 {
01141     // make sure it is closed
01142     socketClose(socket);
01143     bool ok = true;
01144     LOCK();
01145     if (ISSOCKET(socket)) {
01146         TRACE("socketFree(%d)\r\n",  socket);
01147         _sockets[socket].handle     = SOCKET_ERROR;
01148         _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
01149         _sockets[socket].connected  = false;
01150         _sockets[socket].pending    = 0;
01151         ok = true;
01152     }
01153     UNLOCK();
01154     return ok;
01155 }
01156 
01157 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
01158 
01159 int MDMParser::socketSend(int socket, const char * buf, int len)
01160 {
01161     TRACE("socketSend(%d,,%d)\r\n", socket,len);
01162     int cnt = len;
01163     while (cnt > 0) {
01164         int blk = USO_MAX_WRITE;
01165         if (cnt < blk) 
01166             blk = cnt;
01167         bool ok = false;
01168         LOCK();
01169         if (ISSOCKET(socket)) {
01170             sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk);
01171             if (RESP_PROMPT == waitFinalResp()) {
01172                 wait_ms(50);
01173                 send(buf, blk);
01174                 if (RESP_OK == waitFinalResp()) 
01175                     ok = true;
01176             }
01177         }
01178         UNLOCK();
01179         if (!ok) 
01180             return SOCKET_ERROR;
01181         buf += blk;
01182         cnt -= blk;
01183     }
01184     return (len - cnt);
01185 }
01186 
01187 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len)
01188 {
01189     TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len);
01190     int cnt = len;
01191     while (cnt > 0) {
01192         int blk = USO_MAX_WRITE;
01193         if (cnt < blk) 
01194             blk = cnt;
01195         bool ok = false;
01196         LOCK();
01197         if (ISSOCKET(socket)) {
01198             sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk);
01199             if (RESP_PROMPT == waitFinalResp()) {
01200                 wait_ms(50);
01201                 send(buf, blk);
01202                 if (RESP_OK == waitFinalResp())
01203                     ok = true;
01204             }
01205         }
01206         UNLOCK();
01207         if (!ok)
01208             return SOCKET_ERROR;
01209         buf += blk;
01210         cnt -= blk;
01211     }
01212     return (len - cnt);
01213 }
01214 
01215 int MDMParser::socketReadable(int socket)
01216 {
01217     int pending = SOCKET_ERROR;
01218     LOCK();
01219     if (ISSOCKET(socket) && _sockets[socket].connected) {
01220         TRACE("socketReadable(%d)\r\n", socket);
01221         // allow to receive unsolicited commands 
01222         waitFinalResp(NULL, NULL, 0);
01223         if (_sockets[socket].connected)
01224            pending = _sockets[socket].pending; 
01225     }
01226     UNLOCK();
01227     return pending;
01228 }
01229 
01230 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
01231 {
01232     if ((type == TYPE_PLUS) && out) {
01233         int sz, sk;
01234         if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && 
01235             (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01236             memcpy(out, &buf[len-1-sz], sz);
01237         }
01238     }
01239     return WAIT;
01240 }
01241 
01242 int MDMParser::socketRecv(int socket, char* buf, int len)
01243 {
01244     int cnt = 0;
01245     TRACE("socketRecv(%d,,%d)\r\n", socket, len);
01246 #ifdef MDM_DEBUG
01247     memset(buf, '\0', len);
01248 #endif
01249     Timer timer;
01250     timer.start();
01251     while (len) {
01252         int blk = MAX_SIZE; // still need space for headers and unsolicited  commands 
01253         if (len < blk) blk = len;
01254         bool ok = false;        
01255         LOCK();
01256         if (ISSOCKET(socket)) {
01257             if (_sockets[socket].connected) {
01258                 if (_sockets[socket].pending < blk)
01259                     blk = _sockets[socket].pending;
01260                 if (blk > 0) {
01261                     sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk);
01262                     if (RESP_OK == waitFinalResp(_cbUSORD, buf)) {
01263                         _sockets[socket].pending -= blk;
01264                         len -= blk;
01265                         cnt += blk;
01266                         buf += blk;
01267                         ok = true;
01268                     }
01269                 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
01270                     ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
01271                 } else {
01272                     len = 0;
01273                     ok = true;
01274                 }
01275             } else {
01276                 len = 0;
01277                 ok = true;
01278             }
01279         }
01280         UNLOCK();
01281         if (!ok) {
01282             TRACE("socketRecv: ERROR\r\n");
01283             return SOCKET_ERROR;
01284         }
01285     }
01286     TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
01287     return cnt;
01288 }
01289 
01290 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param)
01291 {
01292     if ((type == TYPE_PLUS) && param) {
01293         int sz, sk, p, a,b,c,d;
01294         int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 
01295             &sk,&a,&b,&c,&d,&p,&sz);
01296         if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01297             memcpy(param->buf, &buf[len-1-sz], sz);
01298             param->ip = IPADR(a,b,c,d);
01299             param->port = p;
01300         }
01301     }
01302     return WAIT;
01303 }
01304 
01305 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len)
01306 {
01307     int cnt = 0;
01308     TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
01309 #ifdef MDM_DEBUG
01310     memset(buf, '\0', len);
01311 #endif
01312     Timer timer;
01313     timer.start();
01314     while (len) {
01315         int blk = MAX_SIZE; // still need space for headers and unsolicited commands 
01316         if (len < blk) blk = len;
01317         bool ok = false;        
01318         LOCK();
01319         if (ISSOCKET(socket)) {
01320             if (_sockets[socket].pending < blk)
01321                 blk = _sockets[socket].pending;
01322             if (blk > 0) {
01323                 sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk);
01324                 USORFparam param;
01325                 param.buf = buf;
01326                 if (RESP_OK == waitFinalResp(_cbUSORF, &param)) {
01327                     _sockets[socket].pending -= blk;
01328                     *ip = param.ip;
01329                     *port = param.port;
01330                     len -= blk;
01331                     cnt += blk;
01332                     buf += blk;
01333                     len = 0; // done 
01334                     ok = true;
01335                 }
01336             } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
01337                 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
01338             } else {
01339                 len = 0; // no more data and socket closed or timed-out
01340                 ok = true;
01341             }
01342         }
01343         UNLOCK();
01344         if (!ok) {
01345             TRACE("socketRecv: ERROR\r\n");
01346             return SOCKET_ERROR;
01347         }
01348     }
01349     timer.stop();
01350     timer.reset();
01351     TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
01352     return cnt;
01353 }
01354 
01355 int MDMParser::_findSocket(int handle) {
01356     for (int socket = 0; socket < NUMSOCKETS; socket ++) {
01357         if (_sockets[socket].handle == handle)
01358             return socket;
01359     }
01360     return SOCKET_ERROR;
01361 }
01362 
01363 // ----------------------------------------------------------------
01364 // HTTP
01365 
01366 int MDMParser::httpFindProfile()
01367 {
01368     int profile = HTTP_PROF_ERROR;  //default value
01369     LOCK();
01370     // find a free HTTP profile 
01371     profile = _findProfile();
01372     TRACE("httpFindProfile: profile is %d\r\n", profile);
01373     if (profile != HTTP_PROF_ERROR) {
01374         _httpProfiles[profile].handle     = 1;
01375         _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING;
01376         _httpProfiles[profile].pending    = false;
01377         _httpProfiles[profile].cmd        = -1;
01378         _httpProfiles[profile].result     = -1;
01379     }
01380     UNLOCK();
01381     return profile;
01382 }
01383 
01384 int MDMParser::_findProfile(int handle) {
01385     for (int profile = 0; profile < NUMPROFILES; profile++) {
01386         if (_httpProfiles[profile].handle == handle)
01387             return profile;
01388     }
01389     return HTTP_PROF_ERROR;
01390 }
01391 
01392 bool MDMParser::httpSetBlocking(int profile, int timeout_ms)
01393 {
01394     bool ok = false;
01395     LOCK();
01396     TRACE("httpSetBlocking(%d,%d)\r\n", profile, timeout_ms);
01397     if (ISPROFILE(profile)) {
01398         _httpProfiles[profile].timeout_ms = timeout_ms;
01399         ok = true;
01400     }
01401     UNLOCK();
01402     return ok;
01403 }
01404 
01405 bool MDMParser::httpSetProfileForCmdMng(int profile)
01406 {
01407     bool ok = false;
01408     LOCK();
01409     TRACE("httpSetProfileForCmdMng(%d)\r\n", profile);
01410     if (ISPROFILE(profile)) {
01411         _httpProfiles[profile].pending = true;
01412         _httpProfiles[profile].result = -1;
01413         ok = true;
01414     }
01415     UNLOCK();
01416     return ok;
01417 }
01418 
01419 bool MDMParser::httpFreeProfile(int profile)
01420 {
01421     bool ok = true;
01422     LOCK();
01423     if (ISPROFILE(profile)) {
01424         TRACE("httpFreeProfile(%d)\r\n", profile);
01425         _httpProfiles[profile].handle     = HTTP_PROF_ERROR;
01426         _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING;
01427         _httpProfiles[profile].pending    = false;
01428         _httpProfiles[profile].cmd        = -1;
01429         _httpProfiles[profile].result     = -1;
01430         ok = true;
01431     }
01432     UNLOCK();
01433     return ok;
01434 }
01435 
01436 bool MDMParser::httpResetProfile(int httpProfile)
01437 {
01438     bool ok = false;
01439     
01440     LOCK();
01441     TRACE("httpResetProfile(%d)\r\n", httpProfile);
01442     sendFormated("AT+UHTTP=%d\r\n", httpProfile);
01443     if (RESP_OK == waitFinalResp())
01444         ok = true;
01445     UNLOCK();
01446     
01447     return ok;
01448 }
01449 
01450 bool MDMParser::httpSetPar(int httpProfile, HttpOpCode httpOpCode, const char * httpInPar)
01451 {
01452     bool ok = false;
01453     IP ip = NOIP;
01454     int httpInParNum = 0;
01455     
01456     LOCK();
01457     TRACE("httpSetPar(%d,%d,\"%s\")\r\n", httpProfile, httpOpCode, httpInPar);
01458     switch(httpOpCode){
01459         case HTTP_IP_ADDRESS:   //0
01460             ip = gethostbyname(httpInPar);
01461             if (ip == NOIP)
01462                 return false;
01463             
01464             sendFormated("AT+UHTTP=%d,%d,\"" IPSTR "\"\r\n", httpProfile, httpOpCode, IPNUM(ip));
01465             if (RESP_OK == waitFinalResp())
01466                 ok = true;
01467             break;
01468             
01469         case HTTP_SERVER_NAME:  //1
01470         case HTTP_USER_NAME:    //2
01471         case HTTP_PASSWORD:     //3
01472             sendFormated("AT+UHTTP=%d,%d,\"%s\"\r\n", httpProfile, httpOpCode, httpInPar);
01473             if (RESP_OK == waitFinalResp())
01474                 ok = true;
01475             break;
01476         
01477         case HTTP_AUTH_TYPE:    //4    
01478         case HTTP_SERVER_PORT:  //5
01479             httpInParNum = atoi(httpInPar);
01480             sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 
01481             if (RESP_OK == waitFinalResp())
01482                 ok = true;
01483             break;
01484             
01485         case HTTP_SECURE:       //6
01486             if(_dev.dev != DEV_LISA_C2)
01487             {
01488                 httpInParNum = atoi(httpInPar);
01489                 sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 
01490                 if (RESP_OK == waitFinalResp())
01491                     ok = true;
01492             } else {
01493                 TRACE("httpSetPar: HTTP secure option not supported by module\r\n");
01494                 ok = false;
01495             }
01496             break;
01497             
01498         default:
01499             TRACE("httpSetPar: unknown httpOpCode %s\r\n", httpOpCode);
01500             ok = false; 
01501             break;   
01502     }
01503     UNLOCK();
01504     return ok;
01505 }
01506 
01507 bool MDMParser::httpCommand(int httpProfile, HttpCmd httpCmdCode, const char* httpPath, const char* httpOut, \
01508                             const char* httpIn, int httpContentType, const char* httpCustomPar, char* buf, int len)
01509 {   
01510     bool ok = false;
01511 #ifdef MDM_DEBUG
01512     memset(buf, '\0', len);
01513 #endif
01514     LOCK();
01515     TRACE("%s\r\n", getHTTPcmd(httpCmdCode));
01516     switch (httpCmdCode) 
01517     {   
01518         case HTTP_HEAD:
01519             sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_HEAD, httpPath, httpOut);
01520             break;
01521             
01522         case HTTP_GET:
01523             sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_GET, httpPath, httpOut);
01524             break;
01525             
01526         case HTTP_DELETE:
01527             sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_DELETE, httpPath, httpOut);
01528             break;
01529             
01530         case HTTP_PUT:
01531             //in this case the parameter httpIn is a filename
01532             sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"\r\n", httpProfile, HTTP_PUT, httpPath, httpOut, httpIn);
01533             break;
01534             
01535         case HTTP_POST_FILE:
01536             //in this case the parameter httpIn is a filename
01537             if(_dev.dev != DEV_LISA_C2)
01538             {
01539                 if(httpContentType != 6)
01540                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
01541                                   httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType);
01542                 else
01543                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \
01544                                   httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType, httpCustomPar);
01545             }
01546             else{
01547                 if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL))
01548                 {
01549                     //parameters values consistent with the AT commands specs of LISA-C200
01550                     //(in particular httpCustomPar has to be not defined)
01551                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
01552                                   httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType);
01553                 } else {
01554                     TRACE("httpCommand: command not supported by module");
01555                     return ok;  //error
01556                 }
01557             }
01558             break;
01559             
01560         case HTTP_POST_DATA:
01561             //in this case the parameter httpIn is a string containing data
01562             if(_dev.dev != DEV_LISA_C2)
01563             {
01564                 if(httpContentType != 6)
01565                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
01566                                   httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType);
01567                 else
01568                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \
01569                                   httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType, httpCustomPar);
01570             } else {
01571                 if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL))
01572                 {
01573                     //parameters values consistent with the AT commands specs of LISA-C200
01574                     //(in particular httpCustomPar has to be not defined)
01575                     sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
01576                                   httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType);
01577                 } else {
01578                     TRACE("httpCommand: command not supported by module");
01579                     return ok;  //error
01580                 }
01581             }    
01582             break;
01583             
01584         default:
01585             TRACE("HTTP command not recognized\r\n");
01586             return ok;  //error
01587     }
01588     
01589     if (RESP_OK == waitFinalResp())
01590     {
01591         Timer timer;
01592         timer.start();
01593         httpSetProfileForCmdMng(httpProfile);
01594         while (_httpProfiles[httpProfile].pending)  //waiting for unsolicited
01595         {     
01596             ok = false;  //reset variable  
01597             if(_httpProfiles[httpProfile].result != -1)
01598             {    
01599                 //received unsolicited: starting its analysis 
01600                 _httpProfiles[httpProfile].pending = false;   
01601                 if(_httpProfiles[httpProfile].result == 1)
01602                 {
01603                     //HTTP command successfully executed
01604                     if(_dev.dev != DEV_LISA_C2)
01605                     {
01606                         TRACE("httpCommand: reading files with a dimension " \
01607                               "also greater than MAX_SIZE bytes\r\n");
01608                         if(readFileNew(httpOut,buf,len) >=0 )
01609                             ok = true;
01610                     } else {
01611                         TRACE("httpCommand: reading files with a dimension " \
01612                               "less than MAX_SIZE bytes, otherwise error\r\n");
01613                         if(readFile(httpOut,buf,len) >=0 )
01614                             ok = true;
01615                     }
01616                 } else {
01617                     //HTTP command not successfully executed
01618                     ok = false;
01619                 }
01620             } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout_ms)) {
01621                 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
01622             } else  {
01623                 //not received unsolicited and expired timer
01624                 TRACE("httpCommand: not received unsolicited and expired timer\r\n");
01625                 ok = false;
01626             }
01627             if (!ok) {
01628                 TRACE("%s: ERROR\r\n", getHTTPcmd(httpCmdCode));
01629                 _httpProfiles[httpProfile].pending = false;  //no more while loops
01630             }
01631         }
01632     }
01633     UNLOCK();
01634     return ok;
01635 }
01636 
01637 const char* MDMParser::getHTTPcmd(int httpCmdCode) 
01638 {
01639     switch (httpCmdCode) 
01640     {
01641         case HTTP_HEAD:
01642             return "HTTP HEAD command";
01643         case HTTP_GET:
01644             return "HTTP GET command";
01645         case HTTP_DELETE:
01646             return "HTTP DELETE command";
01647         case HTTP_PUT:
01648             return "HTTP PUT command";
01649         case HTTP_POST_FILE:
01650             return "HTTP POST file command";
01651         case HTTP_POST_DATA:
01652             return "HTTP POST data command";
01653         default:
01654             return "HTTP command not recognized";
01655    }
01656 }
01657 
01658 // ----------------------------------------------------------------
01659 
01660 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
01661 { 
01662     if ((type == TYPE_PLUS) && param && param->num) {
01663         // +CMGL: <ix>,...
01664         int ix;
01665         if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
01666         {
01667             *param->ix++ = ix;
01668             param->num--;
01669         }
01670     }
01671     return WAIT;
01672 }
01673 
01674 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
01675     int ret = -1;
01676     LOCK();
01677     sendFormated("AT+CMGL=\"%s\"\r\n", stat);
01678     CMGLparam param;
01679     param.ix = ix;
01680     param.num = num;
01681     if (RESP_OK == waitFinalResp(_cbCMGL, &param))
01682         ret = num - param.num;
01683     UNLOCK();
01684     return ret;
01685 }
01686 
01687 bool MDMParser::smsSend(const char* num, const char* buf)
01688 {
01689     bool ok = false;
01690     LOCK();
01691     sendFormated("AT+CMGS=\"%s\"\r\n",num);
01692     if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) {
01693         send(buf, strlen(buf));
01694         const char ctrlZ = 0x1A;
01695         send(&ctrlZ, sizeof(ctrlZ));
01696         ok = (RESP_OK == waitFinalResp());
01697     }
01698     UNLOCK();
01699     return ok;
01700 }
01701 
01702 bool MDMParser::smsDelete(int ix)
01703 {
01704     bool ok = false;
01705     LOCK();
01706     sendFormated("AT+CMGD=%d\r\n",ix);
01707     ok = (RESP_OK == waitFinalResp());
01708     UNLOCK();
01709     return ok;
01710 }
01711 
01712 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
01713 {
01714     if (param) {
01715         if (type == TYPE_PLUS) {
01716             if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) {
01717             }
01718         } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) {
01719             memcpy(param->buf, buf, len-2);
01720             param->buf[len-2] = '\0';
01721         }
01722     }
01723     return WAIT;
01724 }
01725 
01726 bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
01727 {
01728     bool ok = false;
01729     LOCK();
01730     CMGRparam param;
01731     param.num = num;
01732     param.buf = buf;
01733     sendFormated("AT+CMGR=%d\r\n",ix);
01734     ok = (RESP_OK == waitFinalResp(_cbCMGR, &param));
01735     UNLOCK();
01736     return ok;
01737 }
01738    
01739 // ----------------------------------------------------------------
01740   
01741 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp)
01742 {
01743     if ((type == TYPE_PLUS) && resp) {
01744         // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..);
01745         if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) {
01746             /*nothing*/            
01747         }
01748     }
01749     return WAIT;
01750 }  
01751 
01752 bool MDMParser::ussdCommand(const char* cmd, char* buf)
01753 {
01754     bool ok = false;
01755     LOCK();
01756     *buf = '\0';
01757     if (_dev.dev != DEV_LISA_C2) {
01758         sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
01759         ok = (RESP_OK == waitFinalResp(_cbCUSD, buf));
01760     }
01761     UNLOCK();
01762     return ok;
01763 }
01764 
01765 // ----------------------------------------------------------------
01766    
01767 int MDMParser::_cbUDELFILE(int type, const char* buf, int len, void*)
01768 {
01769     if ((type == TYPE_ERROR) && strstr(buf, "+CME ERROR: FILE NOT FOUND")) 
01770         return RESP_OK; // file does not exist, so all ok...
01771     return WAIT;
01772 }  
01773 
01774 bool MDMParser::delFile(const char* filename)
01775 {
01776     bool ok = false;
01777     LOCK();
01778     sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
01779     ok = (RESP_OK == waitFinalResp(_cbUDELFILE));
01780     UNLOCK();
01781     return ok;
01782 }
01783 
01784 int MDMParser::writeFile(const char* filename, const char* buf, int len)
01785 {
01786     bool ok = false;
01787     LOCK();
01788     sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
01789     if (RESP_PROMPT == waitFinalResp()) {
01790         send(buf, len);
01791         ok = (RESP_OK == waitFinalResp());
01792     }
01793     UNLOCK();
01794     return ok ? len : -1;
01795 }
01796 
01797 int MDMParser::readFile(const char* filename, char* buf, int len)
01798 {
01799     URDFILEparam param;
01800     param.filename = filename;
01801     param.buf = buf; 
01802     param.sz = len; 
01803     param.len = 0;
01804     LOCK();
01805     sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
01806     if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
01807         param.len = -1;
01808     UNLOCK();
01809     return param.len;
01810 }
01811 
01812 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param)
01813 {
01814     if ((type == TYPE_PLUS) && param && param->filename && param->buf) {
01815         char filename[48];
01816         int sz;
01817         if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) && 
01818             (0 == strcmp(param->filename, filename)) &&
01819             (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01820             param->len = (sz < param->sz) ? sz : param->sz;
01821             memcpy(param->buf, &buf[len-1-sz], param->len);
01822         }
01823     }
01824     return WAIT;
01825 }
01826 
01827 //The following function is useful for reading files with a dimension greater than MAX_SIZE bytes
01828 int MDMParser::readFileNew(const char* filename, char* buf, int len)
01829 {   
01830     int countBytes = -1;  //counter for file reading (default value)
01831     
01832     if(_dev.dev != DEV_LISA_C2)
01833     {
01834         //retrieve information about the file, in particular its size
01835         int filesize = infoFile(filename);
01836         TRACE("readFileNew: filename is %s; filesize is %d\r\n", filename, filesize);
01837         
01838         if (len < filesize)
01839             TRACE("readFileNew: WARNING. Buffer dimension is %d bytes," \
01840                   "while file size is %d bytes\r\n", len, filesize);
01841         
01842         if (filesize > 0)
01843         {
01844 #ifdef MDM_DEBUG
01845             memset(buf, '\0', len);
01846 #endif
01847             int offset = 0;              //start reading from 0
01848             int blockSize = MAX_SIZE;    //still need space for headers and unsolicited commands
01849             int bytesToRead = filesize;  //bytes to read 
01850             
01851             while (bytesToRead)
01852             {    
01853                 bool ok = false;
01854                 
01855                 if (bytesToRead < blockSize)
01856                     blockSize = bytesToRead;
01857                 
01858                 LOCK();
01859                 if (blockSize > 0) {
01860                             
01861                     sendFormated("AT+URDBLOCK=\"%s\",%d,%d\r\n", filename, offset, blockSize);
01862                     
01863                     if (RESP_OK == waitFinalResp(_cbURDBLOCK, buf)) {
01864                         bytesToRead -= blockSize;
01865                         offset += blockSize;
01866                         buf += blockSize;
01867                         ok = true;
01868                     } else {
01869                         //error condition
01870                         countBytes = -1;
01871                         ok = false;
01872                     }
01873                 }
01874                 UNLOCK();
01875                 
01876                 if (!ok) {
01877                     TRACE("readFileNew: ERROR\r\n");
01878                     return countBytes;  //in this case countBytes is -1
01879                 }
01880             }
01881             
01882             countBytes = offset;  //total read bytes
01883             return countBytes;
01884         }
01885     } else {
01886         TRACE("httpCommand: command not supported by module"); 
01887     }
01888     return countBytes;  //it could be 0 or -1 (possible error)    
01889 }
01890 
01891 int MDMParser::_cbURDBLOCK(int type, const char* buf, int len, char* out)
01892 {   
01893     char fileNameRes[48]; 
01894     int sizeRes;
01895     
01896     if ((type == TYPE_PLUS) && out) {
01897         if ((sscanf(buf, "\r\n+URDBLOCK: \"%[^\"]\",%d,", fileNameRes, &sizeRes) == 2) &&
01898             (buf[len-sizeRes-2] == '\"') && (buf[len-1] == '\"')) {
01899             memcpy(out, &buf[len-1-sizeRes], sizeRes);
01900         }
01901     }
01902     
01903     return WAIT;
01904 }
01905 
01906 int MDMParser::infoFile(const char* filename)
01907 {
01908     int infoFile = 0;  //default value
01909     
01910     LOCK();
01911     sendFormated("AT+ULSTFILE=2,\"%s\"\r\n", filename);
01912     if (RESP_OK != waitFinalResp(_cbULSTFILE, &infoFile))
01913         infoFile = -1;  //error condition    
01914     UNLOCK();
01915     
01916     return infoFile;
01917 }
01918 
01919 int MDMParser::_cbULSTFILE(int type, const char* buf, int len, int* infoFile)
01920 { 
01921     if (infoFile) {
01922         if (type == TYPE_PLUS) {
01923             if (sscanf(buf, "\r\n+ULSTFILE: %d\r\n", infoFile) == 1) {
01924             }
01925         }
01926     }
01927     return WAIT;
01928 }
01929 
01930 // ----------------------------------------------------------------
01931 int MDMParser::cellLocSrvTcp(const char* token, const char* server_1, const char* server_2, int days/* = 14*/, \
01932         int period/* = 4*/, int resolution/* = 1*/)
01933 {
01934     bool ok = false;
01935     LOCK();
01936     if (_dev.dev == DEV_LISA_U2_03S || _dev.dev == DEV_SARA_U2 ){
01937         sendFormated("AT+UGSRV=\"%s\",\"%s\",\"%s\"\r\n", server_1, server_2, token, days, period, resolution);
01938         ok = (RESP_OK == waitFinalResp());
01939     } else
01940         ERROR("Command not supported\r\n"); 
01941     UNLOCK();
01942     return ok;
01943 }
01944 
01945 int MDMParser::cellLocSrvUdp(const char* server_1 /*= "cell-live1.services.u-blox.com"*/, int port /*= 46434*/, \
01946         int latency/* = 1000*/, int mode/* = 0*/)
01947 {
01948     bool ok = false;
01949     LOCK();
01950     if (_dev.dev != DEV_TOBY_L2){
01951         sendFormated("AT+UGAOP=\"%s\",%d,%d,%d\r\n", server_1, port, latency, mode);
01952         ok = (RESP_OK == waitFinalResp());
01953     } else
01954         ERROR("Command not supported\r\n"); 
01955     UNLOCK();
01956     return ok;
01957 }
01958 
01959 int MDMParser::cellLocUnsol(int mode)
01960 {
01961     bool ok = false;
01962     LOCK();
01963     if (_dev.dev == DEV_LISA_U2_03S){
01964         sendFormated("AT+ULOCIND=%d\r\n", mode);
01965         ok = (RESP_OK == waitFinalResp());
01966     } else
01967         ERROR("Command not supported\r\n"); 
01968     UNLOCK();
01969     return ok;
01970 }
01971 
01972 int MDMParser::cellLocConfig(int scanMode)
01973 {
01974     bool ok = false;
01975     LOCK();
01976     if (_dev.dev != DEV_TOBY_L2){
01977         sendFormated("AT+ULOCCELL=%d\r\n", scanMode);
01978         ok = (RESP_OK == waitFinalResp());    
01979     }else
01980         ERROR("Command not supported\r\n"); 
01981     UNLOCK();
01982     return ok;
01983 }
01984 
01985 int MDMParser::cellLocRequest(CellSensType sensor, int timeout, int accuracy, CellRespType type/* =1*/, int hypotesis/* =1*/)
01986 {
01987     bool ok = false;
01988     
01989     if (hypotesis > 1 && type != CELL_MULTIHYP){
01990         ERROR("Num hypotesis is not set accordelying to CellRespType\r\n");
01991         return false;
01992         }        
01993     if (hypotesis > CELL_MAX_HYP){
01994         ERROR("Number of hypotesis is too big\r\n");
01995         return false;  
01996     }        
01997     LOCK();      
01998     _locRcvPos=0;
01999     _locExpPos=0;
02000     for (int i=0; i < hypotesis; i++)
02001         _loc[i].validData = false;          
02002     if (_dev.dev == DEV_LISA_U2_03S){
02003         sendFormated("AT+ULOC=2,%d,%d,%d,%d,%d\r\n", sensor, type, timeout, accuracy, hypotesis);        
02004         ok = (RESP_OK == waitFinalResp());
02005     } else if (_dev.dev != DEV_TOBY_L2){
02006         sendFormated("AT+ULOC=2,%d,1,%d,%d\r\n",  sensor, timeout, accuracy);
02007         ok = (RESP_OK == waitFinalResp());
02008     } else
02009         ERROR("Command not supported\r\n");  
02010     UNLOCK();
02011     return ok;
02012 }  
02013 int MDMParser::cellLocGetRes()
02014 {
02015     return _locRcvPos;
02016 }
02017 int MDMParser::cellLocGetExpRes()
02018 {
02019     int res=0;
02020     waitFinalResp(NULL,NULL,0);
02021     LOCK();
02022     if (_locRcvPos>0)
02023         res = _locExpPos;
02024     UNLOCK();
02025     return res;
02026 }
02027 
02028 int MDMParser::cellLocGetData(CellLocData *data, int index/*=0*/){
02029     
02030     if (!_loc[index].validData)
02031           return false;
02032     LOCK(); 
02033     memcpy(data, &_loc[index], sizeof(*_loc));
02034     UNLOCK();
02035     return true;
02036 }
02037 
02038 // ----------------------------------------------------------------
02039 bool MDMParser::setDebug (int level) 
02040 {
02041 #ifdef MDM_DEBUG
02042     _debugLevel = (level < -1) ? -1 : 
02043                   (level >  3) ?  3 : 
02044                                  level;
02045 #endif
02046     return _debugLevel == level;
02047 }
02048 
02049 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 
02050             _DPRINT dprint, void* param) 
02051 {
02052     dprint(param, "Modem::devStatus\r\n");
02053     const char* txtDev[] = { "Unknown",  "SARA-G35", "LISA-U2", "LISA-U2-03S", "LISA-C2", 
02054                              "SARA-U2",  "LEON-G2",  "TOBY-L2", "MPCI-L2" };
02055     if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN))
02056         dprint(param, "  Device:       %s\r\n", txtDev[status->dev]);
02057     const char* txtLpm[] = { "Disabled", "Enabled", "Active" };
02058     if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm))
02059         dprint(param, "  Power Save:   %s\r\n", txtLpm[status->lpm]);
02060     const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" };
02061     if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN))
02062         dprint(param, "  SIM:          %s\r\n", txtSim[status->sim]);
02063     if (*status->ccid)  
02064         dprint(param, "  CCID:         %s\r\n", status->ccid);
02065     if (*status->imei) 
02066         dprint(param, "  IMEI:         %s\r\n", status->imei);
02067     if (*status->imsi)  
02068         dprint(param, "  IMSI:         %s\r\n", status->imsi);
02069     if (*status->meid) 
02070         dprint(param, "  MEID:         %s\r\n", status->meid); // LISA-C
02071     if (*status->manu) 
02072         dprint(param, "  Manufacturer: %s\r\n", status->manu);
02073     if (*status->model)  
02074         dprint(param, "  Model:        %s\r\n", status->model);
02075     if (*status->ver)  
02076         dprint(param, "  Version:      %s\r\n", status->ver);
02077 }
02078 
02079 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status,
02080             _DPRINT dprint, void* param)
02081 {
02082     dprint(param, "Modem::netStatus\r\n");
02083     const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
02084     if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN))
02085         dprint(param, "  CSD Registration:   %s\r\n", txtReg[status->csd]);
02086     if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN))
02087         dprint(param, "  PSD Registration:   %s\r\n", txtReg[status->psd]);
02088     if (status->eps < sizeof(txtReg)/sizeof(*txtReg) && (status->eps != REG_UNKNOWN))
02089         dprint(param, "  EPS Registration:   %s\r\n", txtReg[status->eps]);
02090     const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA", "LTE" };
02091     if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN))
02092         dprint(param, "  Access Technology:  %s\r\n", txtAct[status->act]);
02093     if (status->rssi) 
02094         dprint(param, "  Signal Strength:    %d dBm\r\n", status->rssi);
02095     if (status->ber) 
02096         dprint(param, "  Bit Error Rate:     %d\r\n", status->ber);
02097     if (*status->opr)  
02098         dprint(param, "  Operator:           %s\r\n", status->opr);
02099     if (status->lac != 0xFFFF)  
02100         dprint(param, "  Location Area Code: %04X\r\n", status->lac);
02101     if (status->ci != 0xFFFFFFFF)  
02102         dprint(param, "  Cell ID:            %08X\r\n", status->ci);
02103     if (*status->num)  
02104         dprint(param, "  Phone Number:       %s\r\n", status->num);
02105 }
02106 
02107 void MDMParser::dumpIp(MDMParser::IP ip,
02108             _DPRINT dprint, void* param) 
02109 {
02110     if (ip != NOIP)
02111         dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip));
02112 }
02113     
02114 // ----------------------------------------------------------------
02115 int MDMParser::_parseMatch(Pipe<char> * pipe, int len, const char* sta, const char* end)
02116 {
02117     int o = 0;
02118     if (sta) {
02119         while (*sta) {
02120             if (++o > len)                  return WAIT;
02121             char ch = pipe->next();
02122             if (*sta++ != ch)               return NOT_FOUND;
02123         }
02124     }
02125     if (!end)                               return o; // no termination
02126     // at least any char
02127     if (++o > len)                      return WAIT;
02128     pipe->next();
02129     // check the end     
02130     int x = 0;
02131     while (end[x]) {
02132         if (++o > len)                      return WAIT;
02133         char ch = pipe->next();
02134         x = (end[x] == ch) ? x + 1 : 
02135             (end[0] == ch) ? 1 : 
02136                             0;
02137     }
02138     return o;
02139 }
02140 
02141 int MDMParser::_parseFormated(Pipe<char> * pipe, int len, const char* fmt)
02142 {
02143     int o = 0;
02144     int num = 0;
02145     if (fmt) {
02146         while (*fmt) {
02147             if (++o > len)                  return WAIT;
02148             char ch = pipe->next();
02149             if (*fmt == '%') {
02150                 fmt++;
02151                 if (*fmt == 'd') { // numeric
02152                     fmt ++;
02153                     num = 0;
02154                     while (ch >= '0' && ch <= '9') {
02155                         num = num * 10 + (ch - '0'); 
02156                         if (++o > len)      return WAIT;
02157                         ch = pipe->next();
02158                     }
02159                 }   
02160                 else if (*fmt == 'c') { // char buffer (takes last numeric as length)
02161                     fmt ++;
02162                     while (num --) {
02163                         if (++o > len)      return WAIT;
02164                         ch = pipe->next();
02165                     }   
02166                 }
02167                 else if (*fmt == 's') {
02168                     fmt ++;
02169                     if (ch != '\"')         return NOT_FOUND;
02170                     do {
02171                         if (++o > len)      return WAIT;
02172                         ch = pipe->next();
02173                     } while (ch != '\"');
02174                     if (++o > len)          return WAIT;
02175                     ch = pipe->next();
02176                 }
02177             }
02178             if (*fmt++ != ch)               return NOT_FOUND;
02179         }
02180     }
02181     return o; 
02182 }
02183 
02184 int MDMParser::_getLine(Pipe<char> * pipe, char* buf, int len)
02185 {
02186     int unkn = 0;
02187     int sz = pipe->size();
02188     int fr = pipe->free();
02189     if (len > sz)
02190         len = sz;
02191     while (len > 0)
02192     {
02193         static struct { 
02194               const char* fmt;                              int type; 
02195         } lutF[] = {
02196             { "\r\n+USORD: %d,%d,\"%c\"",                   TYPE_PLUS       },
02197             { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"",  TYPE_PLUS       },
02198             { "\r\n+URDFILE: %s,%d,\"%c\"",                 TYPE_PLUS       },
02199             { "\r\n+URDBLOCK: %s,%d,\"%c\"",                TYPE_PLUS       },
02200         };
02201         static struct { 
02202               const char* sta;          const char* end;    int type; 
02203         } lut[] = {
02204             { "\r\nOK\r\n",             NULL,               TYPE_OK         },
02205             { "\r\nERROR\r\n",          NULL,               TYPE_ERROR      },
02206             { "\r\n+CME ERROR:",        "\r\n",             TYPE_ERROR_CME      }, 
02207             { "\r\n+CMS ERROR:",        "\r\n",             TYPE_ERROR      },
02208             { "\r\nRING\r\n",           NULL,               TYPE_RING       },
02209             { "\r\nCONNECT\r\n",        NULL,               TYPE_CONNECT    },
02210             { "\r\nNO CARRIER\r\n",     NULL,               TYPE_NOCARRIER  },
02211             { "\r\nNO DIALTONE\r\n",    NULL,               TYPE_NODIALTONE },
02212             { "\r\nBUSY\r\n",           NULL,               TYPE_BUSY       },
02213             { "\r\nNO ANSWER\r\n",      NULL,               TYPE_NOANSWER   },
02214             { "\r\n+",                  "\r\n",             TYPE_PLUS       },
02215             { "\r\n@",                  NULL,               TYPE_PROMPT     }, // Sockets
02216             { "\r\n>",                  NULL,               TYPE_PROMPT     }, // SMS
02217             { "\n>",                    NULL,               TYPE_PROMPT     }, // File
02218         };
02219         for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) {
02220             pipe->set(unkn);
02221             int ln = _parseFormated(pipe, len, lutF[i].fmt);
02222             if (ln == WAIT && fr)                       
02223                 return WAIT;
02224             if ((ln != NOT_FOUND) && (unkn > 0))  
02225                 return TYPE_UNKNOWN | pipe->get (buf, unkn);
02226             if (ln > 0)
02227                 return lutF[i].type  | pipe->get (buf, ln);
02228         }
02229         for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) {
02230             pipe->set(unkn);
02231             int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end);
02232             if (ln == WAIT && fr)                       
02233                 return WAIT;
02234             if ((ln != NOT_FOUND) && (unkn > 0))  
02235                 return TYPE_UNKNOWN | pipe->get (buf, unkn);
02236             if (ln > 0)
02237                 return lut[i].type | pipe->get (buf, ln);
02238         }
02239         // UNKNOWN
02240         unkn ++;
02241         len--;
02242     }
02243     return WAIT;
02244 }
02245 
02246 // ----------------------------------------------------------------
02247 // Serial Implementation 
02248 // ----------------------------------------------------------------
02249 
02250 /*! Helper Dev Null Device 
02251     Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout
02252     is shared with the serial port of the modem. Having printfs inbetween the 
02253     AT commands you cause a failure of the modem.
02254 */
02255 class DevNull : public Stream {
02256 public: 
02257     DevNull() : Stream(_name+1) { }             //!< Constructor
02258     void claim(const char* mode, FILE* file) 
02259         { freopen(_name, mode, file); }         //!< claim a stream
02260 protected:
02261     virtual int _getc()         { return EOF; } //!< Nothing
02262     virtual int _putc(int c)    { return c; }   //!< Discard
02263     static const char* _name;                   //!< File name
02264 };
02265 const char* DevNull::_name = "/null";  //!< the null device name
02266 static      DevNull null;              //!< the null device
02267 
02268 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/, 
02269             int baudrate /*= MDMBAUD*/,
02270 #if DEVICE_SERIAL_FC
02271             PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/, 
02272 #endif
02273             int rxSize /*= 256*/, int txSize /*= 128*/) : 
02274             SerialPipe(tx, rx, baudrate, rxSize, txSize) 
02275 {
02276     if (rx == USBRX) 
02277         null.claim("r", stdin);
02278     if (tx == USBTX) {
02279         null.claim("w", stdout);
02280         null.claim("w", stderr);
02281 #ifdef MDM_DEBUG
02282         _debugLevel = -1;
02283 #endif
02284     }
02285 #ifdef TARGET_UBLOX_C027
02286     _onboard = (tx == MDMTXD) && (rx == MDMRXD);
02287     if (_onboard)
02288        c027_mdm_powerOn(false);
02289 #endif
02290     baud(baudrate);
02291 #if DEVICE_SERIAL_FC
02292     if ((rts != NC) || (cts != NC))
02293     {
02294         Flow flow = (cts == NC) ? RTS :
02295                     (rts == NC) ? CTS : RTSCTS ;
02296         set_flow_control(flow, rts, cts);
02297         if (cts != NC) _dev.lpm = LPM_ENABLED;
02298     }
02299 #endif
02300 }
02301 
02302 MDMSerial::~MDMSerial(void)
02303 {
02304     powerOff();
02305 #ifdef TARGET_UBLOX_C027
02306     if (_onboard)
02307         c027_mdm_powerOff();
02308 #endif
02309 }
02310 
02311 int MDMSerial::_send(const void* buf, int len)   
02312 { 
02313     return put((const char*)buf, len, true/*=blocking*/);
02314 }
02315 
02316 int MDMSerial::getLine(char* buffer, int length)
02317 {
02318     return _getLine(&_pipeRx, buffer, length);
02319 }
02320 
02321 // ----------------------------------------------------------------
02322 // USB Implementation 
02323 // ----------------------------------------------------------------
02324 
02325 #ifdef HAVE_MDMUSB
02326 MDMUsb::MDMUsb(void)                             
02327 { 
02328 #ifdef MDM_DEBUG
02329     _debugLevel = 1;
02330 #endif    
02331 #ifdef TARGET_UBLOX_C027
02332     _onboard = true;
02333     c027_mdm_powerOn(true);
02334 #endif
02335 }
02336 
02337 MDMUsb::~MDMUsb(void)
02338 {
02339     powerOff();
02340 #ifdef TARGET_UBLOX_C027
02341     if (_onboard)
02342         c027_mdm_powerOff();
02343 #endif
02344 }
02345 
02346 int MDMUsb::_send(const void* buf, int len)      { return 0; }
02347 
02348 int MDMUsb::getLine(char* buffer, int length)    { return NOT_FOUND; }
02349 
02350 #endif