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:
95:8282dbbe1492
Parent:
90:3915192f6d7e
Child:
98:c786461edd40
diff -r d697fe11f3e5 -r 8282dbbe1492 MDM.cpp
--- a/MDM.cpp	Thu Jun 12 12:41:26 2014 +0000
+++ b/MDM.cpp	Tue Jun 17 07:03:48 2014 +0000
@@ -1,6 +1,5 @@
 #include "mbed.h"
 #include "MDM.h"
-#include "Relax.h"
 #ifdef TARGET_UBLOX_C027
  #include "C027_api.h"
 #endif
@@ -16,8 +15,27 @@
 #define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
 //! registration done check helper (no need to poll further)
 #define REG_DONE(r)     ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 
+//! helper to make sure that lock unlock pair is always balaced 
+#define LOCK()         { lock() 
+//! helper to make sure that lock unlock pair is always balaced 
+#define UNLOCK()       } unlock()
 
 #ifdef MDM_DEBUG
+ #if 1 // colored terminal output using ANSI escape sequences
+  #define COL(c) "\033[" c
+ #else
+  #define COL(c) 
+ #endif
+ #define DEF COL("39m")
+ #define BLA COL("30m")
+ #define RED COL("31m")
+ #define GRE COL("32m")
+ #define YEL COL("33m")
+ #define BLU COL("34m")
+ #define MAG COL("35m")
+ #define CYA COL("36m")
+ #define WHY COL("37m")
+ 
 void dumpAtCmd(const char* buf, int len)
 {
     ::printf(" %3d \"", len);
@@ -42,27 +60,15 @@
     ::printf("\"\r\n");
 }
  
- #define ERROR(fmt) (_debugLevel < 0) ? : ::printf(RED(fmt))
- #define INFO(fmt)  (_debugLevel < 1) ? : ::printf(GRE(fmt))
- #define TRACE(...) (_debugLevel < 2) ? : ::printf(__VA_ARGS__)
- 
- #if 1 // colored terminal output using ANSI escape sequences
-  #define COL(c,t) "\033[" c t "\033[" "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)
+ #define ERROR(...)     (_debugLevel < 0) ? : ::printf(RED), ::printf(__VA_ARGS__), ::printf(DEF) 
+ #define TEST(...)                            ::printf(CYA), ::printf(__VA_ARGS__), ::printf(DEF)  
+ #define INFO(...)      (_debugLevel < 1) ? : ::printf(GRE), ::printf(__VA_ARGS__), ::printf(DEF) 
+ #define TRACE(...)     (_debugLevel < 2) ? : ::printf(__VA_ARGS__)
  
 #else
  
  #define ERROR(...) (void)0 // no tracing
+ #define TEST(...)  (void)0 // no tracing
  #define INFO(...)  (void)0 // no tracing
  #define TRACE(...) (void)0 // no tracing
 
@@ -120,13 +126,13 @@
         {
             int len = LENGTH(ret);
             int type = TYPE(ret);
-            const char* s = (type == TYPE_UNKNOWN)? YEL("UNK") : 
-                            (type == TYPE_TEXT)   ? MAG("TXT") : 
-                            (type == TYPE_OK   )  ? GRE("OK ") : 
-                            (type == TYPE_ERROR)  ? RED("ERR") : 
-                            (type == TYPE_PLUS)   ? CYA(" + ") : 
-                            (type == TYPE_PROMPT) ? BLU(" > ") : 
-                                                        "..."  ;
+            const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 
+                            (type == TYPE_TEXT)   ? MAG "TXT" DEF : 
+                            (type == TYPE_OK   )  ? GRE "OK " DEF : 
+                            (type == TYPE_ERROR)  ? RED "ERR" DEF : 
+                            (type == TYPE_PLUS)   ? CYA " + " DEF : 
+                            (type == TYPE_PROMPT) ? BLU " > " DEF : 
+                                                        "..." ;
             ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
             dumpAtCmd(buf, len);
         }
@@ -224,12 +230,15 @@
                 if (WAIT != ret)
                     return ret; 
             }
-            if (type == TYPE_OK)        return RESP_OK;
-            if (type == TYPE_ERROR)     return RESP_ERROR;
-            if (type == TYPE_PROMPT)    return RESP_PROMPT;
+            if (type == TYPE_OK)
+                return RESP_OK;
+            if (type == TYPE_ERROR)
+                return RESP_ERROR;
+            if (type == TYPE_PROMPT)    
+                return RESP_PROMPT;
         }
         // relax a bit
