irsan julfikar / C027_Support_New_

Fork of C027_Support_Plus_Dialing by irsan julfikar

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 #include <sstream>
00008                 
00009 #define PROFILE         "0"   //!< this is the psd profile used
00010 #define MAX_SIZE        128   //!< max expected messages
00011 // num sockets
00012 #define NUMSOCKETS      (sizeof(_sockets)/sizeof(*_sockets))
00013 //! test if it is a socket is ok to use
00014 #define ISSOCKET(s)     (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR))
00015 //! check for timeout
00016 #define TIMEOUT(t, ms)  ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 
00017 //! registration ok check helper
00018 #define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
00019 //! registration done check helper (no need to poll further)
00020 #define REG_DONE(r)     ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 
00021 //! helper to make sure that lock unlock pair is always balaced 
00022 #define LOCK()         { lock() 
00023 //! helper to make sure that lock unlock pair is always balaced 
00024 #define UNLOCK()       } unlock()
00025 
00026 #ifdef MDM_DEBUG
00027  #if 1 // colored terminal output using ANSI escape sequences
00028   #define COL(c) "\033[" c
00029  #else
00030   #define COL(c) 
00031  #endif
00032  #define DEF COL("39m")
00033  #define BLA COL("30m")
00034  #define RED COL("31m")
00035  #define GRE COL("32m")
00036  #define YEL COL("33m")
00037  #define BLU COL("34m")
00038  #define MAG COL("35m")
00039  #define CYA COL("36m")
00040  #define WHY COL("37m")
00041  
00042 void dumpAtCmd(const char* buf, int len)
00043 {
00044     ::printf(" %3d \"", len);
00045     while (len --) {
00046         char ch = *buf++;
00047         if ((ch > 0x1F) && (ch != 0x7F)) { // is printable
00048             if      (ch == '%')  ::printf("%%");
00049             else if (ch == '"')  ::printf("\\\"");
00050             else if (ch == '\\') ::printf("\\\\");
00051             else putchar(ch);
00052         } else {
00053             if      (ch == '\a') ::printf("\\a"); // BEL (0x07)
00054             else if (ch == '\b') ::printf("\\b"); // Backspace (0x08)
00055             else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09)
00056             else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A)
00057             else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B)
00058             else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C)
00059             else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D)
00060             else                 ::printf("\\x%02x", (unsigned char)ch);
00061         }
00062     }
00063     ::printf("\"\r\n");
00064 }
00065  
00066 void MDMParser::_debugPrint(int level, const char* color, const char* format, ...)
00067 {
00068     if (_debugLevel >= level) 
00069     {
00070         va_list args;
00071         va_start (args, format);
00072         if (color) ::printf(color);
00073         ::vprintf(format, args);
00074         if (color) ::printf(DEF);
00075         va_end (args);
00076     }
00077 }
00078    
00079  #define ERROR(...)     _debugPrint(0, RED, __VA_ARGS__)
00080  #define INFO(...)      _debugPrint(1, GRE, __VA_ARGS__)
00081  #define TRACE(...)     _debugPrint(2, DEF, __VA_ARGS__)
00082  #define TEST(...)      _debugPrint(3, CYA, __VA_ARGS__)
00083  
00084 #else
00085  
00086  #define ERROR(...) (void)0 // no tracing
00087  #define TEST(...)  (void)0 // no tracing
00088  #define INFO(...)  (void)0 // no tracing
00089  #define TRACE(...) (void)0 // no tracing
00090 
00091 #endif
00092 
00093 MDMParser* MDMParser::inst;
00094 
00095 MDMParser::MDMParser(void)
00096 {
00097     inst = this;
00098     memset(&_dev, 0, sizeof(_dev));
00099     memset(&_net, 0, sizeof(_net));
00100     _net.lac = 0xFFFF;
00101     _net.ci = 0xFFFFFFFF;
00102     _ip        = NOIP;
00103     _init      = false;
00104     memset(_sockets, 0, sizeof(_sockets));
00105     for (int socket = 0; socket < NUMSOCKETS; socket ++)
00106         _sockets[socket].handle = SOCKET_ERROR;
00107 #ifdef MDM_DEBUG
00108     _debugLevel = 1;
00109     _debugTime.start();
00110 #endif
00111 }
00112 
00113 int MDMParser::send(const char* buf, int len)
00114 {
00115 #ifdef MDM_DEBUG
00116     if (_debugLevel >= 3) {
00117         ::printf("%10.3f AT send    ", _debugTime.read_ms()*0.001);
00118         dumpAtCmd(buf,len);
00119     }
00120 #endif
00121     return _send(buf, len);
00122 }
00123 
00124 int MDMParser::sendFormated(const char* format, ...) {
00125     char buf[MAX_SIZE];
00126     va_list args;
00127     va_start(args, format);
00128     int len = vsnprintf(buf,sizeof(buf), format, args);
00129     va_end(args);
00130     return send(buf, len);
00131 }
00132 
00133 int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/, 
00134                              void* param /* = NULL*/, 
00135                              int timeout_ms /*= 5000*/)
00136 {
00137     char buf[MAX_SIZE + 64 /* add some more space for framing */]; 
00138     Timer timer;
00139     timer.start();
00140     do {
00141         int ret = getLine(buf, sizeof(buf));
00142 #ifdef MDM_DEBUG
00143         if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
00144         {
00145             int len = LENGTH(ret);
00146             int type = TYPE(ret);
00147             const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 
00148                             (type == TYPE_TEXT)   ? MAG "TXT" DEF : 
00149                             (type == TYPE_OK   )  ? GRE "OK " DEF : 
00150                             (type == TYPE_ERROR)  ? RED "ERR" DEF : 
00151                             (type == TYPE_PLUS)   ? CYA " + " DEF : 
00152                             (type == TYPE_PROMPT) ? BLU " > " DEF :
00153                             (type == TYPE_NOCARRIER)? CYA "NO" DEF :
00154                             (type == TYPE_RING) ? CYA "RING" DEF : 
00155                                                         "..." ;
00156             ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
00157             dumpAtCmd(buf, len);
00158         }
00159 #endif        
00160         if ((ret != WAIT) && (ret != NOT_FOUND))
00161         {
00162             int type = TYPE(ret);
00163             // handle unsolicited commands here
00164             if (type == TYPE_PLUS) {
00165                 const char* cmd = buf+3;
00166                 int a, b, c, d, r;
00167                 char s[32];
00168 
00169                 // SMS Command ---------------------------------
00170                 // +CNMI: <mem>,<index>
00171                 if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 
00172                     TRACE("New SMS at index %d\r\n", a);
00173                 // Socket Specific Command ---------------------------------
00174                 // +UUSORD: <socket>,<length>
00175                 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2)) {
00176                     int socket = _findSocket(a);
00177                     TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
00178                     if (socket != SOCKET_ERROR)
00179                         _sockets[socket].pending = b;
00180                 // +UUSORF: <socket>,<length>
00181                 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) {
00182                     int socket = _findSocket(a);
00183                     TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
00184                     if (socket != SOCKET_ERROR)
00185                         _sockets[socket].pending = b;
00186                 // +UUSOCL: <socket>
00187                 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) {
00188                     int socket = _findSocket(a);
00189                     TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a);
00190                     if ((socket != SOCKET_ERROR) && _sockets[socket].connected)
00191                         _sockets[socket].connected = false;
00192                 }
00193                 if (_dev.dev == DEV_LISA_C200) {
00194                     // CDMA Specific -------------------------------------------
00195                     // +CREG: <n><SID>,<NID>,<stat>
00196                     if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
00197                         // _net.sid = a;
00198                         // _net.nid = b;
00199                         if      (c == 0) _net.csd = REG_NONE;     // not registered, home network
00200                         else if (c == 1) _net.csd = REG_HOME;     // registered, home network
00201                         else if (c == 2) _net.csd = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
00202                         else if (c == 3) _net.csd = REG_DENIED;   // registration denied
00203                         else if (c == 5) _net.csd = REG_ROAMING;  // registered, roaming
00204                         _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
00205                         _net.act = ACT_CDMA;
00206                         // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
00207                     } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
00208                         //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
00209                     }
00210                 } else {
00211                     // GSM/UMTS Specific -------------------------------------------
00212                     // +UUPSDD: <profile_id> 
00213                     if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
00214                         if (*PROFILE == a) _ip = NOIP;
00215                     } else {
00216                         // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
00217                         // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]]     // URC
00218                         b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
00219                         r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
00220                         if (r <= 1)
00221                             r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
00222                         if (r >= 2) {
00223                             Reg *reg = !strcmp(s, "CREG:")  ? &_net.csd : 
00224                                        !strcmp(s, "CGREG:") ? &_net.psd : NULL;
00225                             if (reg) {
00226                                 // network status
00227                                 if      (a == 0) *reg = REG_NONE;     // 0: not registered, home network
00228                                 else if (a == 1) *reg = REG_HOME;     // 1: registered, home network
00229                                 else if (a == 2) *reg = REG_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
00230                                 else if (a == 3) *reg = REG_DENIED;   // 3: registration denied
00231                                 else if (a == 4) *reg = REG_UNKNOWN;  // 4: unknown
00232                                 else if (a == 5) *reg = REG_ROAMING;  // 5: registered, roaming
00233                                 if ((r >= 3) && (b != 0xFFFF))      _net.lac = b; // location area code
00234                                 if ((r >= 4) && (c != 0xFFFFFFFF))  _net.ci  = c; // cell ID
00235                                 // access technology
00236                                 if (r >= 5) {
00237                                     if      (d == 0) _net.act = ACT_GSM;      // 0: GSM
00238                                     else if (d == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
00239                                     else if (d == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
00240                                     else if (d == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
00241                                     else if (d == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
00242                                     else if (d == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
00243                                     else if (d == 6) _net.act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
00244                                 }
00245                             }
00246                         }
00247                     }
00248                 }
00249             }
00250             if (cb) {
00251                 int len = LENGTH(ret);
00252                 int ret = cb(type, buf, len, param);
00253                 if (WAIT != ret)
00254                     return ret; 
00255             }
00256             if (type == TYPE_OK)
00257                 return RESP_OK;
00258             if (type == TYPE_ERROR)
00259                 return RESP_ERROR;
00260             if (type == TYPE_PROMPT)    
00261                 return RESP_PROMPT;
00262         }
00263         // relax a bit
00264         wait_ms(10); 
00265     }
00266     while (!TIMEOUT(timer, timeout_ms));
00267     return WAIT;
00268 }
00269 
00270 int MDMParser::_cbString(int type, const char* buf, int len, char* str)
00271 {
00272     if (str && (type == TYPE_UNKNOWN)) {
00273         if (sscanf(buf, "\r\n%s\r\n", str) == 1)
00274             /*nothing*/;
00275     }
00276     return WAIT;
00277 }
00278 
00279 int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
00280 {
00281     if (val && (type == TYPE_UNKNOWN)) {
00282         if (sscanf(buf, "\r\n%d\r\n", val) == 1)
00283             /*nothing*/;
00284     }
00285     return WAIT;
00286 }
00287 
00288 // ----------------------------------------------------------------
00289 
00290 bool MDMParser::connect(
00291             const char* simpin, 
00292             const char* apn, const char* username, 
00293             const char* password, Auth auth,
00294             PinName pn)
00295 {
00296     bool ok = init(simpin, NULL, pn);  
00297 #ifdef MDM_DEBUG
00298     if (_debugLevel >= 1) dumpDevStatus(&_dev);
00299 #endif
00300     if (!ok)
00301         return false;
00302     ok = registerNet();
00303 #ifdef MDM_DEBUG
00304     if (_debugLevel >= 1) dumpNetStatus(&_net);
00305 #endif
00306     if (!ok)
00307         return false;
00308     IP ip = join(apn,username,password,auth);
00309 #ifdef MDM_DEBUG
00310     if (_debugLevel >= 1) dumpIp(ip);
00311 #endif
00312     if (ip == NOIP)
00313         return false; 
00314     return true;
00315 }
00316 
00317 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
00318 {
00319     int i = 10;
00320     LOCK();
00321     memset(&_dev, 0, sizeof(_dev));
00322     if (pn != NC) {
00323         INFO("Modem::wakeup\r\n");
00324         DigitalOut pin(pn, 1);
00325         while (i--) {
00326             // SARA-U2/LISA-U2 50..80us
00327             /*pin = 0; ::wait_us(50);
00328             pin = 1; ::wait_ms(10); 
00329             */
00330             // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms
00331             pin = 0; ::wait_ms(150);
00332             pin = 1; ::wait_ms(100);
00333             
00334             // purge any messages 
00335             purge();
00336             
00337             // check interface
00338             sendFormated("AT\r\n");
00339             int r = waitFinalResp(NULL,NULL,1000);
00340             if(RESP_OK == r) break;
00341         }
00342         if (i < 0) {
00343             ERROR("No Reply from Modem\r\n");
00344             goto failure;
00345         }
00346     }
00347     _init = true;
00348     
00349     INFO("Modem::init\r\n");
00350     // echo off
00351     sendFormated("AT E0\r\n");
00352     if(RESP_OK != waitFinalResp())
00353         goto failure; 
00354     // enable verbose error messages
00355     sendFormated("AT+CMEE=2\r\n");
00356     if(RESP_OK != waitFinalResp())
00357         goto failure;
00358     // set baud rate
00359     sendFormated("AT+IPR=115200\r\n");
00360     if (RESP_OK != waitFinalResp())
00361         goto failure;
00362     // wait some time until baudrate is applied
00363     wait_ms(200); // SARA-G > 40ms
00364     // identify the module 
00365     sendFormated("ATI\r\n");
00366     if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
00367         goto failure;
00368     if (_dev.dev == DEV_UNKNOWN)
00369         goto failure;
00370     // device specific init
00371     if (_dev.dev == DEV_LISA_C200) {
00372         // get the manufacturer
00373         sendFormated("AT+GMI\r\n");
00374         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
00375             goto failure;
00376         // get the model identification
00377         sendFormated("AT+GMM\r\n");
00378         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
00379             goto failure;
00380         // get the sw version
00381         sendFormated("AT+GMR\r\n");
00382         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
00383             goto failure;
00384         // get the pseudo ESN or MEID
00385         sendFormated("AT+GSN\r\n");
00386         if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
00387             goto failure;
00388 #if 0
00389         // enable power saving
00390         if (_dev.lpm != LPM_DISABLED) {
00391              // enable power saving (requires flow control, cts at least)
00392             sendFormated("AT+UPSV=1,1280\r\n");
00393             if (RESP_OK != waitFinalResp())
00394                 goto failure;  
00395             _dev.lpm = LPM_ACTIVE;
00396         }
00397 #endif
00398     } else {
00399         if ((_dev.dev == DEV_LISA_U200) || (_dev.dev == DEV_LEON_G200)) {
00400             // enable the network identification feature 
00401             sendFormated("AT+UGPIOC=20,2\r\n");
00402             if (RESP_OK != waitFinalResp())
00403                 goto failure;
00404         } else if ((_dev.dev == DEV_SARA_U260) || (_dev.dev == DEV_SARA_U270) || 
00405                    (_dev.dev == DEV_SARA_G350)) {
00406             // enable the network identification feature 
00407             sendFormated("AT+UGPIOC=16,2\r\n");
00408             if (RESP_OK != waitFinalResp())
00409                 goto failure;
00410         }
00411         // check the sim card
00412         for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
00413             sendFormated("AT+CPIN?\r\n");
00414             int ret = waitFinalResp(_cbCPIN, &_dev.sim);
00415             // having an error here is ok (sim may still be initializing)
00416             if ((RESP_OK != ret) && (RESP_ERROR != ret))
00417                 goto failure;
00418             // Enter PIN if needed
00419             if (_dev.sim == SIM_PIN) {
00420                 if (!simpin) {
00421                     ERROR("SIM PIN not available\r\n");
00422                     goto failure;
00423                 }
00424                 sendFormated("AT+CPIN=%s\r\n", simpin);
00425                 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
00426                     goto failure;
00427             } else if (_dev.sim != SIM_READY) {
00428                 wait_ms(1000);
00429             }
00430         }
00431         if (_dev.sim != SIM_READY) {
00432             if (_dev.sim == SIM_MISSING)
00433                 ERROR("SIM not inserted\r\n");
00434             goto failure;
00435         }
00436         // stop message waaiting indication
00437         sendFormated("AT+UMWI=0\r\n");
00438         waitFinalResp();
00439         // get the manufacturer
00440         sendFormated("AT+CGMI\r\n");
00441         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
00442             goto failure;
00443         // get the model identification
00444         sendFormated("AT+CGMM\r\n");
00445         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
00446             goto failure;
00447         // get the 
00448         sendFormated("AT+CGMR\r\n");
00449         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
00450             goto failure;
00451         // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 
00452         // ICCID is a serial number identifying the SIM.
00453         sendFormated("AT+CCID\r\n");
00454         if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
00455             goto failure;
00456         // Returns the product serial number, IMEI (International Mobile Equipment Identity)
00457         sendFormated("AT+CGSN\r\n");
00458         if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
00459             goto failure;
00460         // enable power saving
00461         if (_dev.lpm != LPM_DISABLED) {
00462              // enable power saving (requires flow control, cts at least)
00463             sendFormated("AT+UPSV=1\r\n");
00464             if (RESP_OK != waitFinalResp())
00465                 goto failure;  
00466             _dev.lpm = LPM_ACTIVE;
00467         }
00468         // enable the psd registration unsolicited result code
00469         sendFormated("AT+CGREG=2\r\n");
00470         if (RESP_OK != waitFinalResp())
00471             goto failure;
00472     } 
00473     // enable the network registration unsolicited result code
00474     sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
00475     if (RESP_OK != waitFinalResp())
00476         goto failure;
00477     // Setup SMS in text mode 
00478     sendFormated("AT+CMGF=1\r\n");
00479     if (RESP_OK != waitFinalResp())
00480         goto failure;
00481     // setup new message indication
00482     sendFormated("AT+CNMI=2,1\r\n");
00483     if (RESP_OK != waitFinalResp())
00484         goto failure;
00485     // setup report
00486     sendFormated("AT+CMER=1,0,0,2,1\r\n");
00487     if (RESP_OK != waitFinalResp())
00488         goto failure;
00489     // Request IMSI (International Mobile Subscriber Identification)
00490     sendFormated("AT+CIMI\r\n");
00491     if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
00492         goto failure;
00493     
00494     if (status)
00495         memcpy(status, &_dev, sizeof(DevStatus));
00496     UNLOCK();
00497     return true; 
00498 failure:
00499     unlock();
00500     return false; 
00501 }
00502 
00503 bool MDMParser::powerOff(void)
00504 {
00505     bool ok = false;
00506     if (_init) {
00507         LOCK();
00508         INFO("Modem::powerOff\r\n");
00509         sendFormated("AT+CPWROFF\r\n");
00510         if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) {
00511             _init = false;
00512             ok = true;
00513         }
00514         UNLOCK();
00515     }
00516     return ok;
00517 }
00518 
00519 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
00520 {
00521     if ((type == TYPE_UNKNOWN) && dev) {
00522         if      (strstr(buf, "SARA-G350")) *dev = DEV_SARA_G350;
00523         else if (strstr(buf, "LISA-U200")) *dev = DEV_LISA_U200;
00524         else if (strstr(buf, "LISA-C200")) *dev = DEV_LISA_C200;
00525         else if (strstr(buf, "SARA-U260")) *dev = DEV_SARA_U260;
00526         else if (strstr(buf, "SARA-U270")) *dev = DEV_SARA_U270;
00527         else if (strstr(buf, "LEON-G200")) *dev = DEV_LEON_G200;
00528     }
00529     return WAIT;
00530 }
00531 
00532 int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
00533 {
00534     if (sim) {
00535         if (type == TYPE_PLUS){
00536             char s[16];
00537             if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1)
00538                 *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN;
00539         } else if (type == TYPE_ERROR) {
00540             if (strstr(buf, "+CME ERROR: SIM not inserted"))
00541                 *sim = SIM_MISSING;
00542         }
00543     }
00544     return WAIT;
00545 }
00546 
00547 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
00548 {
00549     if ((type == TYPE_PLUS) && ccid){
00550         if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
00551             /*TRACE("Got CCID: %s\r\n", ccid)*/;
00552     }
00553     return WAIT;
00554 }
00555 
00556 bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/) 
00557 {
00558     Timer timer;
00559     timer.start();
00560     INFO("Modem::register\r\n");
00561     while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
00562         wait_ms(1000);
00563     if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
00564     if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
00565     return REG_OK(_net.csd) || REG_OK(_net.psd);
00566 }
00567 
00568 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
00569 {
00570     bool ok = false;
00571     LOCK();
00572     memset(&_net, 0, sizeof(_net));
00573     _net.lac = 0xFFFF;
00574     _net.ci = 0xFFFFFFFF;
00575     // check registration
00576     sendFormated("AT+CREG?\r\n");
00577     waitFinalResp();     // don't fail as service could be not subscribed 
00578     if (_dev.dev != DEV_LISA_C200) {
00579         // check PSD registration
00580         sendFormated("AT+CGREG?\r\n");
00581         waitFinalResp(); // don't fail as service could be not subscribed 
00582     }
00583     if (REG_OK(_net.csd) || REG_OK(_net.psd))
00584     {
00585         // check modem specific status messages 
00586         if (_dev.dev == DEV_LISA_C200) {
00587             sendFormated("AT+CSS?\r\n");
00588             if (RESP_OK != waitFinalResp())
00589                 goto failure;
00590             while (1) {
00591                 // get the Telephone number
00592                 sendFormated("AT$MDN?\r\n");
00593                 if (RESP_OK != waitFinalResp(_cbString, _net.num))
00594                     goto failure;
00595                 // check if we have a Mobile Directory Number
00596                 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
00597                     break;
00598                     
00599                 INFO("Device not yet activated\r\n");
00600                 INFO("Make sure you have a valid contract with the network operator for this device.\r\n");
00601                 // Check if the the version contains a V for Verizon 
00602                 // Verizon: E0.V.xx.00.xxR, 
00603                 // Sprint E0.S.xx.00.xxR
00604                 if (_dev.ver[3] == 'V') { 
00605                     int i;
00606                     INFO("Start device over-the-air activation (this can take a few minutes)\r\n");
00607                     sendFormated("AT+CDV=*22899\r\n");
00608                     i = 1;
00609                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
00610                         ERROR("Device over-the-air activation failed\r\n");
00611                         goto failure;
00612                     }
00613                     INFO("Device over-the-air activation successful\r\n");
00614                     
00615                     INFO("Start PRL over-the-air update (this can take a few minutes)\r\n");
00616                     sendFormated("AT+CDV=*22891\r\n");
00617                     i = 1;
00618                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
00619                         ERROR("PRL over-the-air update failed\r\n");
00620                         goto failure;
00621                     }
00622                     INFO("PRL over-the-air update successful\r\n");
00623                     
00624                 } else { 
00625                     // Sprint or Aeris 
00626                     INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
00627                     wait_ms(120*1000);
00628                 }
00629             }
00630             // get the the Network access identifier string
00631             char nai[64];
00632             sendFormated("AT$QCMIPNAI?\r\n");
00633             if (RESP_OK != waitFinalResp(_cbString, nai))
00634                 goto failure;
00635         } else {
00636             sendFormated("AT+COPS?\r\n");
00637             if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
00638                 goto failure;
00639             // get the MSISDNs related to this subscriber
00640             sendFormated("AT+CNUM\r\n");
00641             if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
00642                 goto failure;
00643         }  
00644         // get the signal strength indication
00645         sendFormated("AT+CSQ\r\n");
00646         if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
00647             goto failure;
00648     }
00649     if (status) {
00650         memcpy(status, &_net, sizeof(NetStatus));
00651     }
00652     ok = REG_DONE(_net.csd) && REG_DONE(_net.psd);
00653     UNLOCK();
00654     return ok;
00655 failure:
00656     unlock();
00657     return false;
00658 }
00659 
00660 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
00661 {
00662     if ((type == TYPE_PLUS) && status){
00663         int act = 99;
00664         // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
00665         if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) {
00666             if      (act == 0) status->act = ACT_GSM;      // 0: GSM, 
00667             else if (act == 2) status->act = ACT_UTRAN;    // 2: UTRAN
00668         }
00669     }
00670     return WAIT;
00671 }
00672 
00673 int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
00674 {
00675     if ((type == TYPE_PLUS) && num){
00676         int a;
00677         if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 
00678             ((a == 129) || (a == 145))) {
00679         }
00680     }
00681     return WAIT;
00682 }
00683                     
00684 int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status)
00685 {
00686     if ((type == TYPE_PLUS) && status){
00687         int a,b;
00688         char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4
00689         // +CSQ: <rssi>,<qual>
00690         if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) {
00691             if (a != 99) status->rssi = -113 + 2*a;  // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
00692             if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b];  // 
00693         }
00694     }
00695     return WAIT;
00696 }
00697 
00698 int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i)
00699 {
00700     if ((type == TYPE_PLUS) && i){
00701         int a;
00702         if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) {
00703             *i = a;
00704         }
00705     }
00706     return WAIT;
00707 }
00708 
00709 // ----------------------------------------------------------------
00710 // internet connection 
00711 
00712 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 
00713                               const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
00714 {
00715     LOCK();
00716     INFO("Modem::join\r\n");
00717     _ip = NOIP;
00718     if (_dev.dev == DEV_LISA_C200) {
00719         // make a dumy dns lookup (which will fail, so ignore the result) 
00720         sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n");
00721         waitFinalResp(); 
00722         // This fake lookup will enable the IP connection and we 
00723         // should have an IP after this, so we check it
00724         
00725         //Get local IP address
00726         sendFormated("AT+CMIP?\r\n");
00727         if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
00728             goto failure;
00729     } else { 
00730         // check gprs attach status 
00731         sendFormated("AT+CGATT=1\r\n");
00732         if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 
00733             goto failure;
00734         
00735         // Check the profile
00736         int a = 0;
00737         bool force = true;
00738         sendFormated("AT+UPSND=" PROFILE ",8\r\n");
00739         if (RESP_OK != waitFinalResp(_cbUPSND, &a))
00740             goto failure;
00741         if (a == 1 && force) {
00742             // disconnect the profile already if it is connected 
00743             sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
00744             if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
00745                 goto failure;
00746             a = 0;
00747         }
00748         if (a == 0) {
00749             bool ok = false;
00750             // try to lookup the apn settings from our local database by mccmnc
00751             const char* config = NULL;
00752             if (!apn && !username && !password)
00753                 config = apnconfig(_dev.imsi);
00754             
00755             // Set up the dynamic IP address assignment.
00756             sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
00757             if (RESP_OK != waitFinalResp())
00758                 goto failure;
00759  
00760             do {
00761                 if (config) {
00762                     apn      = _APN_GET(config);
00763                     username = _APN_GET(config);
00764                     password = _APN_GET(config);
00765                     TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\")\r\n", apn, username, password);
00766                 }
00767                 // Set up the APN
00768                 if (apn && *apn) {
00769                     sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
00770                     if (RESP_OK != waitFinalResp())
00771                         goto failure;
00772                 }
00773                 if (username && *username) {
00774                     sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
00775                     if (RESP_OK != waitFinalResp())
00776                         goto failure;
00777                 }
00778                 if (password && *password) {
00779                     sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
00780                     if (RESP_OK != waitFinalResp())
00781                         goto failure;
00782                 }
00783                 // try different Authentication Protocols
00784                 // 0 = none 
00785                 // 1 = PAP (Password Authentication Protocol)
00786                 // 2 = CHAP (Challenge Handshake Authentication Protocol)
00787                 for (int i = AUTH_NONE; i <= AUTH_CHAP && !ok; i ++) {
00788                     if ((auth == AUTH_DETECT) || (auth == i)) {
00789                         // Set up the Authentication Protocol
00790                         sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
00791                         if (RESP_OK != waitFinalResp())
00792                             goto failure;
00793                         // Activate the profile and make connection
00794                         sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
00795                         if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
00796                             ok = true;
00797                     }
00798                 }
00799             } while (!ok && config && *config); // maybe use next setting ? 
00800             if (!ok) {
00801                 ERROR("Your modem APN/password/username may be wrong\r\n");
00802                 goto failure;
00803             }
00804         }
00805         //Get local IP address
00806         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
00807         if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
00808             goto failure;
00809     }
00810     UNLOCK();
00811     return _ip;
00812 failure: 
00813     unlock();
00814     return NOIP;
00815 }
00816 
00817 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc)
00818 {
00819     if ((type == TYPE_PLUS) && mccmnc) {
00820         if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1)
00821             ;
00822     }
00823     return WAIT;
00824 }
00825 
00826 int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip)
00827 {
00828     if ((type == TYPE_UNKNOWN) && ip) {
00829         int a,b,c,d;
00830         if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4)
00831             *ip = IPADR(a,b,c,d);
00832     }
00833     return WAIT;
00834 }
00835         
00836 int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
00837 {
00838     if ((type == TYPE_PLUS) && act) {
00839         if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
00840             /*nothing*/;
00841     }
00842     return WAIT;
00843 }
00844 
00845 int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
00846 {
00847     if ((type == TYPE_PLUS) && ip) {
00848         int a,b,c,d;
00849         // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
00850         if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
00851             *ip = IPADR(a,b,c,d);
00852     }
00853     return WAIT;
00854 }
00855 
00856 int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
00857 {
00858     if ((type == TYPE_PLUS) && ip) {
00859         int a,b,c,d;
00860         if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4)
00861             *ip = IPADR(a,b,c,d);
00862     }
00863     return WAIT;
00864 }
00865 
00866 bool MDMParser::disconnect(void)
00867 {
00868     bool ok = false;
00869     LOCK();
00870     INFO("Modem::disconnect\r\n");
00871     if (_ip != NOIP) {
00872         if (_dev.dev == DEV_LISA_C200) {
00873             // There something to do here
00874             _ip = NOIP;
00875             ok = true;
00876         } else { 
00877             sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
00878             if (RESP_OK != waitFinalResp()) {
00879                 _ip = NOIP;
00880                 ok = true;
00881             }
00882         }
00883     }
00884     UNLOCK();
00885     return ok;
00886 }
00887 
00888 MDMParser::IP MDMParser::gethostbyname(const char* host)
00889 {
00890     IP ip = NOIP; 
00891     int a,b,c,d;
00892     if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
00893         ip = IPADR(a,b,c,d);
00894     else {
00895         LOCK();
00896         sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
00897         if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
00898             ip = NOIP;
00899         UNLOCK();
00900     }
00901     return ip;
00902 }
00903 
00904 // ----------------------------------------------------------------
00905 // sockets
00906 
00907 int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle)
00908 {
00909     if ((type == TYPE_PLUS) && handle) {
00910         // +USOCR: socket
00911         if (sscanf(buf, "\r\n+USOCR: %d", handle) == 1)
00912             /*nothing*/;  
00913     }
00914     return WAIT;
00915 }
00916 
00917 int MDMParser::socketSocket(IpProtocol ipproto, int port)
00918 {
00919     int socket;
00920     LOCK();
00921     // find an free socket
00922     socket = _findSocket();
00923     TRACE("socketSocket(%d)\r\n", ipproto);
00924     if (socket != SOCKET_ERROR) {
00925         if (ipproto == IPPROTO_UDP) {
00926             // sending port can only be set on 2G/3G modules
00927             if ((port != -1) && (_dev.dev != DEV_LISA_C200)) {
00928                 sendFormated("AT+USOCR=17,%d\r\n", port);
00929             } else {
00930                 sendFormated("AT+USOCR=17\r\n");
00931             }
00932         } else /*(ipproto == IPPROTO_TCP)*/ {
00933             sendFormated("AT+USOCR=6\r\n");
00934         } 
00935         int handle = SOCKET_ERROR;
00936         if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) && 
00937             (handle != SOCKET_ERROR)) {
00938             TRACE("Socket %d: handle %d was created\r\n", socket, handle);
00939             _sockets[socket].handle     = handle;
00940             _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
00941             _sockets[socket].connected  = false;
00942             _sockets[socket].pending    = 0;
00943         }
00944         else
00945             socket = SOCKET_ERROR;
00946     }
00947     UNLOCK();
00948     return socket;
00949 }
00950 
00951 bool MDMParser::socketConnect(int socket, const char * host, int port)
00952 {
00953     IP ip = gethostbyname(host);
00954     if (ip == NOIP)
00955         return false;
00956     // connect to socket
00957     bool ok = false; 
00958     LOCK();
00959     if (ISSOCKET(socket) && (!_sockets[socket].connected)) {
00960         TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port);
00961         sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port);
00962         if (RESP_OK == waitFinalResp())
00963             ok = _sockets[socket].connected = true;
00964     }
00965     UNLOCK();
00966     return ok;
00967 }
00968 
00969 bool MDMParser::socketIsConnected(int socket)
00970 {
00971     bool ok = false;
00972     LOCK();
00973     ok = ISSOCKET(socket) && _sockets[socket].connected;
00974     TRACE("socketIsConnected(%d) %s\r\n", socket, ok?"yes":"no");
00975     UNLOCK();
00976     return ok;
00977 }
00978 
00979 bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
00980 {
00981     bool ok = false;
00982     LOCK();
00983     TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms);
00984     if (ISSOCKET(socket)) {
00985         _sockets[socket].timeout_ms = timeout_ms;
00986         ok = true;
00987     }
00988     UNLOCK();
00989     return ok;
00990 }
00991 
00992 bool  MDMParser::socketClose(int socket)
00993 {
00994     bool ok = false;
00995     LOCK();
00996     if (ISSOCKET(socket) && _sockets[socket].connected) {
00997         TRACE("socketClose(%d)\r\n", socket);
00998         sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle);
00999         if (RESP_OK == waitFinalResp()) {
01000             _sockets[socket].connected = false;
01001             ok = true;
01002         }
01003     }
01004     UNLOCK();
01005     return ok;
01006 }
01007 
01008 bool  MDMParser::socketFree(int socket)
01009 {
01010     // make sure it is closed
01011     socketClose(socket);
01012     bool ok = true;
01013     LOCK();
01014     if (ISSOCKET(socket)) {
01015         TRACE("socketFree(%d)\r\n",  socket);
01016         _sockets[socket].handle     = SOCKET_ERROR;
01017         _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
01018         _sockets[socket].connected  = false;
01019         _sockets[socket].pending    = 0;
01020         ok = true;
01021     }
01022     UNLOCK();
01023     return ok;
01024 }
01025 
01026 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
01027 
01028 int MDMParser::socketSend(int socket, const char * buf, int len)
01029 {
01030     TRACE("socketSend(%d,,%d)\r\n", socket,len);
01031     int cnt = len;
01032     while (cnt > 0) {
01033         int blk = USO_MAX_WRITE;
01034         if (cnt < blk) 
01035             blk = cnt;
01036         bool ok = false;
01037         LOCK();
01038         if (ISSOCKET(socket)) {
01039             sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk);
01040             if (RESP_PROMPT == waitFinalResp()) {
01041                 wait_ms(50);
01042                 send(buf, blk);
01043                 if (RESP_OK == waitFinalResp()) 
01044                     ok = true;
01045             }
01046         }
01047         UNLOCK();
01048         if (!ok) 
01049             return SOCKET_ERROR;
01050         buf += blk;
01051         cnt -= blk;
01052     }
01053     return (len - cnt);
01054 }
01055 
01056 int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len)
01057 {
01058     TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len);
01059     int cnt = len;
01060     while (cnt > 0) {
01061         int blk = USO_MAX_WRITE;
01062         if (cnt < blk) 
01063             blk = cnt;
01064         bool ok = false;
01065         LOCK();
01066         if (ISSOCKET(socket)) {
01067             sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk);
01068             if (RESP_PROMPT == waitFinalResp()) {
01069                 wait_ms(50);
01070                 send(buf, blk);
01071                 if (RESP_OK == waitFinalResp())
01072                     ok = true;
01073             }
01074         }
01075         UNLOCK();
01076         if (!ok)
01077             return SOCKET_ERROR;
01078         buf += blk;
01079         cnt -= blk;
01080     }
01081     return (len - cnt);
01082 }
01083 
01084 int MDMParser::socketReadable(int socket)
01085 {
01086     int pending = SOCKET_ERROR;
01087     LOCK();
01088     if (ISSOCKET(socket) && _sockets[socket].connected) {
01089         TRACE("socketReadable(%d)\r\n", socket);
01090         // allow to receive unsolicited commands 
01091         waitFinalResp(NULL, NULL, 0);
01092         if (_sockets[socket].connected)
01093            pending = _sockets[socket].pending; 
01094     }
01095     UNLOCK();
01096     return pending;
01097 }
01098 
01099 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
01100 {
01101     if ((type == TYPE_PLUS) && out) {
01102         int sz, sk;
01103         if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && 
01104             (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01105             memcpy(out, &buf[len-1-sz], sz);
01106         }
01107     }
01108     return WAIT;
01109 }
01110 
01111 int MDMParser::socketRecv(int socket, char* buf, int len)
01112 {
01113     int cnt = 0;
01114     TRACE("socketRecv(%d,,%d)\r\n", socket, len);
01115 #ifdef MDM_DEBUG
01116     memset(buf, '\0', len);
01117 #endif
01118     Timer timer;
01119     timer.start();
01120     while (len) {
01121         int blk = MAX_SIZE; // still need space for headers and unsolicited  commands 
01122         if (len < blk) blk = len;
01123         bool ok = false;        
01124         LOCK();
01125         if (ISSOCKET(socket)) {
01126             if (_sockets[socket].connected) {
01127                 if (_sockets[socket].pending < blk)
01128                     blk = _sockets[socket].pending;
01129                 if (blk > 0) {
01130                     sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk);
01131                     if (RESP_OK == waitFinalResp(_cbUSORD, buf)) {
01132                         _sockets[socket].pending -= blk;
01133                         len -= blk;
01134                         cnt += blk;
01135                         buf += blk;
01136                         ok = true;
01137                     }
01138                 } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
01139                     ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
01140                 } else {
01141                     len = 0;
01142                     ok = true;
01143                 }
01144             } else {
01145                 len = 0;
01146                 ok = true;
01147             }
01148         }
01149         UNLOCK();
01150         if (!ok) {
01151             TRACE("socketRecv: ERROR\r\n");
01152             return SOCKET_ERROR;
01153         }
01154     }
01155     TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
01156     return cnt;
01157 }
01158 
01159 int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param)
01160 {
01161     if ((type == TYPE_PLUS) && param) {
01162         int sz, sk, p, a,b,c,d;
01163         int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 
01164             &sk,&a,&b,&c,&d,&p,&sz);
01165         if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01166             memcpy(param->buf, &buf[len-1-sz], sz);
01167             param->ip = IPADR(a,b,c,d);
01168             param->port = p;
01169         }
01170     }
01171     return WAIT;
01172 }
01173 
01174 int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len)
01175 {
01176     int cnt = 0;
01177     TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
01178 #ifdef MDM_DEBUG
01179     memset(buf, '\0', len);
01180 #endif
01181     Timer timer;
01182     timer.start();
01183     while (len) {
01184         int blk = MAX_SIZE; // still need space for headers and unsolicited commands 
01185         if (len < blk) blk = len;
01186         bool ok = false;        
01187         LOCK();
01188         if (ISSOCKET(socket)) {
01189             if (_sockets[socket].pending < blk)
01190                 blk = _sockets[socket].pending;
01191             if (blk > 0) {
01192                 sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk);
01193                 USORFparam param;
01194                 param.buf = buf;
01195                 if (RESP_OK == waitFinalResp(_cbUSORF, &param)) {
01196                     _sockets[socket].pending -= blk;
01197                     *ip = param.ip;
01198                     *port = param.port;
01199                     len -= blk;
01200                     cnt += blk;
01201                     buf += blk;
01202                     len = 0; // done 
01203                     ok = true;
01204                 }
01205             } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
01206                 ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
01207             } else {
01208                 len = 0; // no more data and socket closed or timed-out
01209                 ok = true;
01210             }
01211         }
01212         UNLOCK();
01213         if (!ok) {
01214             TRACE("socketRecv: ERROR\r\n");
01215             return SOCKET_ERROR;
01216         }
01217     }
01218     timer.stop();
01219     timer.reset();
01220     TRACE("socketRecv: %d \"%*s\"\r\n", cnt, cnt, buf-cnt);
01221     return cnt;
01222 }
01223 
01224 int MDMParser::_findSocket(int handle) {
01225     for (int socket = 0; socket < NUMSOCKETS; socket ++) {
01226         if (_sockets[socket].handle == handle)
01227             return socket;
01228     }
01229     return SOCKET_ERROR;
01230 }
01231 
01232 // ----------------------------------------------------------------
01233 
01234 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
01235 { 
01236     if ((type == TYPE_PLUS) && param && param->num) {
01237         // +CMGL: <ix>,...
01238         int ix;
01239         if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
01240         {
01241             *param->ix++ = ix;
01242             param->num--;
01243         }
01244     }
01245     return WAIT;
01246 }
01247 
01248 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
01249     int ret = -1;
01250     LOCK();
01251     sendFormated("AT+CMGL=\"%s\"\r\n", stat);
01252     CMGLparam param;
01253     param.ix = ix;
01254     param.num = num;
01255     if (RESP_OK == waitFinalResp(_cbCMGL, &param,60*1000))
01256         ret = num - param.num;
01257     UNLOCK();
01258     return ret;
01259 }
01260 
01261 bool MDMParser::smsSend(const char* num, const char* buf)
01262 {
01263     purge();
01264     bool ok = false;
01265     LOCK();
01266     sendFormated("AT+CMGS=\"%s\"\r\n",num);
01267     if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) {
01268         send(buf, strlen(buf));
01269         const char ctrlZ = 0x1A;
01270         send(&ctrlZ, sizeof(ctrlZ));
01271         ok = (RESP_OK == waitFinalResp());
01272     }
01273     UNLOCK();
01274     return ok;
01275 }
01276 
01277 bool MDMParser::smsDelete(int ix)
01278 {
01279     bool ok = false;
01280     LOCK();
01281     sendFormated("AT+CMGD=%d\r\n",ix);
01282     ok = (RESP_OK == waitFinalResp());
01283     UNLOCK();
01284     return ok;
01285 }
01286 
01287 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
01288 {
01289     if (param) {
01290         if (type == TYPE_PLUS) {
01291             if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) {
01292             }
01293         } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) {
01294             memcpy(param->buf, buf, len-2);
01295             param->buf[len-2] = '\0';
01296         }
01297     }
01298     return WAIT;
01299 }
01300 
01301 bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
01302 {
01303     bool ok = false;
01304     LOCK();
01305     CMGRparam param;
01306     param.num = num;
01307     param.buf = buf;
01308     sendFormated("AT+CMGR=%d\r\n",ix);
01309     ok = (RESP_OK == waitFinalResp(_cbCMGR, &param));
01310     UNLOCK();
01311     return ok;
01312 }
01313 
01314 //-----------------------------------------------------------------
01315 bool MDMParser::dialStart(const char* num)
01316 {
01317     bool ok = false;
01318     LOCK();
01319         //sendFormated("AT\r\n");
01320         //wait(0.5);
01321         sendFormated("ATD%s;\r\n",num);
01322         ok = (RESP_OK == waitFinalResp());
01323     UNLOCK();
01324     return ok;
01325 }
01326 
01327 bool MDMParser::dialStop()
01328 {
01329     bool ok = false;
01330     LOCK();
01331         sendFormated("ATH\r\n");
01332         ok = (RESP_OK == waitFinalResp());    
01333     UNLOCK();
01334     return ok;
01335 }
01336 
01337 bool MDMParser::dialAns()
01338 {
01339     bool ok = false;
01340     LOCK();
01341     sendFormated("ATA\r\n");
01342     ok = (RESP_OK == waitFinalResp());
01343     UNLOCK();
01344     return ok;
01345 }
01346 
01347 int MDMParser::_cbATA(int type, const char* buf, int len, ATAparam* param)
01348 {
01349    if (param) 
01350    {
01351         if (type == TYPE_PLUS) 
01352         {
01353             if (sscanf(buf, "\r\n+CLIP: %31[^\"]\",%d,,,,%*d", param->num, param->stat) == 2) {
01354                 ;
01355             }
01356         }
01357     }
01358     return WAIT;
01359 }
01360 
01361 bool MDMParser::dialStatus(const char* number)
01362 {
01363    bool ok = false;
01364    LOCK();
01365    ATAparam param;
01366    //ok = (RESP_OK == waitFinalResp(_cbATA, &param));
01367    waitFinalResp(_cbATA, &param);
01368    ok = (number == param.num);
01369    UNLOCK();
01370    return ok;
01371 }
01372 
01373 // ----------------------------------------------------------------
01374 int MDMParser::_cbDBG(int type, const char* buf, int len, DBGparam* param)
01375 {
01376    if(type == TYPE_PLUS)
01377    {
01378         int a, b;
01379         if(sscanf(buf, "\r\n+CLIP: \"%[^\"],%*d",param->num) == 1)
01380         {
01381             return RESP_OK;
01382         }
01383         else if(sscanf(buf, "\r\n+UCALLSTAT: %*d,%d",&a) == 1)
01384         {
01385                 /*
01386                     get call status format:
01387                     +UCALLSTAT: <id>,<status>
01388                     <id> : id call;
01389                     <status> :  0 = active (saat terhubung)
01390                                 1 = hold
01391                                 2 = dialling (melakukan panggilan namun blm terhubung)
01392                                 3 = alerting (melakukan panggilan dan dalam kedalam menunggu)
01393                                 4 = ringing (saat ada panggilan)
01394                                 5 = waiting
01395                                 6 = disconected (dialling dihentikan)
01396                                 7 = connected
01397                 */
01398             *param->status = a;
01399             return RESP_OK;
01400         }
01401         else if(sscanf(buf, "\r\n+CIEV: %d,%d", &a, &b) == 2)
01402         {
01403             if(a == 2)
01404             {
01405                 *param->signal = b;
01406                 return RESP_OK;
01407             }
01408             else return WAIT;
01409         }
01410         else if(sscanf(buf, "\r\n+CMTI: \"%*[^\"]\",%d", &a) == 1)
01411         {
01412             // a is indeks for sms
01413             if(a == 0)
01414                 return WAIT;
01415                 
01416             *param->indeks = a;
01417             return RESP_OK;
01418         }
01419         else return WAIT;
01420     }
01421     else return WAIT;
01422 }
01423 
01424 bool MDMParser::readDbg(int* status, char* num, int *signal, int* idx)
01425 {
01426    bool ok = 0;
01427    LOCK();
01428    DBGparam param;
01429    param.status = status;
01430    param.num = num;
01431    param.signal = signal;
01432    param.indeks = idx;
01433    ok = (RESP_OK == waitFinalResp(_cbDBG, &param, 1000));
01434    UNLOCK();
01435    return ok;
01436 }
01437 
01438 int MDMParser::signal()
01439 {
01440     int sig = 0;
01441     LOCK();
01442     NetStatus _status;
01443     sendFormated("AT+CSQ\r\n");
01444     if (RESP_OK != waitFinalResp(_cbCSQ, &_status))
01445         goto failure;
01446     
01447     // konversi dihilangkan untuk mempermudah kerja. kirim dalam satuan dbm
01448     
01449     if(_status.rssi <= -105)
01450         sig = 0;
01451     if((_status.rssi < -93) && (_status.rssi > -105))
01452         sig = 1;
01453     if((_status.rssi < -81) && (_status.rssi >= -93))
01454         sig = 2;
01455     if((_status.rssi < -69) && (_status.rssi >= -81))
01456         sig = 3;
01457     if((_status.rssi < -57) && (_status.rssi >= -69))
01458         sig = 4;
01459     if(_status.rssi >= -57)
01460         sig = 5;
01461     UNLOCK();
01462     failure:
01463     return sig;
01464 }
01465 
01466 bool MDMParser::mute(bool act)
01467 {
01468     if(act)
01469     {
01470         LOCK();
01471         //sendFormated("AT+CALM=1\r\n");
01472         sendFormated("AT+CRSL=2\r\n");
01473         UNLOCK();
01474         return true;
01475     }
01476     else
01477     {
01478         LOCK();
01479         //sendFormated("AT+CALM=0\r\n");
01480         sendFormated("AT+CRSL=5\r\n");
01481         UNLOCK();
01482         return false;
01483     }
01484 }
01485 
01486 bool MDMParser::sendAT()
01487 {
01488     bool ok = 0;
01489     purge();
01490     LOCK();
01491     sendFormated("AT\r\n");
01492     ok = (RESP_OK == waitFinalResp());
01493     UNLOCK();
01494     return ok;
01495 }
01496 //-----------------------------------------------------------------
01497 
01498 bool MDMParser::CopsCtzu()
01499 {
01500    bool ok = 0;
01501    LOCK();
01502    sendFormated("AT+COPS=2\r\n");
01503    ok = (RESP_OK == waitFinalResp());
01504    sendFormated("AT+CTZU=1\r\n");
01505    ok = (RESP_OK == waitFinalResp());
01506    sendFormated("AT+COPS=0\r\n");
01507    ok = (RESP_OK == waitFinalResp());
01508    UNLOCK();
01509    return ok;
01510 }
01511 
01512 int MDMParser::_cbCCLK(int type, const char* buf, int len, CCLKparam* param)
01513 {
01514     if(type == TYPE_PLUS)
01515     {
01516         if(sscanf(buf, "\r\n+CCLK: \"%[^\"]", param->buf) == 1)
01517         {
01518             return RESP_OK;
01519         }
01520         else return WAIT;
01521     }
01522     else return WAIT;
01523 }
01524 
01525 bool MDMParser::clk(char *buf)
01526 {
01527    bool ok = 0;
01528    LOCK();
01529    CCLKparam param;
01530    param.buf = buf;
01531    sendFormated("AT+CCLK?\r\n");
01532    ok = (RESP_OK == waitFinalResp(_cbCCLK, &param, 1000));
01533    UNLOCK();
01534    return ok;
01535 }
01536 
01537 // ----------------------------------------------------------------
01538   
01539 int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp)
01540 {
01541     if ((type == TYPE_PLUS) && resp) {
01542         // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..);
01543         if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) {
01544             /*nothing*/            
01545         }
01546     }
01547     return WAIT;
01548 }  
01549 
01550 bool MDMParser::ussdCommand(const char* cmd, char* buf)
01551 {
01552     bool ok = false;
01553     LOCK();
01554     *buf = '\0';
01555     if (_dev.dev != DEV_LISA_C200) {
01556         sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
01557         ok = (RESP_OK == waitFinalResp(_cbCUSD, buf));
01558     }
01559     UNLOCK();
01560     return ok;
01561 }
01562 
01563 // ----------------------------------------------------------------
01564    
01565 int MDMParser::_cbUDELFILE(int type, const char* buf, int len, void*)
01566 {
01567     if ((type == TYPE_ERROR) && strstr(buf, "+CME ERROR: FILE NOT FOUND")) 
01568         return RESP_OK; // file does not exist, so all ok...
01569     return WAIT;
01570 }  
01571 
01572 bool MDMParser::delFile(const char* filename)
01573 {
01574     bool ok = false;
01575     LOCK();
01576     sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
01577     ok = (RESP_OK == waitFinalResp(_cbUDELFILE));
01578     UNLOCK();
01579     return ok;
01580 }
01581 
01582 int MDMParser::writeFile(const char* filename, const char* buf, int len)
01583 {
01584     bool ok = false;
01585     LOCK();
01586     sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
01587     if (RESP_PROMPT == waitFinalResp()) {
01588         send(buf, len);
01589         ok = (RESP_OK == waitFinalResp());
01590     }
01591     UNLOCK();
01592     return ok ? len : -1;
01593 }
01594 
01595 int MDMParser::readFile(const char* filename, char* buf, int len)
01596 {
01597     URDFILEparam param;
01598     param.filename = filename;
01599     param.buf = buf; 
01600     param.sz = len; 
01601     param.len = 0;
01602     LOCK();
01603     sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
01604     if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
01605         param.len = -1;
01606     UNLOCK();
01607     return param.len;
01608 }
01609 
01610 int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param)
01611 {
01612     if ((type == TYPE_PLUS) && param && param->filename && param->buf) {
01613         char filename[48];
01614         int sz;
01615         if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) && 
01616             (0 == strcmp(param->filename, filename)) &&
01617             (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
01618             param->len = (sz < param->sz) ? sz : param->sz;
01619             memcpy(param->buf, &buf[len-1-sz], param->len);
01620         }
01621     }
01622     return WAIT;
01623 }
01624   
01625 // ----------------------------------------------------------------
01626 bool MDMParser::setDebug (int level) 
01627 {
01628 #ifdef MDM_DEBUG
01629     if ((_debugLevel >= -1) && (level >= -1) &&
01630         (_debugLevel <=  3) && (level <=  3)) {
01631         _debugLevel = level;
01632         return true;
01633     }
01634 #endif
01635     return false;
01636 }
01637 
01638 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 
01639             _DPRINT dprint, void* param) 
01640 {
01641     dprint(param, "Modem::devStatus\r\n");
01642     const char* txtDev[] = { "Unknown", "SARA-G350", "LISA-U200", "LISA-C200", "SARA-U260", "SARA-U270", "LEON-G200" };
01643     if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN))
01644         dprint(param, "  Device:       %s\r\n", txtDev[status->dev]);
01645     const char* txtLpm[] = { "Disabled", "Enabled", "Active" };
01646     if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm))
01647         dprint(param, "  Power Save:   %s\r\n", txtLpm[status->lpm]);
01648     const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" };
01649     if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN))
01650         dprint(param, "  SIM:          %s\r\n", txtSim[status->sim]);
01651     if (*status->ccid)  
01652         dprint(param, "  CCID:         %s\r\n", status->ccid);
01653     if (*status->imei) 
01654         dprint(param, "  IMEI:         %s\r\n", status->imei);
01655     if (*status->imsi)  
01656         dprint(param, "  IMSI:         %s\r\n", status->imsi);
01657     if (*status->meid) 
01658         dprint(param, "  MEID:         %s\r\n", status->meid); // LISA-C
01659     if (*status->manu) 
01660         dprint(param, "  Manufacturer: %s\r\n", status->manu);
01661     if (*status->model)  
01662         dprint(param, "  Model:        %s\r\n", status->model);
01663     if (*status->ver)  
01664         dprint(param, "  Version:      %s\r\n", status->ver);
01665 }
01666 
01667 void MDMParser::dumpNetStatus(MDMParser::NetStatus *status,
01668             _DPRINT dprint, void* param)
01669 {
01670     dprint(param, "Modem::netStatus\r\n");
01671     const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
01672     if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN))
01673         dprint(param, "  CSD Registration:   %s\r\n", txtReg[status->csd]);
01674     if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN))
01675         dprint(param, "  PSD Registration:   %s\r\n", txtReg[status->psd]);
01676     const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA" };
01677     if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN))
01678         dprint(param, "  Access Technology:  %s\r\n", txtAct[status->act]);
01679     if (status->rssi) 
01680         dprint(param, "  Signal Strength:    %d dBm\r\n", status->rssi);
01681     if (status->ber) 
01682         dprint(param, "  Bit Error Rate:     %d\r\n", status->ber);
01683     if (*status->opr)  
01684         dprint(param, "  Operator:           %s\r\n", status->opr);
01685     if (status->lac != 0xFFFF)  
01686         dprint(param, "  Location Area Code: %04X\r\n", status->lac);
01687     if (status->ci != 0xFFFFFFFF)  
01688         dprint(param, "  Cell ID:            %08X\r\n", status->ci);
01689     if (*status->num)  
01690         dprint(param, "  Phone Number:       %s\r\n", status->num);
01691 }
01692 
01693 void MDMParser::dumpIp(MDMParser::IP ip,
01694             _DPRINT dprint, void* param) 
01695 {
01696     if (ip != NOIP)
01697         dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip));
01698 }
01699     
01700 // ----------------------------------------------------------------
01701 int MDMParser::_parseMatch(Pipe<char> * pipe, int len, const char* sta, const char* end)
01702 {
01703     int o = 0;
01704     if (sta) {
01705         while (*sta) {
01706             if (++o > len)                  return WAIT;
01707             char ch = pipe->next();
01708             if (*sta++ != ch)               return NOT_FOUND;
01709         }
01710     }
01711     if (!end)                               return o; // no termination
01712     // at least any char
01713     if (++o > len)                      return WAIT;
01714     pipe->next();
01715     // check the end     
01716     int x = 0;
01717     while (end[x]) {
01718         if (++o > len)                      return WAIT;
01719         char ch = pipe->next();
01720         x = (end[x] == ch) ? x + 1 : 
01721             (end[0] == ch) ? 1 : 
01722                             0;
01723     }
01724     return o;
01725 }
01726 
01727 int MDMParser::_parseFormated(Pipe<char> * pipe, int len, const char* fmt)
01728 {
01729     int o = 0;
01730     int num = 0;
01731     if (fmt) {
01732         while (*fmt) {
01733             if (++o > len)                  return WAIT;
01734             char ch = pipe->next();
01735             if (*fmt == '%') {
01736                 fmt++;
01737                 if (*fmt == 'd') { // numeric
01738                     fmt ++;
01739                     num = 0;
01740                     while (ch >= '0' && ch <= '9') {
01741                         num = num * 10 + (ch - '0'); 
01742                         if (++o > len)      return WAIT;
01743                         ch = pipe->next();
01744                     }
01745                 }   
01746                 else if (*fmt == 'c') { // char buffer (takes last numeric as length)
01747                     fmt ++;
01748                     while (num --) {
01749                         if (++o > len)      return WAIT;
01750                         ch = pipe->next();
01751                     }   
01752                 }
01753                 else if (*fmt == 's') {
01754                     fmt ++;
01755                     if (ch != '\"')         return NOT_FOUND;
01756                     do {
01757                         if (++o > len)      return WAIT;
01758                         ch = pipe->next();
01759                     } while (ch != '\"');
01760                     if (++o > len)          return WAIT;
01761                     ch = pipe->next();
01762                 }
01763             }
01764             if (*fmt++ != ch)               return NOT_FOUND;
01765         }
01766     }
01767     return o; 
01768 }
01769 
01770 int MDMParser::_getLine(Pipe<char> * pipe, char* buf, int len)
01771 {
01772     int unkn = 0;
01773     int sz = pipe->size();
01774     int fr = pipe->free();
01775     if (len > sz)
01776         len = sz;
01777     while (len > 0)
01778     {
01779         static struct { 
01780               const char* fmt;                              int type; 
01781         } lutF[] = {
01782             { "\r\n+USORD: %d,%d,\"%c\"",                   TYPE_PLUS       },
01783             { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"",  TYPE_PLUS       },
01784             { "\r\n+URDFILE: %s,%d,\"%c\"",                 TYPE_PLUS       },
01785         };
01786         static struct { 
01787               const char* sta;          const char* end;    int type; 
01788         } lut[] = {
01789             { "\r\nOK\r\n",             NULL,               TYPE_OK         },
01790             { "\r\nERROR\r\n",          NULL,               TYPE_ERROR      },
01791             { "\r\n+CME ERROR:",        "\r\n",             TYPE_ERROR      }, 
01792             { "\r\n+CMS ERROR:",        "\r\n",             TYPE_ERROR      },
01793             { "\r\nRING\r\n",           NULL,               TYPE_RING       },
01794             { "\r\nCONNECT\r\n",        NULL,               TYPE_CONNECT    },
01795             { "\r\nNO CARRIER\r\n",     NULL,               TYPE_NOCARRIER  },
01796             { "\r\nNO DIALTONE\r\n",    NULL,               TYPE_NODIALTONE },
01797             { "\r\nBUSY\r\n",           NULL,               TYPE_BUSY       },
01798             { "\r\nNO ANSWER\r\n",      NULL,               TYPE_NOANSWER   },
01799             { "\r\n+",                  "\r\n",             TYPE_PLUS       },
01800             { "\r\n@",                  NULL,               TYPE_PROMPT     }, // Sockets
01801             { "\r\n>",                  NULL,               TYPE_PROMPT     }, // SMS
01802             { "\n>",                    NULL,               TYPE_PROMPT     }, // File
01803         };
01804         for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) {
01805             pipe->set(unkn);
01806             int ln = _parseFormated(pipe, len, lutF[i].fmt);
01807             if (ln == WAIT && fr)                       
01808                 return WAIT;
01809             if ((ln != NOT_FOUND) && (unkn > 0))  
01810                 return TYPE_UNKNOWN | pipe->get (buf, unkn);
01811             if (ln > 0)
01812                 return lutF[i].type  | pipe->get (buf, ln);
01813         }
01814         for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) {
01815             pipe->set(unkn);
01816             int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end);
01817             if (ln == WAIT && fr)                       
01818                 return WAIT;
01819             if ((ln != NOT_FOUND) && (unkn > 0))  
01820                 return TYPE_UNKNOWN | pipe->get (buf, unkn);
01821             if (ln > 0)
01822                 return lut[i].type | pipe->get (buf, ln);
01823         }
01824         // UNKNOWN
01825         unkn ++;
01826         len--;
01827     }
01828     return WAIT;
01829 }
01830 
01831 // ----------------------------------------------------------------
01832 // Serial Implementation 
01833 // ----------------------------------------------------------------
01834 
01835 /*! Helper Dev Null Device 
01836     Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout
01837     is shared with the serial port of the modem. Having printfs inbetween the 
01838     AT commands you cause a failure of the modem.
01839 */
01840 class DevNull : public Stream {
01841 public: 
01842     DevNull() : Stream(_name+1) { }             //!< Constructor
01843     void claim(const char* mode, FILE* file) 
01844         { freopen(_name, mode, file); }         //!< claim a stream
01845 protected:
01846     virtual int _getc()         { return EOF; } //!< Nothing
01847     virtual int _putc(int c)    { return c; }   //!< Discard
01848     static const char* _name;                   //!< File name
01849 };
01850 const char* DevNull::_name = "/null";  //!< the null device name
01851 static      DevNull null;              //!< the null device
01852 
01853 MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/, 
01854             int baudrate /*= MDMBAUD*/,
01855 #if DEVICE_SERIAL_FC
01856             PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/, 
01857 #endif
01858             int rxSize /*= 256*/, int txSize /*= 128*/) : 
01859             SerialPipe(tx, rx, rxSize, txSize) 
01860 {
01861     if (rx == USBRX) 
01862         null.claim("r", stdin);
01863     if (tx == USBTX) {
01864         null.claim("w", stdout);
01865         null.claim("w", stderr);
01866 #ifdef MDM_DEBUG
01867         _debugLevel = -1;
01868 #endif
01869     }
01870 #ifdef TARGET_UBLOX_C027
01871     _onboard = (tx == MDMTXD) && (rx == MDMRXD);
01872     if (_onboard)
01873        c027_mdm_powerOn(false);
01874 #endif
01875     baud(baudrate);
01876 #if DEVICE_SERIAL_FC
01877     if ((rts != NC) || (cts != NC))
01878     {
01879         Flow flow = (cts == NC) ? RTS :
01880                     (rts == NC) ? CTS : RTSCTS ;
01881         set_flow_control(flow, rts, cts);
01882         if (cts != NC) _dev.lpm = LPM_ENABLED;
01883     }
01884 #endif
01885 }
01886 
01887 MDMSerial::~MDMSerial(void)
01888 {
01889     /*powerOff();
01890 #ifdef TARGET_UBLOX_C027
01891     if (_onboard)
01892         c027_mdm_powerOff();
01893 #endif*/
01894 }
01895 
01896 int MDMSerial::_send(const void* buf, int len)   
01897 { 
01898     return put((const char*)buf, len, true/*=blocking*/);
01899 }
01900 
01901 int MDMSerial::getLine(char* buffer, int length)
01902 {
01903     return _getLine(&_pipeRx, buffer, length);
01904 }
01905 
01906 // ----------------------------------------------------------------
01907 // USB Implementation 
01908 // ----------------------------------------------------------------
01909 
01910 #ifdef HAVE_MDMUSB
01911 MDMUsb::MDMUsb(void)                             
01912 { 
01913 #ifdef MDM_DEBUG
01914     _debugLevel = 1;
01915 #endif    
01916 #ifdef TARGET_UBLOX_C027
01917     _onboard = true;
01918     c027_mdm_powerOn(true);
01919 #endif
01920 }
01921 
01922 MDMUsb::~MDMUsb(void)
01923 {
01924     /*powerOff();
01925 #ifdef TARGET_UBLOX_C027
01926     if (_onboard)
01927         c027_mdm_powerOff();
01928 #endif*/
01929 }
01930 
01931 int MDMUsb::_send(const void* buf, int len)      { return 0; }
01932 
01933 int MDMUsb::getLine(char* buffer, int length)    { return NOT_FOUND; }
01934 
01935 #endif