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:
74:208e3e32d263
Parent:
73:2b32e0a21df2
Child:
75:ce6e12067d0c
--- a/MDM.cpp	Thu May 15 08:25:45 2014 +0000
+++ b/MDM.cpp	Thu May 15 22:20:42 2014 +0000
@@ -2,30 +2,34 @@
 #include <ctype.h>
 #include <string.h>
 #include "MDM.h"
+#include "Relax.h"
+#ifdef TARGET_UBLOX_C027
+ #include "C027_api.h"
+#endif
 
-#define TRACE           (1/*1=off,0=trace*/)?:printf
-//#define DEBUG         // enable this for AT command debugging
-#define PROFILE         "0"   // this is the psd profile used
-// some helper 
+#define PROFILE         "0"   //!< this is the psd profile used
+#define MAX_SIZE        128   //!< max expected messages
+//! test if it is a socket
 #define ISSOCKET(s)     (((s) >= 0) && ((s) < (sizeof(_sockets)/sizeof(*_sockets))))
-#define WAIT_MS(ms)     wait_ms(ms) // you may choose to use Thread::wait(ms)
 
-#define MAX_SIZE        128   // max expected messages
 
-#ifdef DEBUG
-void dump(const char* buf, int len)
+#ifdef MDM_DEBUG
+void dumpAtCmd(const char* buf, int len)
 {
+    printf(" %3d \"", len);
     while (len --) {
         char ch = *buf++;
-        if      (ch == '\r') printf("\\r");
-        else if (ch == '\n') printf("\\n");
-        else if (ch >= 0x20) printf("%c", ch);
+        if      (ch == '\r') puts("\\r");
+        else if (ch == '\n') puts("\\n");
+        else if (ch >= 0x20) putchar(ch);
         else                 printf("\\x%02x", ch);
     }
+    puts("\"\r\n");
 }
-
-Timer dbgTime; 
-
+ 
+ #define INFO  (_debugLevel >= 1) ? : printf
+ #define TRACE (_debugLevel >= 2) ? : printf
+ 
  #if 1 // colored terminal output using ANSI escape sequences
   #define COL(c,t) "\33[" c t "\33[" "39m"
  #else
@@ -39,6 +43,12 @@
  #define MAG(t) COL("35m",t)
  #define CYA(t) COL("36m",t)
  #define WHY(t) COL("37m",t)
+ 
+#else
+ 
+ #define INFO(...)  (void)0 // no tracing
+ #define TRACE(...) (void)0 // no tracing
+
 #endif
 
 MDMParser* MDMParser::inst;
@@ -52,18 +62,27 @@
     _net.ci = 0xFFFFFFFF;
     _ip        = NOIP;
     memset(_sockets, 0, sizeof(_sockets));
-#ifdef DEBUG
-    dbgTime.start();    
+#ifdef MDM_DEBUG
+    _debugTime.start();
+#endif
+}
+
+MDMParser::~MDMParser(void)
+{
+    powerOff();
+#ifdef TARGET_UBLOX_C027
+    if (_onboard)
+        c027_mdm_powerOff();
 #endif
 }
 
 int MDMParser::send(const char* buf, int len)
 {
-#ifdef DEBUG
-    printf("%10.3f ", dbgTime.read_ms()*0.001);
-    printf("AT send    %4d \"", len);
-    dump(buf,len);
-    printf("\"\r\n");
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 3) {
+        printf("%10.3f AT send    ", _debugTime.read_ms()*0.001);
+        dumpAtCmd(buf,len);
+    }
 #endif
     return _send(buf, len);
 }
@@ -86,8 +105,8 @@
     timer.start();
     do {
         int ret = getLine(buf, sizeof(buf));
-#ifdef DEBUG
-        if ((ret != WAIT) && (ret != NOT_FOUND))
+#ifdef MDM_DEBUG
+        if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
         {
             int len = LENGTH(ret);
             int type = TYPE(ret);
@@ -98,10 +117,8 @@
                             (type == TYPE_PLUS)   ? CYA(" + ") : 
                             (type == TYPE_PROMPT) ? BLU(" > ") : 
                                                         "..."  ;
-            printf("%10.3f ", dbgTime.read_ms()*0.001);
-            printf("AT read %s %3d \"", s, len);
-            dump(buf, len);
-            printf("\"\r\n");
+            printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
+            dumpAtCmd(buf, len);
         }
 #endif        
         if ((ret != WAIT) && (ret != NOT_FOUND))
@@ -193,7 +210,7 @@
             }
         }
         // relax a bit