-        RELAX_MS(10); 
+        wait_ms(10); 
     }
     while (!TIMEOUT(timer, timeout_ms));
     return WAIT;
@@ -285,30 +294,32 @@
 bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
 {
     int i = 10;
+    LOCK();
     memset(&_dev, 0, sizeof(_dev));
     if (pn != NC) {
         INFO("Modem::wakeup\r\n");
         DigitalOut pin(pn, 1);
         while (i--) {
             // SARA-U2/LISA-U2 50..80us
-            pin = 0; wait_us(50);
-            pin = 1; wait_ms(10); 
+            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);
+            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))
-                break;
+            int r = waitFinalResp(NULL,NULL,500);
+            if(RESP_OK == r) break;
         }
         if (i < 0) {
-            ERROR("No Reply from Modem");
-            return false;
+            ERROR("No Reply from Modem\r\n");
+            goto failure;
         }
     }
     _init = true;
@@ -317,47 +328,47 @@
     // echo off
     sendFormated("AT E0\r\n");
     if(RESP_OK != waitFinalResp())
-        return false;
+        goto failure; 
     // enable verbose error messages
     sendFormated("AT+CMEE=2\r\n");
     if(RESP_OK != waitFinalResp())
-        return false;
+        goto failure;
     // set baud rate
     sendFormated("AT+IPR=115200\r\n");
     if (RESP_OK != waitFinalResp())
-        return false;
-    RELAX_MS(40);
+        goto failure;
+    wait_ms(40);
     // identify the module 
     sendFormated("ATI\r\n");
     if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
-        return false;
+        goto failure;
     if (_dev.dev == DEV_UNKNOWN)
