support library for C027 helper functions for Buffer Pipes, Buffered Serial Port (rtos capable) and GPS parsing. It includes modem APIs for USSD, SMS and Sockets.

Dependents:   HTTPClient_Cellular_HelloWorld Cellular_HelloMQTT MbedSmartRestMain Car_Bon_car_module ... more

This library is intended to be used with u-blox products such as the C027 or a shield with u-blox cellular and GPS modules like the cellular and positioning shield from Embedded Artist.

For 2G/GSM and 3G/UMTS you need to:

  • have a SIM card and know its PIN number
  • need to know you network operators APN setting These setting should be passed to the connect or init and join functions. You can also extend the APN database in MDMAPN.h.

For CDMA products you need to make sure that you have provisioned and activated the modem with either Sprint or Verizon.

Revision:
31:a0bed6c1e05d
Parent:
30:1a647403171b
Child:
32:8f12ac182bbb
--- a/MDM.cpp	Tue Apr 08 15:49:04 2014 +0000
+++ b/MDM.cpp	Wed Apr 09 11:48:04 2014 +0000
@@ -1,5 +1,6 @@
 #include "mbed.h"
 #include <ctype.h>
+#include <string.h>
 #include "MDM.h"
 
 #define TRACE           (0)?:printf
@@ -8,9 +9,6 @@
 #define MAX_SIZE        256  // max expected messages
 // some helper 
 #define ISSOCKET(s)     (((s) >= 0) && ((s) < (sizeof(_sockets)/sizeof(*_sockets))))
-#define IPSTR           "%d.%d.%d.%d"
-#define IPNUM(addr)     (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8)&0xff, addr&0xff
-#define IPADR(a,b,c,d)  ((a<<24) | (b<<16) | (c<<8) | d)
 
 #ifdef DEBUG
 void dump(const char* buf, int len)
@@ -23,36 +21,35 @@
         else                 printf("\\x%02x", ch);
     }
 }
-#endif        
+ #if 1 // colored terminal output using ANSI escape sequences
+  #define COL(c,t) "\33[" c t "\33[" "39m"
+ #else
+  #define COL(c,t) t
+ #endif
+ #define BLA(t) COL("30m",t)
+ #define RED(t) COL("31m",t)
+ #define GRE(t) COL("32m",t)
+ #define YEL(t) COL("33m",t)
+ #define BLU(t) COL("34m",t)
+ #define MAG(t) COL("35m",t)
+ #define CYA(t) COL("36m",t)
+ #define WHY(t) COL("37m",t)
+#endif
 
 MDMParser::MDMParser(void)
 {
-    // device info
-    _model   = MODEL_UNKNOWN;
-    _sim     = SIM_UNKNOWN;
-    *_ccid  = '\0';
-    *_imsi  = '\0';
-    *_imei  = '\0';
-    // network info
-    _net     = NET_UNKNOWN;
-    _act     = ACT_UNKNOWN;
-    _rssi    = 0;
-    *_num    = '\0';
-    *_opr    = '\0';
-    // data network info
-    _ip      = 0;
-    for (int socket = 0; socket < sizeof(_sockets)/sizeof(*_sockets); socket++) {
-        _sockets[socket].state = SOCK_FREE;
-        _sockets[socket].pending = 0;
-    }
+    memset(&_dev, 0, sizeof(_dev));
+    memset(&_net, 0, sizeof(_net));
+    _ip      = NOIP;
+    memset(_sockets, 0, sizeof(_sockets));
 }
 
 int MDMParser::send(const char* buf, int len)
 {
 #ifdef DEBUG
-    printf("   send \"");
+    printf("AT send    %4d \"", len);
     dump(buf,len);
-    printf("\"\n");
+    printf("\"\r\n");
 #endif
     return _send(buf, len);
 }
