Rob Meades / C027_Support_N

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