-        return false;
+        goto failure;
     // device specific init
     if (_dev.dev == DEV_LISA_C200) {
         // get the manufacturer
         sendFormated("AT+GMI\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
-            return false;
+            goto failure;
         // get the model identification
         sendFormated("AT+GMM\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
-            return false;
+            goto failure;
         // get the sw version
         sendFormated("AT+GMR\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
-            return false;
-        // Return the pseudo ESN or MEID
+            goto failure;
+        // get the pseudo ESN or MEID
         sendFormated("AT+GSN\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
-            return false;
+            goto failure;
 #if 0
         // enable power saving
         if (_dev.lpm != LPM_DISABLED) {
              // enable power saving (requires flow control, cts at least)
             sendFormated("AT+UPSV=1,1280\r\n");
             if (RESP_OK != waitFinalResp())
-                return false;  
+                goto failure;  
             _dev.lpm = LPM_ACTIVE;
         }
 #endif
@@ -366,12 +377,12 @@
             // enable the network identification feature 
             sendFormated("AT+UGPIOC=20,2\r\n");
             if (RESP_OK != waitFinalResp())
-                return false;
+                goto failure;
         } else {
             // enable the network identification feature 
             sendFormated("AT+UGPIOC=16,2\r\n");
             if (RESP_OK != waitFinalResp())
-                return false;
+                goto failure;
         }
         // check the sim card
         for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
@@ -379,90 +390,98 @@
             int ret = waitFinalResp(_cbCPIN, &_dev.sim);
             // having an error here is ok (sim may still be initializing)
             if ((RESP_OK != ret) && (RESP_ERROR != ret))
-                return false;
+                goto failure;
             // Enter PIN if needed
             if (_dev.sim == SIM_PIN) {
                 if (!simpin) {
                     ERROR("SIM PIN not available\r\n");
-                    return false;
+                    goto failure;
                 }
                 sendFormated("AT+CPIN=%s\r\n", simpin);
                 if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
-                    return false;
+                    goto failure;
             } else if (_dev.sim != SIM_READY) {
-                RELAX_MS(1000);
+                wait_ms(1000);
             }
         }
         if (_dev.sim != SIM_READY) {
             if (_dev.sim == SIM_MISSING)
                 ERROR("SIM not inserted\r\n");
-            return false;
+            goto failure;
         }
         // get the manufacturer
         sendFormated("AT+CGMI\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
-            return false;
+            goto failure;
         // get the model identification
         sendFormated("AT+CGMM\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.model))
-            return false;
+            goto failure;
         // get the 
         sendFormated("AT+CGMR\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
-            return false;            
+            goto failure;            
         // 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 (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
-            return false;
+            goto failure;
         // Returns the product serial number, IMEI (International Mobile Equipment Identity)
         sendFormated("AT+CGSN\r\n");
         if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
-            return false;
+            goto failure;
         // enable power saving
         if (_dev.lpm != LPM_DISABLED) {
              // enable power saving (requires flow control, cts at least)
             sendFormated("AT+UPSV=1\r\n");
             if (RESP_OK != waitFinalResp())
-                return false;  
+                goto failure;  
             _dev.lpm = LPM_ACTIVE;
         }
         // enable the psd registration unsolicited result code
         sendFormated("AT+CGREG=2\r\n");
         if (RESP_OK != waitFinalResp())
-            return false;
+            goto failure;
     } 
     // 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;
+        goto failure;
     // Setup SMS in text mode 
     sendFormated("AT+CMGF=1\r\n");
     if (RESP_OK != waitFinalResp())
-        return false;
+        goto failure;
     // setup new message indication
     sendFormated("AT+CNMI=2,1\r\n");
     if (RESP_OK != waitFinalResp())
-        return false;
+        goto failure;
     // Request IMSI (International Mobile Subscriber Identification)
     sendFormated("AT+CIMI\r\n");
     if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
-        return false;
+        goto failure;
     if (status)
         memcpy(status, &_dev, sizeof(DevStatus));
+    UNLOCK();
     return true; 
+failure:
+    unlock();
+    return false; 
 }
 
 bool MDMParser::powerOff(void)
 {
+    bool ok = false;
     if (_init) {
+        LOCK();
         INFO("Modem::powerOff\r\n");
         sendFormated("AT+CPWROFF\r\n");
-        if (RESP_OK != waitFinalResp(NULL,NULL,120*1000))
-            return false;
-        _init = false;
+        if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) {
+            _init = false;
+            ok = true;
+        }
+        UNLOCK();
     }
-    return true;
+    return ok;
 }
 
 int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
@@ -512,7 +531,7 @@
     timer.start();
     INFO("Modem::register\r\n");
     while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
-        RELAX_MS(1000);
+        wait_ms(1000);
     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);
@@ -520,6 +539,8 @@
 
 bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
 {
+    bool ok = false;
+    LOCK();
     memset(&_net, 0, sizeof(_net));
     _net.lac = 0xFFFF;
     _net.ci = 0xFFFFFFFF;
@@ -537,12 +558,12 @@
         if (_dev.dev == DEV_LISA_C200) {
             sendFormated("AT+CSS?\r\n");
             if (RESP_OK != waitFinalResp())
-                return false;
+                goto failure;
             while (1) {
                 // get the Telephone number
                 sendFormated("AT$MDN?\r\n");
                 if (RESP_OK != waitFinalResp(_cbString, _net.num))
-                    return false;
+                    goto failure;
                 // check if we have a Mobile Directory Number
                 if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
                     break;
@@ -559,7 +580,7 @@
                     i = 1;
                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
                         ERROR("Device over-the-air activation failed\r\n");
-                        return false;
+                        goto failure;
                     }
                     INFO("Device over-the-air activation successful\r\n");
                     
@@ -568,39 +589,44 @@
                     i = 1;
                     if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
                         ERROR("PRL over-the-air update failed\r\n");
-                        return false;
+                        goto failure;
                     }
                     INFO("PRL over-the-air update successful\r\n");
                     
                 } else { 
                     // Sprint or Aeris 
                     INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
-                    RELAX_MS(120*1000);
+                    wait_ms(120*1000);
                 }
             }
             // get the the Network access identifier string
             char nai[64];
             sendFormated("AT$QCMIPNAI?\r\n");
             if (RESP_OK != waitFinalResp(_cbString, nai))
-                return false;
+                goto failure;
         } else {
             sendFormated("AT+COPS?\r\n");
             if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
-                return false;
-            // Returns the MSISDNs related to this subscriber
+                goto failure;
+            // get the MSISDNs related to this subscriber
             sendFormated("AT+CNUM\r\n");
             if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
-                return false;
+                goto failure;
         }  
-        // Returns the signal strength indication
+        // get the signal strength indication
         sendFormated("AT+CSQ\r\n");
         if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