@@ -78,9 +75,17 @@
 #ifdef DEBUG
         if ((ret != WAIT) && (ret != NOT_FOUND))
         {
-            printf("   line %06X \"", ret);
-            dump(buf, LENGTH(ret));
-            printf("\"\n");
+            int len = LENGTH(ret);
+            int type = TYPE(ret);
+            const char* s = (type == TYPE_UNKNOWN)? YEL("UNK") : 
+                            (type == TYPE_OK   )  ? GRE("OK ") : 
+                            (type == TYPE_ERROR)  ? RED("ERR") : 
+                            (type == TYPE_PLUS)   ? CYA(" + ") : 
+                            (type == TYPE_PROMPT) ? BLU(" > ") : 
+                                                        "..."  ;
+            printf("AT read %s %3d \"", s, len);
+            dump(buf, len);
+            printf("\"\r\n");
         }
 #endif        
         if ((ret != WAIT) && (ret != NOT_FOUND))
@@ -92,46 +97,43 @@
             // handle unsolicited commands here
             if (type == TYPE_PLUS) {
                 const char* cmd = buf+3;
-                int a, b, c, d;
+                int a, b;
                 char s[32];
 
-                // +CSQ: <rssi>,<qual>
-                if (sscanf(cmd, "CSQ: %d,%d",&a,&b) == 2) {
-                    if (a != 99) _rssi = -113 + 2*a;  // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
-                    //if (b != 99) int qual = b;  // 
+                // SMS Command ---------------------------------
+                // +CNMI: <mem>,<index>
+                if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 
+                    TRACE("New SMS at index %d\r\n", a);
                 // Socket Specific Command ---------------------------------
                 // +UUSORD: <socket>,<length>
                 } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2) && 
                     ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) {
-                    TRACE("Socket %d: %d bytes pending\n", a, b);
+                    TRACE("Socket %d: %d bytes pending\r\n", a, b);
                     _sockets[a].pending = b;
                 // +UUSORF: <socket>,<length>
                 } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2) && 
                     ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) {
-                    TRACE("Socket %d: %d bytes pending\n", a, b);
+                    TRACE("Socket %d: %d bytes pending\r\n", a, b);
                     _sockets[a].pending = b;
                 // +UUSOCL: <socket>
                 } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1) && 
                     ISSOCKET(a) && (_sockets[a].state == SOCK_CONNECTED)) {
-                    TRACE("Socket %d: closed by remote host\n", a);
+                    TRACE("Socket %d: closed by remote host\r\n", a);
                     _sockets[a].state = SOCK_CREATED/*=CLOSED*/;
                 }                
