Own fork of C027_Support

Dependents:   MbedSmartRestMain MbedSmartRestMain

Fork of C027_Support by u-blox

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