-            return false;
+            goto failure;
     }
     if (status) {
         memcpy(status, &_net, sizeof(NetStatus));
     }
-    return REG_DONE(_net.csd) && REG_DONE(_net.psd);
+    ok = REG_DONE(_net.csd) && REG_DONE(_net.psd);
+    UNLOCK();
+    return ok;
+failure:
+    unlock();
+    return false;
 }
 
 int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
@@ -658,6 +684,7 @@
 MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 
                               const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
 {
+    LOCK();
     INFO("Modem::join\r\n");
     _ip = NOIP;
     if (_dev.dev == DEV_LISA_C200) {
@@ -670,24 +697,24 @@
         //Get local IP address
         sendFormated("AT+CMIP?\r\n");
         if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
-            return NOIP;
+            goto failure;
     } else { 
         // check gprs attach status 
         sendFormated("AT+CGATT=1\r\n");
         if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 
-            return NOIP;
+            goto failure;
         
         // Check the profile
         int a = 0;
         bool force = true;
         sendFormated("AT+UPSND=" PROFILE ",8\r\n");
         if (RESP_OK != waitFinalResp(_cbUPSND, &a))
-            return NOIP;
+            goto failure;
         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;
+                goto failure;
             a = 0;
         }
         if (a == 0) {
@@ -700,7 +727,7 @@
             // Set up the dynamic IP address assignment.
             sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
             if (RESP_OK != waitFinalResp())
-                return NOIP;
+                goto failure;
  
             do {
                 if (config) {
@@ -713,17 +740,17 @@
                 if (apn && *apn) {
                     sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
                     if (RESP_OK != waitFinalResp())
-                        return NOIP;
+                        goto failure;
                 }
                 if (username && *username) {
                     sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
                     if (RESP_OK != waitFinalResp())
-                        return NOIP;
+                        goto failure;
                 }
                 if (password && *password) {
                     sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
                     if (RESP_OK != waitFinalResp())
-                        return NOIP;
+                        goto failure;
                 }
                 // try different Authentication Protocols
                 // 0 = none 
@@ -734,7 +761,7 @@
                         // Set up the Authentication Protocol
                         sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
                         if (RESP_OK != waitFinalResp())
-                            return NOIP;
+                            goto failure;
                         // Activate the profile and make connection
                         sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
                         if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
@@ -744,15 +771,19 @@
             } while (config && *config); // maybe use next setting ? 
             if (!ok) {
                 ERROR("Your modem APN/password/username may be wrong\r\n");
-                return NOIP;
+                goto failure;
             }
         }
         //Get local IP address
         sendFormated("AT+UPSND=" PROFILE ",0\r\n");
         if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
-            return NOIP;
+            goto failure;
     }
+    UNLOCK();
     return _ip;
+failure: 
+    unlock();
+    return NOIP;
 }
 
 int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc)
@@ -798,7 +829,7 @@
 {
     if ((type == TYPE_PLUS) && ip) {
         int a,b,c,d;
-        if (sscanf(buf, "\r\n+UDNSRN: \""IPSTR"\"", &a,&b,&c,&d) == 4)
+        if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4)
             *ip = IPADR(a,b,c,d);
     }
     return WAIT;
@@ -806,18 +837,24 @@
 
 bool MDMParser::disconnect(void)
 {
-    if (_ip == NOIP)
-        return true;
+    bool ok = false;
+    LOCK();
     INFO("Modem::disconnect\r\n");
-    if (_dev.dev == DEV_LISA_C200) {
-        // There something to do here
-    } else { 
-        sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
-        if (RESP_OK != waitFinalResp())
-            return false;
+    if (_ip != NOIP) {
+        if (_dev.dev == DEV_LISA_C200) {
+            // There something to do here
+            _ip = NOIP;
+            ok = true;
+        } else { 
+            sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
+            if (RESP_OK != waitFinalResp()) {
+                _ip = NOIP;
+                ok = true;
+            }
+        }
     }
-    _ip = NOIP;
-    return true;
+    UNLOCK();
+    return ok;
 }
 
 MDMParser::IP MDMParser::gethostbyname(const char* host)
@@ -827,9 +864,11 @@
     if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
         ip = IPADR(a,b,c,d);
     else {
+        LOCK();
         sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
         if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
-            return false;
+            ip = NOIP;
+        UNLOCK();
     }
     return ip;
 }
