C027_SupportTest_xively_locationで使用しているC027用ライブラリ

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