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:
79:291df065e345
Parent:
78:caf0014375cb
Child:
80:34985b4d821e
--- a/MDM.cpp	Tue May 20 11:40:07 2014 +0000
+++ b/MDM.cpp	Mon May 26 11:55:16 2014 +0000
@@ -12,6 +12,9 @@
 //! check for timeout
 #define TIMEOUT(t, ms)  ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 
 
+#define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
+#define REG_DONE(r)     ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 
+
 #ifdef MDM_DEBUG
 void dumpAtCmd(const char* buf, int len)
 {
@@ -162,11 +165,12 @@
                     if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
                         // _net.sid = a;
                         // _net.nid = b;
-                        if      (c == 0) _net.reg = REG_NONE;     // not registered, home network
-                        else if (c == 1) _net.reg = REG_HOME;     // registered, home network
-                        else if (c == 2) _net.reg = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
-                        else if (c == 3) _net.reg = REG_DENIED;   // registration denied
-                        else if (c == 5) _net.reg = REG_ROAMING;  // registered, roaming
+                        if      (c == 0) _net.csd = REG_NONE;     // not registered, home network
+                        else if (c == 1) _net.csd = REG_HOME;     // registered, home network
+                        else if (c == 2) _net.csd = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
+                        else if (c == 3) _net.csd = REG_DENIED;   // registration denied
+                        else if (c == 5) _net.csd = REG_ROAMING;  // registered, roaming
+                        _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
                         _net.act = ACT_CDMA;
                     // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
                     } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