@@ -849,81 +888,101 @@
 
 int MDMParser::socketSocket(IpProtocol ipproto, int port)
 {
+    int socket = SOCKET_ERROR;
+    LOCK();
     TRACE("socketSocket(%d)\r\n", ipproto);
-    if(ipproto == IPPROTO_TCP) {
-        sendFormated("AT+USOCR=6\r\n");
-    } else if ((ipproto == IPPROTO_UDP) && (port == -1)){
+    if ((ipproto == IPPROTO_UDP) && (port == -1)){
         sendFormated("AT+USOCR=17\r\n");
     } else if (ipproto == IPPROTO_UDP){
         sendFormated("AT+USOCR=17,%d\r\n", port);
-    } else { // other types not supported
-        return SOCKET_ERROR;
-    }
-    int socket = -1;
+    } else /*(ipproto == IPPROTO_TCP)*/ {
+        sendFormated("AT+USOCR=6\r\n");
+    } 
     if (RESP_OK != waitFinalResp(_cbUSOCR, &socket))
-        return SOCKET_ERROR;
-    if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_FREE))
-        return SOCKET_ERROR;
-    // successfull
-    _sockets[socket].state = SOCK_CREATED;
-    _sockets[socket].pending = 0;
-    _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
+        socket = SOCKET_ERROR;
+    else if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_FREE))
+        socket = SOCKET_ERROR;
+    if (socket != SOCKET_ERROR) {
+        // successfull
+        _sockets[socket].state = SOCK_CREATED;
+        _sockets[socket].pending = 0;
+        _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
+    }
+    UNLOCK();
     return socket;
 }
 
 bool MDMParser::socketConnect(int socket, const char * host, int port)
 {
-    TRACE("socketConnect(%d,%s,%d)\r\n", socket, host,port);
     IP ip = gethostbyname(host);
     if (ip == NOIP)
         return false;
     // connect to socket
-    if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED))
-        return false;
-    sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", socket, IPNUM(ip), port);
-    if (RESP_OK != waitFinalResp())
-        return false;
-    _sockets[socket].state = SOCK_CONNECTED;
-    return true;
+    bool ok = false; 
+    LOCK();
+    if (ISSOCKET(socket) && (_sockets[socket].state == SOCK_CREATED)) {
+        TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port);
+        sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", socket, IPNUM(ip), port);
+        if (RESP_OK == waitFinalResp())
+            ok = _sockets[socket].state = SOCK_CONNECTED;
+    }
+    UNLOCK();
+    return ok;
 }
 
 bool MDMParser::socketIsConnected(int socket)
 {
+    bool ok = false;
+    LOCK();
     TRACE("socketIsConnected(%d)\r\n", socket);
-    if (!ISSOCKET(socket))
-        return false;
-    return _sockets[socket].state == SOCK_CONNECTED;
+    ok = ISSOCKET(socket) && 
+         _sockets[socket].state == SOCK_CONNECTED;
+    UNLOCK();
+    return ok;
 }
 
 bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
 {
+    bool ok = false;
+    LOCK();
     TRACE("socketSetBlocking(%d,%d)\r\n", socket, timeout_ms);
-    if (!ISSOCKET(socket))
-        return false;
-    _sockets[socket].timeout_ms = timeout_ms;
-    return true;
+    if (ISSOCKET(socket)) {
+        _sockets[socket].timeout_ms = timeout_ms;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
 }
 
 bool  MDMParser::socketClose(int socket)
 {
-    TRACE("socketClose(%d)\r\n", socket);
-    if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED))
-        return false;
-    sendFormated("AT+USOCL=%d\r\n", socket);
-    if (RESP_OK != waitFinalResp())
-        return false;
-    _sockets[socket].state = SOCK_CREATED;
-    return true;
+    bool ok = false;
+    LOCK();
+    if (ISSOCKET(socket) && (_sockets[socket].state == SOCK_CONNECTED)) {
+        TRACE("socketClose(%d)\r\n", socket);
+        sendFormated("AT+USOCL=%d\r\n", socket);
+        if (RESP_OK == waitFinalResp()) {
+            _sockets[socket].state = SOCK_CREATED;
+            ok = true;
+        }
+    }
+    UNLOCK();
+    return ok;
 }
 
 bool  MDMParser::socketFree(int socket)
 {
-    TRACE("socketFree(%d)\r\n", socket);
+    // make sure it is closed
     socketClose(socket);
-    if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CREATED))
-        return false;
-    _sockets[socket].state = SOCK_FREE;
-    return true;
+    bool ok = true;
+    LOCK();
+    if (ISSOCKET(socket) && (_sockets[socket].state == SOCK_CREATED)) {
+        TRACE("socketFree(%d)\r\n", socket);
+        _sockets[socket].state = SOCK_FREE;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
 }
 
 #define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