-        WAIT_MS(10); 
+        RELAX_MS(10); 
     }
     while ((timeout_ms == TIMEOUT_BLOCKING) || 
            (timer.read_ms() < timeout_ms));
@@ -225,46 +242,60 @@
 bool MDMParser::connect(
             const char* simpin, 
             const char* apn, const char* username, const char* password,
-            bool dump)
+            PinName pn)
 {
     DevStatus devStatus = {};
-    WAIT_MS(2000);
-    bool mdmOk = init(simpin, &devStatus);
-    if (dump) dumpDevStatus(&devStatus);
+    bool mdmOk = init(simpin, &devStatus, pn);  
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpDevStatus(&devStatus);
+#endif
     if (!mdmOk)
         return false;
     // wait until we are connected
-    int i = 60;
+    int i = 180;
     NetStatus netStatus = {};
+    INFO("Modem::register\r\n");
     while (!checkNetStatus(&netStatus))
     {
         if ((netStatus.reg == REG_DENIED) || (i == 0))
             break;;
         i --;
-        WAIT_MS(1000);
+        RELAX_MS(1000);
     }
-    if (dump) dumpNetStatus(&netStatus);
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpNetStatus(&netStatus);
+#endif
     if ((netStatus.reg == REG_DENIED) || (i == 0))
         return false;
     IP ip = join(apn,username,password);
-    if (dump) dumpIp(ip);
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpIp(ip);
+#endif
     if (ip == NOIP)
         return false; 
     return true;
 }
 
-bool MDMParser::init(const char* simpin, DevStatus* status)
+bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
 {
-    int i = 5;
-    // we should wait some time before 
-    while (i--) {
-        // check interface and disable local echo
-        sendFormated("AT\r\n");
-        if(RESP_OK == waitFinalResp(NULL,NULL,1000))
-            break;
+    int i = 10;
+    if (pn != NC) {
+        INFO("Modem::wakeup\r\n");
+        DigitalOut pin(pn, 1);
+        while (i--) {
+            pin = 0;
+            RELAX_MS(5); // SARA-G/U
+            pin = 1;
+            RELAX_MS(100);
+            // check interface and disable local echo
+            sendFormated("AT\r\n");
+            if(RESP_OK == waitFinalResp(NULL,NULL,500))
+                break;
+        }
+        if (i < 0)
+            return false;
     }
-    if (i < 0)
-        return false;
+    INFO("Modem::init\r\n");
     // echo off
     sendFormated("AT E0\r\n");
     if(RESP_OK != waitFinalResp())
@@ -277,7 +308,7 @@
     sendFormated("AT+IPR=115200\r\n");
     if (RESP_OK != waitFinalResp())
         return false;
-    WAIT_MS(40);
+    RELAX_MS(40);
     // identify the module 
     sendFormated("ATI\r\n");
     if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
@@ -334,14 +365,14 @@
             // Enter PIN if needed
             if (_dev.sim == SIM_PIN) {
                 if (!simpin) {
-                    TRACE("SIM PIN not available\r\n");
+                    INFO("SIM PIN not available\r\n");
                     return false;
                 }
                 sendFormated("AT+CPIN=%s\r\n", simpin);
                 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
                     return false;
             } else if (_dev.sim != SIM_READY) {
-                WAIT_MS(1000);
+                RELAX_MS(1000);
             }
         }
         if (_dev.sim != SIM_READY)
@@ -403,6 +434,15 @@
     return true; 
 }
 
+bool MDMParser::powerOff(void)
+{
+    INFO("Modem::powerOff\r\n");
+    sendFormated("AT+CPWROFF\r\n");
+    if (RESP_OK != waitFinalResp(NULL,NULL,120*1000))
+        return false;
+    return true;
+}
+
 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
 {
     if ((type == TYPE_UNKNOWN) && dev) {
@@ -538,19 +578,13 @@
     }
     return WAIT;
 }
