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.

Fork of C027_Support by u-blox

Revision:
95:8282dbbe1492
Parent:
90:3915192f6d7e
Child:
98:c786461edd40
--- 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 {