@@ -936,12 +995,17 @@
         int blk = USO_MAX_WRITE;
         if (cnt < blk) 
             blk = cnt;
+        bool ok = false;
+        LOCK();
         sendFormated("AT+USOWR=%d,%d\r\n",socket,blk);
-        if (RESP_PROMPT != waitFinalResp())
-            return SOCKET_ERROR;
-        RELAX_MS(50);
-        send(buf, blk);
-        if (RESP_OK != waitFinalResp()) 
+        if (RESP_PROMPT == waitFinalResp()) {
+            wait_ms(50);
+            send(buf, blk);
+            if (RESP_OK == waitFinalResp()) 
+                ok = true;
+        }
+        UNLOCK();
+        if (!ok) 
             return SOCKET_ERROR;
         buf += blk;
         cnt -= blk;
@@ -957,12 +1021,17 @@
         int blk = USO_MAX_WRITE;
         if (cnt < blk) 
             blk = cnt;
-       sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",socket,IPNUM(ip),port,blk);
-        if (RESP_PROMPT != waitFinalResp())
-            return SOCKET_ERROR;
-        RELAX_MS(50);
-        send(buf, blk);
-        if (RESP_OK != waitFinalResp())
+        bool ok = false;
+        LOCK();
+        sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",socket,IPNUM(ip),port,blk);
+        if (RESP_PROMPT == waitFinalResp()) {
+            wait_ms(50);
+            send(buf, blk);
+            if (RESP_OK == waitFinalResp())
+                ok = true;
+        }
+        UNLOCK();
+        if (!ok)
             return SOCKET_ERROR;
         buf += blk;
         cnt -= blk;
@@ -972,14 +1041,17 @@
 
 int MDMParser::socketReadable(int socket)
 {
-    TRACE("socketReadable(%d)\r\n", socket);
-    if (!ISSOCKET(socket) || (_sockets[socket].state != SOCK_CONNECTED))
-        return SOCKET_ERROR;
-    // allow to receive unsolicited commands 
-    waitFinalResp(NULL, NULL, 0);
-    if (_sockets[socket].state != SOCK_CONNECTED)
-        return SOCKET_ERROR;
-    return _sockets[socket].pending;
+    int pending = SOCKET_ERROR;
+    LOCK();
+    if (ISSOCKET(socket) && (_sockets[socket].state == SOCK_CONNECTED)) {
+        TRACE("socketReadable(%d)\r\n", socket);
+        // allow to receive unsolicited commands 
+        waitFinalResp(NULL, NULL, 0);
+        if (_sockets[socket].state == SOCK_CONNECTED)
+           pending = _sockets[socket].pending; 
+    }
+    UNLOCK();
+    return pending;
 }
 
 int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