-bool MDMParser::powerOff(void)
-{
-    sendFormated("AT+CPWROFF\r\n");
-    if (RESP_OK != waitFinalResp(NULL,NULL,120))
-        return false;
-    return true;
-}
 
 // ----------------------------------------------------------------
 // internet connection 
 
 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, const char* password /*= NULL*/)
 {
+    TRACE("Modem::join\r\n");
     _ip = NOIP;
     if (_dev.dev == DEV_LISA_C200) {
         // TODO: is there something to do here?
@@ -565,7 +599,7 @@
     } else { 
         // check gprs attach status 
         sendFormated("AT+CGATT=1\r\n");
-        if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000))
+        if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 
             return NOIP;
         
         // Check the profile
@@ -601,8 +635,10 @@
             return NOIP;
         // Activate the profile and make connection
         sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
-        if (RESP_OK != waitFinalResp(NULL,NULL,150*1000))
+        if (RESP_OK != waitFinalResp(NULL,NULL,150*1000)) {
+            INFO("Your modem APN/password/username may be wrong\r\n");
             return NOIP;
+        }
         //Get local IP address
         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
         if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
@@ -655,6 +691,7 @@
 {
     if (_ip == NOIP)
         return true;
+    INFO("Modem::disconnect\r\n");
     if (_dev.dev == DEV_LISA_C200) {
         // TODO: is there something to do here?
     } else { 
@@ -738,7 +775,6 @@
     TRACE("socketIsConnected(%d)\r\n", socket);
     if (!ISSOCKET(socket))
         return false;
-    TRACE(" ... %d\r\n", _sockets[socket].state);
     return _sockets[socket].state == SOCK_CONNECTED;
 }
 
@@ -786,7 +822,7 @@
         sendFormated("AT+USOWR=%d,%d\r\n",socket,blk);
         if (RESP_PROMPT != waitFinalResp())
             return SOCKET_ERROR;
-        WAIT_MS(50);
+        RELAX_MS(50);
         send(buf, blk);
         if (RESP_OK != waitFinalResp()) 
             return SOCKET_ERROR;
@@ -807,7 +843,7 @@
        sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",socket,IPNUM(ip),port,blk);
         if (RESP_PROMPT != waitFinalResp())
             return SOCKET_ERROR;
-        WAIT_MS(50);
+        RELAX_MS(50);
         send(buf, blk);
         if (RESP_OK != waitFinalResp())
             return SOCKET_ERROR;
@@ -1034,7 +1070,17 @@
 }
    
 // ----------------------------------------------------------------
- 
+bool MDMParser::setDebug(int level) 
+{
+#ifdef MDM_DEBUG
+    if ((_debugLevel >= 0) && (level >= 0)) {
+        _debugLevel = level;
+        return true;
+    }
+#endif
+    return false;
+}
+
 void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 
             _DPRINT dprint, void* param) 
 {
@@ -1158,7 +1204,6 @@
     return o; 
 }
 
-
 int MDMParser::_getLine(Pipe<char>* pipe, char* buf, int len)
 {
     int unkn = 0;
@@ -1230,6 +1275,14 @@
             int rxSize /*= 256*/, int txSize /*= 128*/) : 
             SerialPipe(tx, rx, rxSize, txSize) 
 {
+#ifdef MDM_DEBUG
+    _debugLevel = (tx == USBTX) ? -1 : 1;
+#endif    
+#ifdef TARGET_UBLOX_C027
+    _onboard = (tx == MDMTXD) && (rx == MDMRXD);
+    if (_onboard)
+       c027_mdm_powerOn(false);
+#endif
     baud(baudrate);
 #if DEVICE_SERIAL_FC
     if ((rts != NC) || (cts != NC))
@@ -1257,8 +1310,16 @@
 // ----------------------------------------------------------------
 
 #ifdef HAVE_MDMUSB
-// TODO properly implement with USB 
-MDMUsb::MDMUsb(void)                             { }
+MDMUsb(void)                             
+{ 
+#ifdef MDM_DEBUG
+    _debugLevel = 1;
+#endif    
+#ifdef TARGET_UBLOX_C027
+    _onboard = true;
+    c027_mdm_powerOn(true);
+#endif
+}
 int MDMUsb::_send(const void* buf, int len)      { return len; }
 int MDMUsb::getLine(char* buffer, int length)    { return NOT_FOUND; }
 #endif