Iftikhar Aziz / C027_Support

Fork of C027_Support by Umar Naeem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MDM.cpp Source File

MDM.cpp

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