@@ -998,32 +1070,43 @@
 {
     int cnt = 0;
     TRACE("socketRecv(%d,,%d)\r\n", socket, len);
-    if (!ISSOCKET(socket))
-        return SOCKET_ERROR;
+#ifdef MDM_DEBUG
     memset(buf, '\0', len);
+#endif
     Timer timer;
     timer.start();
     while (len) {
         int blk = MAX_SIZE; // still need space for headers and unsolicited  commands 
-        if (_sockets[socket].pending < blk)
-            blk = _sockets[socket].pending;
         if (len < blk) blk = len;
-        if (blk) {
-            sendFormated("AT+USORD=%d,%d\r\n",socket, blk);
-            if (RESP_OK != waitFinalResp(_cbUSORD, buf)) {
-                return SOCKET_ERROR;
+        bool ok = false;        
+        LOCK();
+        if (ISSOCKET(socket)) {
+            if (_sockets[socket].state == SOCK_CONNECTED) {
+                if (_sockets[socket].pending < blk)
+                    blk = _sockets[socket].pending;
+                if (blk > 0) {
+                    sendFormated("AT+USORD=%d,%d\r\n",socket, blk);
+                    if (RESP_OK == waitFinalResp(_cbUSORD, buf)) {
+                        _sockets[socket].pending -= blk;
+                        len -= blk;
+                        cnt += blk;
+                        buf += blk;
+                        ok = true;
+                    }
+                } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
+                    ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
+                } else {
+                    len = 0;
+                    ok = true;
+                }
+            } else if (_sockets[socket].state == SOCK_CREATED) {
+                len = 0;
+                ok = true;
             }
-            len -= blk;
-            cnt += blk;
-            buf += blk;
-            _sockets[socket].pending -= blk;
-        } else if ((_sockets[socket].state == SOCK_CONNECTED) && 
-                   !TIMEOUT(timer, _sockets[socket].timeout_ms)) {
-            // allow to receive unsolicited commands 
-            waitFinalResp(NULL, NULL, 10);
-        } else {
-            len = 0; // no more data and socket closed or timed-out
         }
+        UNLOCK();
+        if (!ok)
+            return SOCKET_ERROR;
     }
     return cnt;
 }
@@ -1032,9 +1115,9 @@
 {
     if ((type == TYPE_PLUS) && param) {
         int sz, sk, p, a,b,c,d;
-        if ((sscanf(buf, "\r\n+USORF: %d,\""IPSTR"\",%d,%d,", 
-            &sk,&a,&b,&c,&d,&p,&sz) == 7) && 
-            (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
+        int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 
+            &sk,&a,&b,&c,&d,&p,&sz);
+        if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
             memcpy(param->buf, &buf[len-1-sz], sz);
             param->ip = IPADR(a,b,c,d);
             param->port = p;
@@ -1047,34 +1130,43 @@
 {
     int cnt = 0;
     TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
-    if (!ISSOCKET(socket))
-        return SOCKET_ERROR;
+#ifdef MDM_DEBUG
     memset(buf, '\0', len);
+#endif
     Timer timer;
     timer.start();
     while (len) {
         int blk = MAX_SIZE; // still need space for headers and unsolicited commands 
-        if (_sockets[socket].pending < blk)
-            blk = _sockets[socket].pending;
         if (len < blk) blk = len;
-        if (blk) {
-            sendFormated("AT+USORF=%d,%d\r\n",socket, blk);
-            USORFparam param;
-            param.buf = buf;
-            if (RESP_OK != waitFinalResp(_cbUSORF, &param)) {
-                return SOCKET_ERROR;
+        bool ok = false;        
+        LOCK();
+        if (ISSOCKET(socket)) {
+            if (_sockets[socket].pending < blk)
+                blk = _sockets[socket].pending;
+            if (blk > 0) {
+                sendFormated("AT+USORF=%d,%d\r\n",socket, blk);
+                USORFparam param;
+                param.buf = buf;
+                if (RESP_OK == waitFinalResp(_cbUSORF, &param)) {
+                    _sockets[socket].pending -= blk;
+                    *ip = param.ip;
+                    *port = param.port;
+                    len -= blk;
+                    cnt += blk;
+                    buf += blk;
+                    len = 0; // done 
+                    ok = true;
+                }
+            } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
+                ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
+            } else {
+                len = 0; // no more data and socket closed or timed-out
+                ok = true;
             }
-            *ip = param.ip;
-            *port = param.port;
-            len -= blk;
-            cnt += blk;
-            buf += blk;
-            _sockets[socket].pending -= blk;
-        } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
-            // allow to receive unsolicited commands 
-            waitFinalResp(NULL, NULL, 10);
-        } else
-            len = 0; // no more data and socket closed or timed-out
+        }
+        UNLOCK();
+        if (!ok)
+            return SOCKET_ERROR;
     }
     timer.stop();
     timer.reset();
@@ -1098,37 +1190,41 @@
 }
 
 int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
+    int ret = -1;
+    LOCK();
     sendFormated("AT+CMGL=\"%s\"\r\n", stat);
     CMGLparam param;
     param.ix = ix;
     param.num = num;
-    if (RESP_OK != waitFinalResp(_cbCMGL, &param))
-        return -1;
-    return num - param.num;
+    if (RESP_OK == waitFinalResp(_cbCMGL, &param))
+        ret = num - param.num;
+    UNLOCK();
+    return ret;
 }
 
 bool MDMParser::smsSend(const char* num, const char* buf)
 {
+    bool ok = false;
+    LOCK();
     sendFormated("AT+CMGS=\"%s\"\r\n",num);
-    if (RESP_PROMPT != waitFinalResp(NULL,NULL,150*1000)) {
-        return false;
+    if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) {
+        send(buf, strlen(buf));
+        const char ctrlZ = 0x1A;
+        send(&ctrlZ, sizeof(ctrlZ));
+        ok = (RESP_OK == waitFinalResp());
     }
-    send(buf, strlen(buf));
-    const char ctrlZ = 0x1A;
-    send(&ctrlZ, sizeof(ctrlZ));
-    if (RESP_OK != waitFinalResp()) {
-        return false;
-    }
-    return true;
+    UNLOCK();
+    return ok;
 }
 
 bool MDMParser::smsDelete(int ix)
 {
+    bool ok = false;
+    LOCK();
     sendFormated("AT+CMGD=%d\r\n",ix);
-    if (RESP_OK != waitFinalResp()) {
-        return false;
-    }
-    return true;
+    ok = (RESP_OK == waitFinalResp());
+    UNLOCK();
+    return ok;
 }
 
 int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
@@ -1147,14 +1243,15 @@
 
 bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
 {
+    bool ok = false;
+    LOCK();
     CMGRparam param;
     param.num = num;
     param.buf = buf;
     sendFormated("AT+CMGR=%d\r\n",ix);
-    if (RESP_OK != waitFinalResp(_cbCMGR, &param)) {
-        return false;
-    }
-    return true;
+    ok = (RESP_OK == waitFinalResp(_cbCMGR, &param));
+    UNLOCK();
+    return ok;
 }
    
 // ----------------------------------------------------------------
@@ -1172,47 +1269,54 @@
 
 bool MDMParser::ussdCommand(const char* cmd, char* buf)
 {
-    if (_dev.dev == DEV_LISA_C200) 
-        return false;
+    bool ok = false;
+    LOCK();
     *buf = '\0';
-    sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
-    if (RESP_OK != waitFinalResp(_cbCUSD, buf)) {
-        return false;
+    if (_dev.dev != DEV_LISA_C200) {
+        sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
+        ok = (RESP_OK == waitFinalResp(_cbCUSD, buf));
     }
-    return true;
+    UNLOCK();
+    return ok;
 }
 
 // ----------------------------------------------------------------
    
 bool MDMParser::delFile(const char* filename)
 {
+    bool ok = false;
+    LOCK();
     sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
-    if (RESP_OK != waitFinalResp())
-        return false;
-    return true;
+    ok = (RESP_OK == waitFinalResp());
+    UNLOCK();
+    return ok;
 }
 
 int MDMParser::writeFile(const char* filename, const char* buf, int len)
 {
+    bool ok = false;
+    LOCK();
     sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
-    if (RESP_PROMPT != waitFinalResp())
-        return 0;
-    send(buf, len);
-    if (RESP_OK != waitFinalResp())
-        return 0;
-    return len;
+    if (RESP_PROMPT == waitFinalResp()) {
+        send(buf, len);
+        ok = (RESP_OK == waitFinalResp());
+    }
+    UNLOCK();
+    return ok ? len : -1;
 }
 
 int MDMParser::readFile(const char* filename, char* buf, int len)
 {
-    sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
     URDFILEparam param;
     param.filename = filename;
     param.buf = buf; 
     param.sz = len; 
     param.len = 0;
-    if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
-        return -1;
+    LOCK();
+    sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
+    if (RESP_OK != waitFinalResp(_cbURDFILE, &param));
+        param.len = -1;
+    UNLOCK();
     return param.len;
 }
 
@@ -1388,7 +1492,7 @@
               const char* fmt;                              int type; 
         } lutF[] = {
             { "\r\n+USORD: %d,%d,\"%c\"",                   TYPE_PLUS       },
-            { "\r\n+USORF: %d,\""IPSTR"\",%d,%d,\"%c\"",    TYPE_PLUS       },
+            { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"",  TYPE_PLUS       },
             { "\r\n+URDFILE: %s,%d,\"%c\"",                 TYPE_PLUS       },
         };
         static struct {