C027_Support library plus AT Comand for dialing.

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