@@ -174,35 +178,41 @@
                     }
                 } else {
                     // GSM/UMTS Specific -------------------------------------------
-                    // +CREG: <n>,<stat>[,<lac>,<ci>[,AcT]] // reply to AT+CREG
-                    // +CREG: <stat>[,<lac>,<ci>[,AcT]] // URC
-                    b = 255;
-                    r = sscanf(cmd, "CREG: %*d,%d,\"%X\",\"%X\",%d",&a,&b,&c,&d);
-                    if (r <= 0)
-                        r = sscanf(cmd, "CREG: %d,\"%X\",\"%X\",%d",&a,&b,&c,&d);
-                    if (r >= 1) {
-                        // network status
-                        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
-                        if ((r >= 2) && (b != 0xFFFF))      _net.lac = b; // location area code
-                        if ((r >= 3) && (c != 0xFFFFFFFF))  _net.ci  = c; // cell ID
-                        // access technology
-                        if (r >= 4) {
-                            if      (d == 0) _net.act = ACT_GSM;      // 0: GSM
-                            else if (d == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
-                            else if (d == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
-                            else if (d == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
-                            else if (d == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
-                            else if (d == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
-                            else if (d == 6) _net.act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
+                    // +UUPSDD: <profile_id> 
+                    if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
+                        if (*PROFILE == a) _ip = NOIP;
+                    } else {
+                        // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
+                        // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]]     // URC
+                        b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
+                        r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
+                        if (r <= 1)
+                            r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
+                        if (r >= 2) {
+                            Reg *reg = !strcmp(s, "CREG:")  ? &_net.csd : 
+                                       !strcmp(s, "CGREG:") ? &_net.psd : NULL;
+                            if (reg) {
+                                // network status
+                                if      (a == 0) *reg = REG_NONE;     // 0: not registered, home network
+                                else if (a == 1) *reg = REG_HOME;     // 1: registered, home network
+                                else if (a == 2) *reg = REG_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
+                                else if (a == 3) *reg = REG_DENIED;   // 3: registration denied
+                                else if (a == 4) *reg = REG_UNKNOWN;  // 4: unknown
+                                else if (a == 5) *reg = REG_ROAMING;  // 5: registered, roaming
+                                if ((r >= 3) && (b != 0xFFFF))      _net.lac = b; // location area code
+                                if ((r >= 4) && (c != 0xFFFFFFFF))  _net.ci  = c; // cell ID
+                                // access technology
+                                if (r >= 5) {
+                                    if      (d == 0) _net.act = ACT_GSM;      // 0: GSM
+                                    else if (d == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
+                                    else if (d == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
+                                    else if (d == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
+                                    else if (d == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
+                                    else if (d == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
+                                    else if (d == 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 = NOIP;
                     }
                 }
             }
@@ -277,10 +287,17 @@
         INFO("Modem::wakeup\r\n");
         DigitalOut pin(pn, 1);
         while (i--) {
-            pin = 0;
-            RELAX_MS(5); // SARA-G/U
-            pin = 1;
-            RELAX_MS(100);
+            // SARA-U2/LISA-U2 50..80us
+            pin = 0; wait_us(50);
+            pin = 1; wait_ms(10); 
+            
+            // SARA-G35 >5ms, LISA-C2 > 150ms
+            pin = 0; wait_ms(150);
+            pin = 1; wait_ms(100);
+            
+            // purge any messages 
+            while (WAIT != waitFinalResp(NULL,NULL,0))
+                /* nothing */;
             // check interface and disable local echo
             sendFormated("AT\r\n");
             if(RESP_OK == waitFinalResp(NULL,NULL,500))
@@ -407,7 +424,15 @@
                 return false;  
             _dev.lpm = LPM_ACTIVE;
         }
+        // enable the psd registration unsolicited result code
+        sendFormated("AT+CGREG=2\r\n");
+        if (RESP_OK != waitFinalResp())
+            return false;
     } 
+    // enable the network registration unsolicited result code
+    sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
+    if (RESP_OK != waitFinalResp())
+        return false;
     // Setup SMS in text mode 
     sendFormated("AT+CMGF=1\r\n");
     if (RESP_OK != waitFinalResp())
@@ -420,10 +445,6 @@
     sendFormated("AT+CIMI\r\n");
     if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
         return false;
-    // enable the network registration unsolicited result code
-    sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
-    if (RESP_OK != waitFinalResp())
-        return false;
     if (status)
         memcpy(status, &_dev, sizeof(DevStatus));
     return true; 
@@ -489,9 +510,9 @@
     INFO("Modem::register\r\n");
     while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
         RELAX_MS(1000);
-    if (_net.reg == REG_DENIED)
-        ERROR("Network Registration Denied\r\n");
-    return (_net.reg == REG_ROAMING) || (_net.reg == REG_HOME);
+    if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
+    if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
+    return REG_OK(_net.csd) || REG_OK(_net.psd);
 }
 
 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
@@ -503,7 +524,13 @@
     sendFormated("AT+CREG?\r\n");
     if (RESP_OK != waitFinalResp())
         return false;
-    if ((_net.reg == REG_ROAMING) || (_net.reg == REG_HOME))
+    if (_dev.dev != DEV_LISA_C200) {
+        // check PSD registration
+        sendFormated("AT+CGREG?\r\n");
+        if (RESP_OK != waitFinalResp())
+            return false;
+    }
+    if (REG_OK(_net.csd) || REG_OK(_net.psd))
     {
         // check modem specific status messages 
         if (_dev.dev == DEV_LISA_C200) {
@@ -515,7 +542,7 @@
             if (RESP_OK != waitFinalResp(_cbString, _net.num))
                 return false;
             // check if we have a Mobile Directory Number
-            if (!*_net.num || (memcmp(_net.num, "0000", 4) == 0))
+            if (!*_net.num || (memcmp(_net.num, "000000", 6) == 0))
                 return false;
             // get the the Network access identifier string
             char nai[64];
@@ -523,10 +550,6 @@
             if (RESP_OK != waitFinalResp(_cbString, nai))
                 return false;
         } else {
-            // check GPRS attach status
-            sendFormated("AT+CGATT?\r\n");
-            if (RESP_OK != waitFinalResp(_cbCGATT, &_net.gprs))
-                return false;
             // check operator selection 
             sendFormated("AT+COPS?\r\n");
             if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
@@ -544,19 +567,7 @@
     if (status) {
         memcpy(status, &_net, sizeof(NetStatus));
     }
-    return ((_net.reg == REG_HOME) || (_net.reg == REG_ROAMING) || (_net.reg == REG_DENIED));
-}
-
-int MDMParser::_cbCGATT(int type, const char* buf, int len, Gprs* gprs)
-{
-    if ((type == TYPE_PLUS) && gprs){
-        int i;
-        if (sscanf(buf, "\r\n+CGATT: %d\r\n", &i) == 1) {
-            if      (i == 0) *gprs = GPRS_DETACHED;
-            else if (i == 1) *gprs = GPRS_ATTACHED;
-        }
-    }
-    return WAIT;
+    return REG_DONE(_net.csd) && REG_DONE(_net.psd);
 }
 
 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
@@ -600,7 +611,8 @@
 // ----------------------------------------------------------------
 // internet connection 
 
-MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, const char* password /*= NULL*/)
+MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 
+                              const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
 {
     INFO("Modem::join\r\n");
     _ip = NOIP;
@@ -623,40 +635,61 @@
         
         // Check the profile
         int a = 0;
+        bool force = true;
         sendFormated("AT+UPSND=" PROFILE ",8\r\n");
         if (RESP_OK != waitFinalResp(_cbUPSND, &a))
             return NOIP;
-        if (a == 1) {
+        if (a == 1 && force) {
             // disconnect the profile already if it is connected 
             sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
             if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
                 return NOIP;;
+            a = 0;
         }
-        // Set up the APN
-        if (apn) {
-            sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
-            if (RESP_OK != waitFinalResp())
-                return NOIP;
-        }
-        if (username) {    
-            sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
+        if (a == 0) {
+            // Set up the APN
+            if (apn) {
+                sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
+                if (RESP_OK != waitFinalResp())
+                    return NOIP;
+            }
+            if (username) {    
+                sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
+                if (RESP_OK != waitFinalResp())
+                    return NOIP;
+            }
+            if (password) {
+                sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
+                if (RESP_OK != waitFinalResp())
+                    return NOIP;
+            }
+            // Set up the dynamic IP address assignment.
+            sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
             if (RESP_OK != waitFinalResp())
                 return NOIP;
-        }
-        if (password) {
-            sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
-            if (RESP_OK != waitFinalResp())
+            // try different Authentication Protocols
+            // 0 = none 
+            // 1 = PAP (Password Authentication Protocol)
+            // 2 = CHAP (Challenge Handshake Authentication Protocol)
+            int i = AUTH_NONE;
+            while (i <= AUTH_CHAP)
+            {
+                if ((auth == AUTH_DETECT) || (auth == i)) {
+                    // Set up the dynamic IP address assignment.
+                    sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
+                    if (RESP_OK != waitFinalResp())
+                        return NOIP;
+                    // Activate the profile and make connection
+                    sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
+                    if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
+                        break;
+                }
+                i ++;
+            }
+            if (i > AUTH_CHAP) {
+                ERROR("Your modem APN/password/username may be wrong\r\n");
                 return NOIP;
-        }
-        // Set up the dynamic IP address assignment.
-        sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
-        if (RESP_OK != waitFinalResp())
-            return NOIP;
-        // Activate the profile and make connection
-        sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
-        if (RESP_OK != waitFinalResp(NULL,NULL,150*1000)) {
-            ERROR("Your modem APN/password/username may be wrong\r\n");
-            return NOIP;
+            }
         }
         //Get local IP address
         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
@@ -1128,11 +1161,10 @@
 {
     dprint(param, "Modem::netStatus\r\n");
     const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
-    if (status->reg < sizeof(txtReg)/sizeof(*txtReg) && (status->reg != MDMParser::REG_UNKNOWN))
-        dprint(param, "  Registration:       %s\r\n", txtReg[status->reg]);
-    const char* txtGprs[] = { "Unknown", "Detached", "Attached" };
-    if (status->gprs < sizeof(txtGprs)/sizeof(*txtGprs) && (status->gprs != MDMParser::GPRS_UNKNOWN))
-        dprint(param, "  Gprs:               %s\r\n", txtGprs[status->gprs]);
+    if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != MDMParser::REG_UNKNOWN))
+        dprint(param, "  CSD Registration:   %s\r\n", txtReg[status->csd]);
+    if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != MDMParser::REG_UNKNOWN))
+        dprint(param, "  PSD Registration:   %s\r\n", txtReg[status->psd]);
     const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA" };
     if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != MDMParser::ACT_UNKNOWN))
         dprint(param, "  Access Technology:  %s\r\n", txtAct[status->act]);