-                if (_model == MODEL_LISA_C200) {
+                if (_dev.model == MODEL_LISA_C200) {
                     // CDMA Specific -------------------------------------------
                     // +CREG: <n><SID>,<NID>,<stat>
                     if (sscanf(cmd, "CREG: %*d,%*d,%*d,%d",&a) == 1) {
-                        if      (a == 0) _net = NET_NONE;     // not registered, home network
-                        else if (a == 1) _net = NET_HOME;     // registered, home network
-                        else if (a == 2) _net = NET_NONE;     // not registered, but MT is currently searching a new operator to register to
-                        else if (a == 3) _net = NET_DENIED;   // registration denied
-                        else if (a == 5) _net = NET_ROAMING;  // registered, roaming
-                        _act = ACT_CDMA;
+                        if      (a == 0) _net.reg = REG_NONE;     // not registered, home network
+                        else if (a == 1) _net.reg = REG_HOME;     // registered, home network
+                        else if (a == 2) _net.reg = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
+                        else if (a == 3) _net.reg = REG_DENIED;   // registration denied
+                        else if (a == 5) _net.reg = REG_ROAMING;  // registered, roaming
+                        _net.act = ACT_CDMA;
                     // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
                     } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
-                        //_net = (strcmp("Z", s) == 0) ? NET_UNKNOWN : NET_HOME;
-                    // +CMIP: xxx.xxx.xxx.xxx
-                    } else if (sscanf(cmd, "CMIP: " IPSTR, &a,&b,&c,&d) == 4) {
-                        _ip = IPADR(a,b,c,d);
+                        //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
                     }
                 } else {
                     // GSM/UMTS Specific -------------------------------------------
@@ -139,37 +141,23 @@
                     b = 255;
                     if (sscanf(cmd, "CREG: %*d,%d,%*d,%d",&a,&b) >= 1) {
                         // network status
-                        if      (a == 0) _net = NET_NONE;     // 0: not registered, home network
-                        else if (a == 1) _net = NET_HOME;     // 1: registered, home network
-                        else if (a == 2) _net = NET_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
-                        else if (a == 3) _net = NET_DENIED;   // 3: registration denied
-                        else if (a == 4) _net = NET_UNKNOWN;  // 4: unknown
-                        else if (a == 5) _net = NET_ROAMING;  // 5: registered, roaming
+                        if      (a == 0) _net.reg = REG_NONE;     // 0: not registered, home network
+                        else if (a == 1) _net.reg = REG_HOME;     // 1: registered, home network
+                        else if (a == 2) _net.reg = REG_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
+                        else if (a == 3) _net.reg = REG_DENIED;   // 3: registration denied
+                        else if (a == 4) _net.reg = REG_UNKNOWN;  // 4: unknown
+                        else if (a == 5) _net.reg = REG_ROAMING;  // 5: registered, roaming
                         // access technology
-                        if      (b == 0) _act = ACT_GSM;      // 0: GSM
-                        else if (b == 1) _act = ACT_GSM;      // 1: GSM COMPACT
-                        else if (b == 2) _act = ACT_UTRAN;    // 2: UTRAN
-                        else if (b == 3) _act = ACT_EDGE;     // 3: GSM with EDGE availability
-                        else if (b == 4) _act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
-                        else if (b == 5) _act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
-                        else if (b == 6) _act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
-                    // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
-                    } else if (sscanf(cmd, "COPS: %*d,%*d,\"%[^\"]\",%d",s,&b) >= 1) {
-                        strcpy(_opr,s);
-                        if      (a == 0) _act = ACT_GSM;      // 0: GSM, 
-                        else if (a == 2) _act = ACT_UTRAN;    // 2: UTRAN
-                    // +CPIN: <code>
-                    } else if (sscanf(cmd, "CPIN: %7s",s) == 1) {
-                        _sim = (strcmp("READY", s) == 0) ? SIM_READY : SIM_UNKNOWN;
-                    // +CNUM: <code>
-                    } else if (sscanf(cmd, "CNUM: \"My Number\",\"%31[^\"]\",%d", s, &a) == 2) {
-                        if ((a == 129) || (a == 145)) strncpy(_num, s, sizeof(_num));
-                    // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
-                    } else if (sscanf(cmd, "UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4) {
-                        _ip = IPADR(a,b,c,d);
+                        if      (b == 0) _net.act = ACT_GSM;      // 0: GSM
+                        else if (b == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
+                        else if (b == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
+                        else if (b == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
+                        else if (b == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
+                        else if (b == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
+                        else if (b == 6) _net.act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
                     // +UUPSDD: <profile_id> 
                     } else if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
-                        if (*PROFILE == a) _ip = 0;
+                        if (*PROFILE == a) _ip = NOIP;
                     }
                 }
             }
@@ -189,25 +177,26 @@
     return WAIT;
 }
 
-// ----------------------------------------------------------------
-
-int MDMParser::_cbATI(int type, const char* buf, int len, Model* model)
+int MDMParser::_cbString(int type, const char* buf, int len, char* str)
 {
-    if ((type == TYPE_UNKNOWN) && model) {
-        if (strstr(buf, "SARA-G350")) {
-            *model = MODEL_SARA_G350;
-            /*TRACE("Identified Model: SARA-G350 2G\n")*/;
-        } else if (strstr(buf, "LISA-U200")) {
-            *model = MODEL_LISA_U200;
-            /*TRACE("Identified Model: LISA-U200 2G/3G\n")*/;
-        } else if (strstr(buf, "LISA-C200")) {
-            *model= MODEL_LISA_C200;
-            /*TRACE("Identified Model: LISA-C200 CDMA\n")*/;
-        }
+    if (str && (type == TYPE_UNKNOWN)) {
+        if (sscanf(buf, "\r\n%s\r\n", str) == 1)
+            /*nothing*/;
     }
     return WAIT;
 }
 
+int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
+{
+    if (val && (type == TYPE_UNKNOWN)) {
+        if (sscanf(buf, "\r\n%d\r\n", val) == 1)
+            /*nothing*/;
+    }
+    return WAIT;
+}
+
+// ----------------------------------------------------------------
+
 bool MDMParser::init(const char* pin, DevStatus* status)
 {
     for(int i = 0; i < 5; i++) {
@@ -231,19 +220,19 @@
     wait_ms(40);
     // identify the module 
     sendFormated("ATI\r\n");
-    if (OK != waitFinalResp(_cbATI, &_model))
+    if (OK != waitFinalResp(_cbATI, &_dev.model))
         return false;
-    if (_model == MODEL_UNKNOWN)
+    if (_dev.model == MODEL_UNKNOWN)
         return false;
     // model specific init
-    if (_model == MODEL_LISA_C200) {
+    if (_dev.model == MODEL_LISA_C200) {
         // disable flow control
         sendFormated("AT+IFC=0,0\r\n");
         if (OK != waitFinalResp())
             return false;
         // Return the pseudo ESN or MEID
         sendFormated("AT+GSN\r\n");
-        if (OK != waitFinalResp(_cbGSN, _imei))
+        if (OK != waitFinalResp(_cbString, _dev.imei))
             return false;
     } else {
         // disable flow control
@@ -255,7 +244,7 @@
         if (OK != waitFinalResp())
             return false;
         // enable the network identification feature 
-        if (_model == MODEL_LISA_U200) {
+        if (_dev.model == MODEL_LISA_U200) {
             sendFormated("AT+UGPIOC=20,2\r\n");
             if (OK != waitFinalResp())
                 return false;
@@ -264,36 +253,34 @@
             if (OK != waitFinalResp())
                 return false;
         }
-        // Enter PIN if needed
-        if (pin) {
-            sendFormated("AT+CPIN=%s\r\n", pin);
-            if (OK != waitFinalResp())
-                return false;
-        }
         // check the sim card
-        for (int i = 0; i < 5; i++) {
+        for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
             sendFormated("AT+CPIN?\r\n");
-            int ret = waitFinalResp();
+            int ret = waitFinalResp(_cbCPIN, &_dev.sim);
             if ((OK != ret) && (ERROR != ret))
                 return false;
-            if (_sim != SIM_UNKNOWN)
-                break;
-            wait_ms(1000);
+            // Enter PIN if needed
+            if (_dev.sim == SIM_PIN) {
+                if (!pin) {
+                    TRACE("SIM PIN not available\r\n");
+                    return false;
+                }
+                sendFormated("AT+CPIN=%s\r\n", pin);
+                if (OK != waitFinalResp(_cbCPIN, &_dev.sim))
+                    return false;
+            } else if (_dev.sim != SIM_READY)
+                wait_ms(1000);
         }
-        if (_sim != SIM_READY)
+        if (_dev.sim != SIM_READY)
             return false;
         // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 
         // ICCID is a serial number identifying the SIM.
         sendFormated("AT+CCID\r\n");
-        if (OK != waitFinalResp(_cbCCID, _ccid))
+        if (OK != waitFinalResp(_cbCCID, _dev.ccid))
             return false;
         // Returns the product serial number, IMEI (International Mobile Equipment Identity)
         sendFormated("AT+CGSN\r\n");
-        if (OK != waitFinalResp(_cbCGSN, _imei))
-            return false;
-        // Setup SMS in text mode 
-        sendFormated("AT+CMGF=1\r\n");
-        if (OK != waitFinalResp())
+        if (OK != waitFinalResp(_cbString, _dev.imei))
             return false;
         // Configure New message indication
         //sendFormated("AT+CNMI=2,1,0,0,0\r\n");
@@ -301,53 +288,56 @@
         //    return false;
             
     } 
+    // Setup SMS in text mode 
+    sendFormated("AT+CMGF=1\r\n");
+    if (OK != waitFinalResp())
+        return false;
+    // setup new message indication
+    sendFormated("AT+CNMI=1,1\r\n");
+    if (OK != waitFinalResp())
+        return false;
     // Request IMSI (International Mobile Subscriber Identification)
     sendFormated("AT+CIMI\r\n");
-    if (OK != waitFinalResp(_cbCIMI, _imsi))
+    if (OK != waitFinalResp(_cbString, _dev.imsi))
         return false;
     if (status)
-    {
-        status->model = _model;
-        status->sim   = _sim;
-        status->ccid  = _ccid;
-        status->imsi  = _imsi;    
-        status->imei  = _imei;
+        memcpy(status, &_dev, sizeof(DevStatus));
+    return true; 
+}
+
+int MDMParser::_cbATI(int type, const char* buf, int len, Model* model)
+{
+    if ((type == TYPE_UNKNOWN) && model) {
+        if (strstr(buf, "SARA-G350")) {
+            *model = MODEL_SARA_G350;
+            /*TRACE("Identified Model: SARA-G350 2G\\n")*/;
+        } else if (strstr(buf, "LISA-U200")) {
+            *model = MODEL_LISA_U200;
+            /*TRACE("Identified Model: LISA-U200 2G/3G\r\n")*/;
+        } else if (strstr(buf, "LISA-C200")) {
+            *model= MODEL_LISA_C200;
+            /*TRACE("Identified Model: LISA-C200 CDMA\r\n")*/;
+        }
     }
-    return true; 
+    return WAIT;
+}
+
+int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
+{
+    if ((type == TYPE_PLUS) && sim){
+        char s[16];
+        if (sscanf(buf, "\r\n+CPIN: %[^\r]\r<n", s) >= 1) {
+            *sim = (strcmp("READY", s) == 0) ? SIM_READY : SIM_PIN;
+        }
+    }
+    return WAIT;
 }
 
 int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
 {
     if ((type == TYPE_PLUS) && ccid){
         if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
-            /*TRACE("Got CCID: %s\n", ccid)*/;
-    }
-    return WAIT;
-}
-
-int MDMParser::_cbGSN(int type, const char* buf, int len, char* imei)
-{
-    if ((type == TYPE_UNKNOWN) && imei){
-        if (sscanf(buf, "\r\n%[^\r]\r\n%*[^\r]\r\n", imei) == 1)
-            /*TRACE("Got IMEI: %s\n", imei)*/;
-    }
-    return WAIT;
-}
-
-int MDMParser::_cbCGSN(int type, const char* buf, int len, char* imei)
-{
-    if ((type == TYPE_UNKNOWN) && imei){
-        if (sscanf(buf, "\r\n%[^\r]\r\n", imei) == 1)
-            /*TRACE("Got IMEI: %s\n", imei)*/;
-    }
-    return WAIT;
-}
-
-int MDMParser::_cbCIMI(int type, const char* buf, int len, char* imsi)
-{
-    if ((type == TYPE_UNKNOWN) && imsi) {
-        if (sscanf(buf, "\r\n%[^\r]\r\n", imsi) == 1)
-            /*TRACE("Got IMSI: %s\n", imsi)*/;
+            /*TRACE("Got CCID: %s\r\n", ccid)*/;
     }
     return WAIT;
 }
@@ -358,39 +348,85 @@
     sendFormated("AT+CREG?\r\n");
     if (OK != waitFinalResp())
         return false;
-    if ((_net != NET_ROAMING) && (_net != NET_HOME))
+    if ((_net.reg != REG_ROAMING) && (_net.reg != REG_HOME))
         return false;
     // check modem specific status messages 
-    if (_model == MODEL_LISA_C200) {
+    if (_dev.model == MODEL_LISA_C200) {
         sendFormated("AT+CSS?\r\n");
         if (OK != waitFinalResp())
             return false;
-        if ((_net != NET_ROAMING) && (_net != NET_HOME))
+    } else {
+        // check GPRS attach status
+        int state = 0;
+        sendFormated("AT+CGATT?\r\n");
+        if (OK != waitFinalResp(_cbCGATT, &state))
             return false;
-    } else {
+        if (state != 1)
+            return false;
         // check operator selection 
         sendFormated("AT+COPS?\r\n");
-        if (OK != waitFinalResp())
+        if (OK != waitFinalResp(_cbCOPS, &_net))
             return false;
         // Returns the MSISDNs related to this subscriber
         sendFormated("AT+CNUM\r\n");
-        if (OK != waitFinalResp())
+        if (OK != waitFinalResp(_cbCNUM, _net.num))
             return false;
     }  
     // Returns the signal strength indication
     sendFormated("AT+CSQ\r\n");
-    if (OK != waitFinalResp())
+    if (OK != waitFinalResp(_cbCSQ, &_net.rssi))
         return false;
     if (status) {
-        status->num = _num;
-        status->opr = _opr;
-        status->rssi = _rssi;
-        status->net = _net;
-        status->act = _act;
+        memcpy(status, &_net, sizeof(NetStatus));
     }
     return true;
 }
 
+int MDMParser::_cbCGATT(int type, const char* buf, int len, int* state)
+{
+    if ((type == TYPE_PLUS) && state){
+        if (sscanf(buf, "\r\n+CGATT: %d\r\n", state) == 1)
+            /*TRACE("Got CGATT: %d\r\n", state)*/;
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
+{
+    if ((type == TYPE_PLUS) && status){
+        int act = 99;
+        // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
+        if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) {
+            if      (act == 0) status->act = ACT_GSM;      // 0: GSM, 
+            else if (act == 2) status->act = ACT_UTRAN;    // 2: UTRAN
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
+{
+    if ((type == TYPE_PLUS) && num){
+        int a;
+        if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 
+            ((a == 129) || (a == 145))) {
+        }
+    }
+    return WAIT;
+}
+                    
+int MDMParser::_cbCSQ(int type, const char* buf, int len, int* rssi)
+{
+    if ((type == TYPE_PLUS) && rssi){
+        int a;
+        // +CSQ: <rssi>,<qual>
+        if (sscanf(buf, "\r\n+CSQ: %d,%*d",&a) == 1) {
+            if (a != 99) *rssi = -113 + 2*a;  // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
+            //if (b != 99) int qual = b;  // 
+        }
+    }
+    return WAIT;
+}
 bool MDMParser::powerOff(void)
 {
     sendFormated("AT+CPWROFF\r\n");
@@ -402,80 +438,106 @@
 // ----------------------------------------------------------------
 // internet connection 
 
-MDMParser::IP MDMParser::strToIp(const char* str)
+MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* user /*= NULL*/, const char* password /*= NULL*/)
 {
-    IP ip = 0;
-    char* p = (char*)str;
-    for(int i = 0; i < 4; i++) {
-        ip |= atoi(p);
-        p = strchr(p, '.');
-        if (p == NULL) {
-            break;
-        }
-        ip <<= 8;
-        p++;
-    }
-    return ip;
-}
-
-bool MDMParser::join(const char* apn /*= NULL*/, const char* user /*= NULL*/, const char* password /*= NULL*/)
-{
-    if (_model == MODEL_LISA_C200) {
+    IP ip = NOIP;
+    if (_dev.model == MODEL_LISA_C200) {
 #ifdef TODO // TODO implement 
         // enable the 
         sendFormated("AT$QCMIPEP=1\r\n");
         if (OK != waitFinalResp())
-            return false;
+            return NOIP;
         //Get local IP address
         sendFormated("AT+CMIP?\r\n");
+        // extract: +CMIP: xxx.xxx.xxx.xxx
         if (OK != waitFinalResp())
-            return false;
+            return NOIP;
+        
 #endif
     } else { 
         // check gprs attach status 
         sendFormated("AT+CGATT?\r\n");
         if (OK != waitFinalResp())
-            return false;
-         // Set up the APN
+            return NOIP;
+        
+        // Check the profile
+        int a = 0;
+        sendFormated("AT+UPSND=" PROFILE ",8\r\n");
+        if (OK != waitFinalResp(_cbUPSND, &a))
+            return NOIP;
+        if (a == 1) {
+            // disconnect the profile already if it is connected 
+            sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
+            if (OK != waitFinalResp())
+                return NOIP;;
+        }
+        // Set up the APN
         if (apn) {
             sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
             if (OK != waitFinalResp())
-                return false;
+                return NOIP;
         }
         if (user) {    
             sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", user);
             if (OK != waitFinalResp())
-                return false;
+                return NOIP;
         }
         if (password) {
             sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
             if (OK != waitFinalResp())
-                return false;
+                return NOIP;
         }
         // Set up the dynamic IP address assignment.
         sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
         if (OK != waitFinalResp())
-            return false;
+            return NOIP;
         // Activate the profile and make connection
         sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
         if (OK != waitFinalResp())
-            return false;
+            return NOIP;
         //Get local IP address
         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
-        if (OK != waitFinalResp())
-            return false;
+        if (OK != waitFinalResp(_cbUPSND, &ip))
+            return NOIP;
+    }
+    return ip;
+}
+
+int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
+{
+    if ((type == TYPE_PLUS) && act) {
+        if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
+            /*nothing*/;
     }
-    if (!_ip)
-        return false;
-    TRACE("Got IP address: " IPSTR "\n",  IPNUM(_ip));
-    return true;
+    return WAIT;
+}
+
+int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
+{
+    if ((type == TYPE_PLUS) && ip) {
+        int a,b,c,d;
+        // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
+        if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
+            *ip = IPADR(a,b,c,d);
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
+{
+    if ((type == TYPE_PLUS) && ip) {
+        int a,b,c,d;
+        if (sscanf(buf, "\r\n+UDNSRN: \""IPSTR"\"", &a,&b,&c,&d) == 4)
+            *ip = IPADR(a,b,c,d);
+    }
+    return WAIT;
 }
 
 bool MDMParser::disconnect(void)
 {
-    if (_ip == 0)
+    if (_ip == NOIP)
         return true;
-    if (_model == MODEL_LISA_C200) {
+    if (_dev.model == MODEL_LISA_C200) {
 #ifdef TODO // TODO implement 
         sendFormated("AT$QCMIPEP=0\r\n");
 #endif
@@ -484,35 +546,22 @@
     }
     if (OK != waitFinalResp())
         return false;
-    _ip = 0;
+    _ip = NOIP;
     return true;
 }
 
-int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
-{
-    if ((type == TYPE_PLUS) && ip) {
-        buf += 3;
-        int a,b,c,d;
-        if (sscanf(buf, "UDNSRN: \""IPSTR"\"", &a,&b,&c,&d) == 4)
-            *ip = IPADR(a,b,c,d);
-    }
-    return WAIT;
-}
-
-bool MDMParser::gethostbyname(const char* host, IP* ip)
+MDMParser::IP MDMParser::gethostbyname(const char* host)
 {
-    char ipstr[16];
-    IP addr = strToIp(host);
-    *ip = 0;
-    snprintf(ipstr, sizeof(ipstr), IPSTR, IPNUM(addr));
-    if (strcmp(ipstr, host) == 0) {
-        *ip = addr;
-        return true;
+    IP ip = NOIP; 
+    int a,b,c,d;
+    if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
+        ip = IPADR(a,b,c,d);
+    else {
+        sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
+        if (OK != waitFinalResp(_cbUDNSRN, &ip))
+            return false;
     }
-    sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
-    if (OK != waitFinalResp(_cbUDNSRN, ip))
-        return false;
-    return *ip != 0;
+    return ip;
 }
 
 // ----------------------------------------------------------------
@@ -552,8 +601,8 @@
 
 bool MDMParser::socketConnect(int socket, const char * host, int port)
 {
-    IP ip;
-    if (!gethostbyname(host, &ip))
+    IP ip = gethostbyname(host);
+    if (ip == NOIP)
         return false;
     // connect to socket
     if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED))
@@ -715,24 +764,29 @@
 }
 
 // ----------------------------------------------------------------
-int MDMParser::_cbCPMS(int type, const char* buf, int len, int* num)
+
+int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
 { 
-    if ((type == TYPE_PLUS) && num) {
-        // AT+CPMS: <used1>,<total1>,<used2>,<total2>,<used3>,<total3>;
-        if (sscanf(buf, "\r\n+CPMS: %d,%*d", num) == 1)
-            /*nothing*/;
+    if ((type == TYPE_PLUS) && param && param->num) {
+        // +CMGL: <ix>,...
+        int ix;
+        if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
+        {
+            *param->ix++ = ix;
+            param->num--;
+        }
     }
     return WAIT;
 }
 
-int MDMParser::smsCount(void)
-{
-    int num = 0;
-    sendFormated("AT+CPMS=\"ME\"\r\n");
-    if (OK != waitFinalResp(_cbCPMS,&num)) {
-        return 0;
-    }
-    return num;
+int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
+    sendFormated("AT+CMGL=\"%s\"\r\n", stat);
+    CMGLparam param;
+    param.ix = ix;
+    param.num = num;
+    if (OK != waitFinalResp(_cbCMGL, &param))
+        return -1;
+    return num - param.num;
 }
 
 bool MDMParser::smsSend(const char* num, const char* buf)
@@ -797,14 +851,15 @@
     }
     return WAIT;
 }  
-int MDMParser::ussdCommand(const char* cmd, char* buf, int len)
+
+bool MDMParser::ussdCommand(const char* cmd, char* buf)
 {
     *buf = '\0';
     sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
     if (OK != waitFinalResp(_cbCUSD, buf)) {
-        return -1;
+        return false;
     }
-    return strlen(buf);
+    return true;
 }
        
 // ----------------------------------------------------------------
@@ -884,7 +939,7 @@
         } lut[] = {
             { "\r\nOK\r\n",             NULL,               TYPE_OK         },
             { "\r\nERROR\r\n",          NULL,               TYPE_ERROR      },
-            { "\r\n+CME ERROR:",        "\r\n",             TYPE_ERROR      },
+            { "\r\n+CME ERROR:",        "\r\n",             TYPE_ERROR      }, 
             { "\r\n+CMS ERROR:",        "\r\n",             TYPE_ERROR      },
             { "\r\nRING\r\n",           NULL,               TYPE_RING       },
             { "\r\nCONNECT\r\n",        NULL,               TYPE_CONNECT    },
@@ -902,7 +957,7 @@
             if (ln == WAIT && fr)                       
                 return WAIT;
             if ((ln != NOT_FOUND) && (unkn > 0))  
-                return pipe->get(buf, unkn);
+                return TYPE_UNKNOWN | pipe->get(buf, unkn);
             if (ln > 0)
                 return lutF[i].type  | pipe->get(buf, ln);
         }
@@ -912,7 +967,7 @@
             if (ln == WAIT && fr)                       
                 return WAIT;
             if ((ln != NOT_FOUND) && (unkn > 0))  
-                return pipe->get(buf, unkn);
+                return TYPE_UNKNOWN | pipe->get(buf, unkn);
             if (ln > 0)
                 return lut[i].type | pipe->get(buf, ln);
         }