Dmitry Pakhomenko / VodafoneUSBModem

Dependencies:   Socket USBHostWANDongle lwip-sys lwip

Fork of VodafoneUSBModem by mbed official

Files at this revision

API Documentation at this revision

Comitter:
donatien
Date:
Thu May 24 16:40:40 2012 +0000
Child:
1:e20fc9aeb62e
Commit message:
Initial Commit

Changed in this revision

USBHostWANDongleLib.lib Show annotated file Show diff for this revision Revisions of this file
contrib/vodafone/if/VodafoneK3770.cpp Show annotated file Show diff for this revision Revisions of this file
contrib/vodafone/if/VodafoneK3770.h Show annotated file Show diff for this revision Revisions of this file
contrib/vodafone/if/vodafone/VodafoneManager.h Show annotated file Show diff for this revision Revisions of this file
main/drv/at/ATCommandsInterface.cpp Show annotated file Show diff for this revision Revisions of this file
main/drv/at/ATCommandsInterface.h Show annotated file Show diff for this revision Revisions of this file
main/drv/serial/io/IOSerialStream.cpp Show annotated file Show diff for this revision Revisions of this file
main/drv/serial/io/IOSerialStream.h Show annotated file Show diff for this revision Revisions of this file
main/drv/serial/usb/USBSerialStream.cpp Show annotated file Show diff for this revision Revisions of this file
main/drv/serial/usb/USBSerialStream.h Show annotated file Show diff for this revision Revisions of this file
main/if/info/DongleDeviceInfo.h Show annotated file Show diff for this revision Revisions of this file
main/if/ip/PPPIPInterface.cpp Show annotated file Show diff for this revision Revisions of this file
main/if/ip/PPPIPInterface.h Show annotated file Show diff for this revision Revisions of this file
main/if/sms/SMSInterface.cpp Show annotated file Show diff for this revision Revisions of this file
main/if/sms/SMSInterface.h Show annotated file Show diff for this revision Revisions of this file
main/if/ussd/USSDInterface.cpp Show annotated file Show diff for this revision Revisions of this file
main/if/ussd/USSDInterface.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostWANDongleLib.lib	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/USBHostWANDongleLib/#ae46a0638b2c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/VodafoneK3770.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,474 @@
+/* VodafoneK3770.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 4
+#ifndef __MODULE__
+#define __MODULE__ "VodafoneK3770.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "VodafoneK3770.h"
+
+VodafoneK3770::VodafoneK3770() : m_dongle(),
+m_stream(m_dongle), m_at(&m_stream),
+m_ppp(&m_stream), m_sms(&m_at), m_ussd(&m_at),
+m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false)
+{
+
+}
+
+class CREGProcessor : public IATCommandsProcessor
+{
+public:
+  CREGProcessor() : status(STATUS_REGISTERING)
+  {
+
+  }
+  enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
+  REGISTERING_STATUS getStatus()
+  {
+    return status;
+  }
+private:
+  virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+  {
+    int r;
+    if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
+    {
+      switch(r)
+      {
+      case 1:
+      case 5:
+        status = STATUS_OK;
+        break;
+      case 0:
+      case 2:
+        status = STATUS_REGISTERING;
+        break;
+      case 3:
+      default:
+        status = STATUS_FAILED;
+        break;
+      }
+    }
+    return OK;
+  }
+  virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+  {
+    return OK;
+  }
+  volatile REGISTERING_STATUS status;
+};
+
+class COPSProcessor : public IATCommandsProcessor
+{
+public:
+  COPSProcessor() : valid(false)
+  {
+    network[0] = '\0';
+    apn[0] = '\0';
+    bearer[0] = '\0';
+  }
+  char* getNetwork()
+  {
+    return network;
+  }
+  char* getAPN()
+  {
+    return apn;
+  }
+  char* getBearer()
+  {
+    return bearer;
+  }
+  bool isValid()
+  {
+    return valid;
+  }
+private:
+  virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+  {
+    int networkId;
+    int bearerId;
+    int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
+    if( s == 2 )
+    {
+      switch(networkId)
+      {
+      case 23415:
+        strcpy(network, "Vodafone UK");
+        strcpy(apn, "pp.vodafone.co.uk");
+        valid = true;
+        break;
+      case 20810:
+        strcpy(network, "SFR FR");
+        strcpy(apn, "websfr");
+        valid = true;
+        break;
+      default:
+        break;
+      }
+    }
+    else
+    {
+      return OK;
+    }
+    switch(bearerId)
+    {
+    case 0: strcpy(bearer, "GSM"); break;
+    case 1: strcpy(bearer, "GSM Compact"); break;
+    case 2: strcpy(bearer, "UTRAN"); break;
+    case 3: strcpy(bearer, "GSM w/EGPRS"); break;
+    case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
+    case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
+    case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
+    case 7: strcpy(bearer, "E-UTRAN"); break;
+
+    default:
+      break;
+    }
+    return OK;
+  }
+  virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
+  {
+    return OK;
+  }
+  char network[24];
+  char bearer[24];
+  char apn[24];
+  volatile bool valid;
+};
+
+
+int VodafoneK3770::connect(const char* apn, const char* user, const char* password)
+{
+  if( !m_ipInit )
+  {
+    m_ipInit = true;
+    m_ppp.init();
+  }
+  m_ppp.setup(user, password);
+
+  int ret = init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  m_smsInit = false; //SMS status reset
+  m_ussdInit = false; //USSD status reset
+
+  ATCommandsInterface::ATResult result;
+
+#if 0
+  //Get network info & select corresponding APN
+  COPSProcessor copsProcessor;
+  DBG("Get network info & select APN from DB");
+  ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id
+  DBG("Result of command: Err code=%d", ret);
+  DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+
+  if(!copsProcessor.isValid())
+  {
+    WARN("Connected to an unknown network, try to connect with default parameters");
+    DBG("Connected with %s", copsProcessor.getBearer());
+  }
+  else
+  {
+    DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer());
+    char cmd[48];
+    sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN());
+    ret = m_at.executeSimple(cmd, &result);
+    DBG("Result of command: Err code=%d", ret);
+    DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+    DBG("APN set to %s", copsProcessor.getAPN());
+  }
+  #else
+  if(apn != NULL)
+  {
+    char cmd[48];
+    sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
+    ret = m_at.executeSimple(cmd, &result);
+    DBG("Result of command: Err code=%d", ret);
+    DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+    DBG("APN set to %s", apn);
+  }
+  #endif
+
+
+  //Connect
+  DBG("Connecting");
+  ret = m_at.executeSimple("ATDT *99#", &result);
+  DBG("Result of command: Err code=%d", ret);
+  DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
+  m_at.close(); // Closing AT parser
+  m_atOpen = false; //Will need to be reinitialized afterwards
+
+  DBG("AT Parser closed");
+  if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT))
+  {
+    ERR("Could not connect");
+    return ret; //Could not connect
+  }
+  DBG("Connecting PPP");
+
+  ret = m_ppp.connect();
+  DBG("Result of connect: Err code=%d", ret);
+  return ret;
+}
+
+
+int VodafoneK3770::disconnect()
+{
+  DBG("Disconnecting from PPP");
+  int ret = m_ppp.disconnect();
+  if(ret)
+  {
+    ERR("Disconnect returned %d, still trying to disconnect", ret);
+  }
+
+  //Ugly but leave dongle time to recover
+  Thread::wait(500);
+
+  ATCommandsInterface::ATResult result;
+  DBG("Starting AT thread");
+  ret = m_at.open();
+  if(ret)
+  {
+    return ret;
+  }
+
+  DBG("Trying to hangup");
+
+#if 0 //Does not appear to work
+  int tries = 10;
+  do
+  {
+    ret = m_at.executeSimple("+++", &result, 1000);
+    DBG("Result of command: Err code=%d\n", ret);
+    DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+  } while(tries-- && ret);
+  if(!ret)
+  {
+    ret = m_at.executeSimple("ATH", &result);
+    DBG("Result of command: Err code=%d\n", ret);
+    DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+  }
+#endif
+
+  //Reinit AT parser
+  ret = m_at.init();
+  DBG("Result of command: Err code=%d\n", ret);
+  if(ret)
+  {
+    m_at.close(); // Closing AT parser
+    DBG("AT Parser closed, could not complete disconnection");
+    return NET_TIMEOUT;
+  }
+
+  m_at.close(); // Closing AT parser
+  DBG("AT Parser closed");
+  return OK;
+}
+
+int VodafoneK3770::sendSM(const char* number, const char* message)
+{
+  int ret = init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  if(!m_smsInit)
+  {
+    ret = m_sms.init();
+    if(ret)
+    {
+      return ret;
+    }
+    m_smsInit = true;
+  }
+
+  ret = m_sms.send(number, message);
+  if(ret)
+  {
+    return ret;
+  }
+
+  return OK;
+}
+
+int VodafoneK3770::getSM(char* number, char* message, size_t maxLength)
+{
+  int ret = init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  if(!m_smsInit)
+  {
+    ret = m_sms.init();
+    if(ret)
+    {
+      return ret;
+    }
+    m_smsInit = true;
+  }
+
+  ret = m_sms.get(number, message, maxLength);
+  if(ret)
+  {
+    return ret;
+  }
+
+  return OK;
+}
+
+int VodafoneK3770::getSMCount(size_t* pCount)
+{
+  int ret = init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  if(!m_smsInit)
+  {
+    ret = m_sms.init();
+    if(ret)
+    {
+      return ret;
+    }
+    m_smsInit = true;
+  }
+
+  ret = m_sms.getCount(pCount);
+  if(ret)
+  {
+    return ret;
+  }
+
+  return OK;
+}
+
+int VodafoneK3770::sendUSSD(const char* command, char* result, size_t maxLength)
+{
+  int ret = init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  if(!m_ussdInit)
+  {
+    ret = m_ussd.init();
+    if(ret)
+    {
+      return ret;
+    }
+    m_ussdInit = true;
+  }
+
+  ret = m_ussd.send(command, result, maxLength);
+  if(ret)
+  {
+    return ret;
+  }
+
+  return OK;
+}
+
+ATCommandsInterface* VodafoneK3770::getATCommandsInterface()
+{
+  return &m_at;
+}
+
+int VodafoneK3770::init()
+{
+  if( !m_dongleConnected )
+  {
+    m_dongleConnected = true;
+    while( !m_dongle.connected() )
+    {
+      m_dongle.tryConnect();
+      Thread::wait(10);
+    }
+  }
+
+  if(m_atOpen)
+  {
+    return OK;
+  }
+
+  DBG("Starting AT thread if needed");
+  int ret = m_at.open();
+  if(ret)
+  {
+    return ret;
+  }
+
+  DBG("Sending initialisation commands");
+  ret = m_at.init();
+  if(ret)
+  {
+    return ret;
+  }
+
+  DBG("Configuring unsolicited result codes support properly");
+  //Configuring port
+  ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant
+  if(ret != OK)
+  {
+    return NET_PROTOCOL;
+  }
+
+  ATCommandsInterface::ATResult result;
+
+  //Wait for network registration
+  CREGProcessor cregProcessor;
+  do
+  {
+    DBG("Waiting for network registration");
+    ret = m_at.execute("AT+CREG?", &cregProcessor, &result);
+    DBG("Result of command: Err code=%d\n", ret);
+    DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+    if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
+    {
+      Thread::wait(3000);
+    }
+  } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
+  if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
+  {
+    ERR("Registration denied");
+    return NET_AUTH;
+  }
+
+  m_atOpen = true;
+
+  return OK;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/VodafoneK3770.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,113 @@
+/* VodafoneK3770.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef VODAFONEK3770_H_
+#define VODAFONEK3770_H_
+
+#include "core/fwk.h"
+
+#include "USB3GModule/WANDongle.h"
+#include "drv/at/ATCommandsInterface.h"
+#include "drv/serial/usb/USBSerialStream.h"
+#include "if/ip/PPPIPInterface.h"
+#include "if/sms/SMSInterface.h"
+#include "if/ussd/USSDInterface.h"
+
+/** Vodafone K3770 dongle
+ */
+class VodafoneK3770
+{
+public:
+  /** Create Vodafone K3770 dongle API instance
+
+   */
+  VodafoneK3770();
+
+  //Internet-related functions
+
+  /** Open a 3G internet connection
+      @return 0 on success, error code on failure
+  */
+  int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
+
+  /** Close the internet connection
+     @return 0 on success, error code on failure
+  */
+  int disconnect();
+
+
+  /** Send a SM
+     @param number The receiver's phone number
+     @param message The message to send
+     @return 0 on success, error code on failure
+   */
+  int sendSM(const char* number, const char* message);
+
+
+  /** Receive a SM
+     @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
+     @param message Pointer to a buffer to store the the incoming message
+     @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+     @return 0 on success, error code on failure
+   */
+  int getSM(char* number, char* message, size_t maxLength);
+
+  /** Get the number of SMs in the incoming box
+     @param pCount pointer to store the number of unprocessed SMs on
+     @return 0 on success, error code on failure
+   */
+  int getSMCount(size_t* pCount);
+
+  /** Send a USSD command & wait for its result
+    @param command The command to send
+    @param result Buffer in which to store the result
+    @param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
+    @return 0 on success, error code on failure
+  */
+  int sendUSSD(const char* command, char* result, size_t maxLength);
+
+  /** Get the ATCommandsInterface instance
+     @return Pointer to the ATCommandsInterface instance
+   */
+  ATCommandsInterface* getATCommandsInterface();
+
+protected:
+  int init();
+
+private:
+  WANDongle m_dongle;
+  USBSerialStream m_stream;
+  ATCommandsInterface m_at;
+  PPPIPInterface m_ppp;
+  SMSInterface m_sms;
+  USSDInterface m_ussd;
+
+  bool m_dongleConnected;
+  bool m_ipInit;
+  bool m_smsInit;
+  bool m_ussdInit;
+  bool m_atOpen;
+};
+
+
+#endif /* VODAFONEK3770_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vodafone/if/vodafone/VodafoneManager.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ * VodafoneManager.h
+ *
+ *  Created on: 16 déc. 2011
+ *      Author: Donatien
+ */
+
+#ifndef VODAFONEMANAGER_H_
+#define VODAFONEMANAGER_H_
+
+#include "core/fwk.h"
+#include "if/ussd/USSDInterface.h"
+
+class VodafoneManager : protected USSDInterface
+{
+
+
+};
+
+#endif /* VODAFONEMANAGER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/at/ATCommandsInterface.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,806 @@
+/* ATCommandsInterface.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 2//ERR+WARN
+#ifndef __MODULE__
+#define __MODULE__ "ATCommandsInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <cstdio>
+//#include <cstring> //For memset, strstr...
+
+using std::memmove;
+
+#include "ATCommandsInterface.h"
+
+ATCommandsInterface::ATCommandsInterface(IOStream* pStream) :
+   m_pStream(pStream), m_open(false), m_env2AT(), m_AT2Env(), m_processingMtx(),
+   m_processingThread(&ATCommandsInterface::staticCallback, this, (osPriority)AT_THREAD_PRIORITY, 4*192),
+   m_eventsMtx()
+{
+  memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*));
+
+  m_processingMtx.lock();
+}
+
+//Open connection to AT Interface in order to execute command & register/unregister events
+int ATCommandsInterface::open()
+{
+  if( m_open )
+  {
+    WARN("AT interface is already open");
+    return OK;
+  }
+  DBG("Opening AT interface");
+  //Start processing
+  m_processingThread.signal_set(AT_SIG_PROCESSING_START);
+
+  m_processingMtx.unlock();
+
+  m_open = true;
+
+  //Advertize this to events handlers
+  m_eventsMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+  {
+    if( m_eventsHandlers[i] != NULL )
+    {
+      m_eventsHandlers[i]->onDispatchStart();
+    }
+  }
+  m_eventsMtx.unlock();
+
+  DBG("AT interface opened");
+
+  return OK;
+}
+
+//Initialize AT link
+int ATCommandsInterface::init()
+{
+  DBG("Sending ATZ E1 V1");
+  //Should we flush m_pStream at this point ???
+  int err;
+  int tries = 5;
+  do
+  {
+    err = executeSimple("ATZ E1 V1", NULL, 3000); //Enable echo and verbosity
+    if(err && tries)
+    {
+      WARN("No response, trying again");
+      Thread::wait(1000); //Give dongle time to recover
+    }
+  } while(err && tries--);
+  if( err )
+  {
+    ERR("Sending ATZ E1 V1 returned with err code %d", err);
+    return err;
+  }
+
+  DBG("AT interface initialized");
+
+  return OK;
+}
+
+//Close connection
+int ATCommandsInterface::close()
+{
+  if( !m_open )
+  {
+    WARN("AT interface is already closed");
+    return OK;
+  }
+
+  DBG("Closing AT interface");
+
+  //Stop processing
+  m_processingThread.signal_set(AT_SIG_PROCESSING_STOP);
+  //m_stopSphre.release();
+
+  int* msg = m_env2AT.alloc(osWaitForever);
+  *msg = AT_STOP;
+  m_env2AT.put(msg); //Used to unstall the process if needed
+
+  //Unlock process routine (abort read)
+  m_pStream->abortRead(); //This is thread-safe
+  m_processingMtx.lock();
+  m_open = false;
+
+  //Advertize this to events handlers
+  m_eventsMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+  {
+    if( m_eventsHandlers[i] != NULL )
+    {
+      m_eventsHandlers[i]->onDispatchStop();
+    }
+  }
+  m_eventsMtx.unlock();
+
+  DBG("AT interface closed");
+  return OK;
+}
+
+bool ATCommandsInterface::isOpen()
+{
+  return m_open;
+}
+
+int ATCommandsInterface::executeSimple(const char* command, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+  return execute(command, this, pResult, timeout);
+}
+
+int ATCommandsInterface::execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+  DBG("Executing command %s", command);
+  if(!m_open)
+  {
+    WARN("Interface is not open!");
+    return NET_INVALID;
+  }
+
+  //Lock transaction mutex
+  m_transactionMtx.lock();
+
+  //Discard previous result if it arrived too late
+  osEvent evt = m_AT2Env.get(0);
+
+  if(evt.status == osEventMail)
+  {
+    m_AT2Env.free((int*)evt.value.p);
+    WARN("Previous result discarded");
+  }
+
+  //Send params to the process routine
+  m_transactionCommand = command;
+  if(pProcessor != NULL)
+  {
+    m_pTransactionProcessor = pProcessor;
+  }
+  else
+  {
+    m_pTransactionProcessor = this; //Use default behaviour
+  }
+
+  Thread::wait(100); //FIXME find stg else
+
+  DBG("Sending command ready signal to AT thread & aborting current blocking read operation");
+
+  //Produce command ready signal
+  int* msg = m_env2AT.alloc(osWaitForever);
+  *msg = AT_CMD_READY;
+  m_env2AT.put(msg);
+
+  DBG("Trying to enter abortRead()");
+  //Unlock process routine (abort read)
+  m_pStream->abortRead(); //This is thread-safe
+
+  //Wait for a result (get result message)
+  evt = m_AT2Env.get(timeout);
+
+  if(evt.status != osEventMail)
+  {
+    //Cancel request
+    msg = m_env2AT.alloc(osWaitForever);
+    *msg = AT_TIMEOUT;
+    m_env2AT.put(msg);
+
+    DBG("Trying to enter abortRead()");
+    //Unlock process routine (abort read)
+    m_pStream->abortRead(); //This is thread-safe
+
+    WARN("Command returned no message");
+    m_transactionMtx.unlock();
+    return NET_TIMEOUT;
+  }
+  DBG("Command returned with message %d", *msg);
+
+  m_AT2Env.free((int*)evt.value.p);
+
+  if(pResult != NULL)
+  {
+    *pResult = m_transactionResult;
+  }
+
+  int ret = ATResultToReturnCode(m_transactionResult);
+  if(ret != OK)
+  {
+    WARN("Command returned AT result %d with code %d", m_transactionResult.result, m_transactionResult.code);
+  }
+
+  DBG("Command returned successfully");
+
+  //Unlock transaction mutex
+  m_transactionMtx.unlock();
+
+  return ret;
+}
+
+int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr)
+{
+  m_eventsMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+  {
+    if( m_eventsHandlers[i] == NULL )
+    {
+      m_eventsHandlers[i] = pHdlr;
+      m_eventsMtx.unlock();
+      return OK;
+    }
+  }
+  m_eventsMtx.unlock();
+  return NET_OOM; //No room left
+}
+
+int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr)
+{
+  m_eventsMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find handler in list
+  {
+    if( m_eventsHandlers[i] == pHdlr )
+    {
+      m_eventsHandlers[i] = NULL;
+      m_eventsMtx.unlock();
+      return OK;
+    }
+  }
+  m_eventsMtx.unlock();
+  return NET_NOTFOUND; //Not found
+}
+
+
+int ATCommandsInterface::tryReadLine()
+{
+  static bool lineDetected = false;
+
+  //Block on serial read or incoming command
+  DBG("Trying to read a new line from stream");
+  int ret = m_pStream->waitAvailable(); //This can be aborted
+  size_t readLen = 0;
+  if(ret == OK)
+  {
+    ret = m_pStream->read((uint8_t*)m_inputBuf + m_inputPos, &readLen, AT_INPUT_BUF_SIZE - 1 - m_inputPos, 0); //Do NOT wait at this point
+  }
+  if(ret == OK)
+  {
+    m_inputPos+=readLen;
+    m_inputBuf[m_inputPos] = '\0'; //Add null terminating character to ease the use of str* functions
+    DBG("In buffer: [%s]", m_inputBuf);
+  }
+
+  if( ret == NET_INTERRUPTED ) //It is worth checking readLen as data might have been read even though the read was interrupted
+  {
+    DBG("Read was interrupted");
+    return NET_INTERRUPTED; //0 chars were read
+  }
+  else if(readLen == 0)
+  {
+    DBG("Nothing read");
+    return OK; //0 chars were read
+  }
+
+  DBG("Trying to process incoming line");
+  bool lineProcessed = false;
+
+  do
+  {
+    lineProcessed = false; //Reset flag
+
+    DBG("New iteration");
+
+    //Look for a new line
+    if(!lineDetected)
+    {
+      DBG("No line detected yet");
+      //Try to look for a starting CRLF
+      char* crPtr = strchr(m_inputBuf, CR);
+      /*
+      Different cases at this point:
+      - CRLF%c sequence: this is the start of a line
+      - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
+      - LF: this is the trailing LF char of the previous line, discard
+      - CR / CRLF incomplete sequence: more data is needed to determine which action to take
+      - %c ... CR sequence: this should be the echo of the previous sequence
+      - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
+
+      In every case, move mem at the beginning
+      */
+      if(crPtr != NULL)
+      {
+        DBG("CR char found");
+
+#if 0
+        //Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
+        memmove(m_inputBuf, crPtr, (m_inputPos + 1) - (crPtr-m_inputBuf)); //Move null-terminating char as well
+        m_inputPos = m_inputPos - (crPtr-m_inputBuf); //Adjust m_inputPos
+#endif
+
+        //If the line starts with CR, this should be a result code
+        if( crPtr == m_inputBuf )
+        {
+          //To determine the sequence we need at least 3 chars
+          if(m_inputPos >= 3)
+          {
+            //Look for a LF char next to the CR char
+            if(m_inputBuf[1] == LF)
+            {
+              //At this point we can check whether this is the end of a preceding line or the beginning of a new one
+              if(m_inputBuf[2] != CR)
+              {
+                DBG("Beginning of new line found");
+                //Beginning of a line
+                lineDetected = true; //Move to next state-machine step
+              }
+              else
+              {
+                //End of an unprocessed line
+                WARN("End of unprocessed line");
+              }
+              //In both cases discard CRLF
+              DBG("Discarding CRLF");
+              memmove(m_inputBuf, m_inputBuf + 2, (m_inputPos + 1) - 2); //Move null-terminating char as well
+              m_inputPos = m_inputPos - 2; //Adjust m_inputPos
+            }
+            else
+            {
+              //This is completely unexpected, discard the CR char to try to recover good state
+              WARN("Unexpected %c char (%02d code) found after CR char", m_inputBuf[1]);
+              memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
+              m_inputPos = m_inputPos - 1; //Adjust m_inputPos
+            }
+          }
+        }
+        //if the line does NOT begin with CR, this can be an echo of the previous command, process it
+        else
+        {
+          int crPos = crPtr - m_inputBuf;
+          int lfOff = 0; //Offset for LF if present
+          DBG("New line found (possible echo of command)");
+          //This is the end of line
+          //Replace m_inputBuf[crPos] with null-terminating char
+          m_inputBuf[crPos] = '\0';
+          //Check if there is a LF char afterwards
+          if(m_inputPos - crPos >= 1)
+          {
+            if(m_inputBuf[crPos+1] == LF)
+            {
+              lfOff++; //We will discard LF char as well
+            }
+          }
+          //Process line
+          processReadLine();
+          //Shift remaining data to beginning of buffer
+          memmove(m_inputBuf, m_inputBuf + crPos + lfOff + 1, (m_inputPos + 1) - (crPos + lfOff + 1)); //Move null-terminating char as well
+          m_inputPos = m_inputPos - (crPos + lfOff + 1); //Adjust m_inputPos
+          DBG("One line was successfully processed");
+          lineProcessed = true; //Line was processed with success
+          lineDetected = false; //Search now for a new line
+        }
+      }
+      else if(m_inputBuf[0] == LF) //If there is a remaining LF char from the previous line, discard it
+      {
+        DBG("Discarding single LF char");
+        memmove(m_inputBuf, m_inputBuf + 1, (m_inputPos + 1) - 1); //Move null-terminating char as well
+        m_inputPos = m_inputPos - 1; //Adjust m_inputPos
+      }
+    }
+
+    //Look for the end of line
+    if(lineDetected)
+    {
+      DBG("Looking for end of line");
+      //Try to look for a terminating CRLF
+      char* crPtr = strchr(m_inputBuf, CR);
+      /*
+      Different cases at this point:
+      - CRLF sequence: this is the end of the line
+      - CR%c sequence : unexpected
+      - CR incomplete sequence: more data is needed to determine which action to take
+      */
+
+      //Try to look for a '>' (greater than character) that marks an entry prompt
+      char* greaterThanPtr = strchr(m_inputBuf, GD);
+      /*
+      This character must be detected as there is no CRLF sequence at the end of an entry prompt
+       */
+
+      if(crPtr != NULL)
+      {
+        DBG("CR char found");
+        int crPos = crPtr - m_inputBuf;
+        //To determine the sequence we need at least 2 chars
+        if(m_inputPos - crPos >= 2)
+        {
+          //Look for a LF char next to the CR char
+          if(m_inputBuf[crPos + 1] == LF)
+          {
+            DBG("End of new line found");
+            //This is the end of line
+            //Replace m_inputBuf[crPos] with null-terminating char
+            m_inputBuf[crPos] = '\0';
+            //Process line
+            int ret = processReadLine();
+            if(ret)
+            {
+              m_inputPos = 0;
+              lineDetected = false;
+              return ret;
+            }
+
+            //If sendData has been called, all incoming data has been discarded
+            if(m_inputPos > 0)
+            {
+              //Shift remaining data to beginning of buffer
+              memmove(m_inputBuf, m_inputBuf + crPos + 2, (m_inputPos + 1) - (crPos + 2)); //Move null-terminating char as well
+              m_inputPos = m_inputPos - (crPos + 2); //Adjust m_inputPos
+            }
+
+            DBG("One line was successfully processed");
+            lineProcessed = true; //Line was processed with success
+          }
+          else
+          {
+            //This is completely unexpected, discard all chars till the CR char to try to recover good state
+            WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[crPos + 1]);
+            memmove(m_inputBuf, m_inputBuf + crPos + 1, (m_inputPos + 1) - (crPos + 1)); //Move null-terminating char as well
+            m_inputPos = m_inputPos - (crPos + 1); //Adjust m_inputPos
+          }
+          lineDetected = false; //In both case search now for a new line
+        }
+      }
+      else if(greaterThanPtr != NULL)
+      {
+        DBG("> char found");
+        int gdPos = greaterThanPtr - m_inputBuf;
+        //To determine the sequence we need at least 2 chars
+        if(m_inputPos - gdPos >= 2)
+        {
+          //Look for a space char next to the GD char
+          if(m_inputBuf[gdPos + 1] == ' ')
+          {
+            //This is an entry prompt
+            //Replace m_inputBuf[gdPos] with null-terminating char
+            m_inputBuf[gdPos] = '\0';
+
+            //Shift remaining data to beginning of buffer
+            memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
+            m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
+
+            //Process prompt
+            ret = processEntryPrompt();
+            if(ret)
+            {
+              m_inputPos = 0;
+              lineDetected = false;
+              return ret;
+            }
+
+            DBG("One line was successfully processed");
+            lineProcessed = true; //Line was processed with success
+          }
+          else
+          {
+            //This is completely unexpected, discard all chars till the GD char to try to recover good state
+            WARN("Unexpected %c char (%02d code) found in incoming line", m_inputBuf[gdPos + 1]);
+            memmove(m_inputBuf, m_inputBuf + gdPos + 1, (m_inputPos + 1) - (gdPos + 1)); //Move null-terminating char as well
+            m_inputPos = m_inputPos - (gdPos + 1); //Adjust m_inputPos
+          }
+          lineDetected = false; //In both case search now for a new line
+        }
+      }
+    }
+  } while(lineProcessed); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again
+
+  //If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short)
+  if(m_inputPos == AT_INPUT_BUF_SIZE - 1)
+  {
+    //Discard everything
+    m_inputPos = 0;
+    WARN("Incoming buffer is too short to process incoming line");
+    //Look for a new line
+    lineDetected = false;
+  }
+
+  DBG("Processed every full incoming lines");
+
+  return OK;
+}
+
+int ATCommandsInterface::trySendCommand()
+{
+  osEvent evt = m_env2AT.get(0);
+  DBG("status = %d, msg = %d", evt.status, evt.value.p);
+  if(evt.status == osEventMail)
+  {
+    int* msg = (int*) evt.value.p;
+    if( *msg == AT_CMD_READY ) //Command pending
+    {
+      if(m_transactionState != IDLE)
+      {
+        WARN("Previous command not processed!");
+      }
+      DBG("Sending pending command");
+      m_pStream->write((uint8_t*)m_transactionCommand, strlen(m_transactionCommand), osWaitForever);
+      char cr = CR;
+      m_pStream->write((uint8_t*)&cr, 1, osWaitForever); //Carriage return line terminator
+      m_transactionState = COMMAND_SENT;
+    }
+    else
+    {
+      m_transactionState = IDLE; //State-machine reset
+    }
+    m_env2AT.free(msg);
+  }
+  return OK;
+}
+
+int ATCommandsInterface::processReadLine()
+{
+  DBG("Processing read line [%s]", m_inputBuf);
+  //The line is stored in m_inputBuf
+  if(m_transactionState == COMMAND_SENT)
+  {
+    //If the command has been sent, checks echo to see if it has been received properly
+    if( strcmp(m_transactionCommand, m_inputBuf) == 0 )
+    {
+      DBG("Command echo received");
+      //If so, it means that the following lines will only be solicited results
+      m_transactionState = READING_RESULT;
+      return OK;
+    }
+  }
+  if(m_transactionState == IDLE || m_transactionState == COMMAND_SENT)
+  {
+    bool found = false;
+    char* pSemicol = strchr(m_inputBuf, ':');
+    char* pData = NULL;
+    if( pSemicol != NULL ) //Split the identifier & the result code (if it exists)
+    {
+      *pSemicol = '\0';
+      pData = pSemicol + 1;
+      if(pData[0]==' ')
+      {
+        pData++; //Suppress whitespace
+      }
+    }
+    //Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command
+    m_eventsMtx.lock();
+    //Go through the list
+    for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+    {
+      if( m_eventsHandlers[i] != NULL )
+      {
+        if( m_eventsHandlers[i]->isATCodeHandled(m_inputBuf) )
+        {
+          m_eventsHandlers[i]->onEvent(m_inputBuf, pData);
+          found = true; //Do not break here as there might be multiple handlers for one event type
+        }
+      }
+    }
+    m_eventsMtx.unlock();
+    if(found)
+    {
+      return OK;
+    }
+  }
+  if(m_transactionState == READING_RESULT)
+  {
+    //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s)
+    if(strcmp("OK", m_inputBuf) == 0)
+    {
+      DBG("OK result received");
+      m_transactionResult.code = 0;
+      m_transactionResult.result = ATResult::AT_OK;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else if(strcmp("ERROR", m_inputBuf) == 0)
+    {
+      DBG("ERROR result received");
+      m_transactionResult.code = 0;
+      m_transactionResult.result = ATResult::AT_ERROR;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else if(strncmp("CONNECT", m_inputBuf, 7 /*=strlen("CONNECT")*/) == 0) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
+    {
+      DBG("CONNECT result received");
+      m_transactionResult.code = 0;
+      m_transactionResult.result = ATResult::AT_CONNECT;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else if(strcmp("COMMAND NOT SUPPORT", m_inputBuf) == 0) //Huawei-specific, not normalized
+    {
+      DBG("COMMAND NOT SUPPORT result received");
+      m_transactionResult.code = 0;
+      m_transactionResult.result = ATResult::AT_ERROR;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else if(strstr(m_inputBuf, "+CME ERROR:") == m_inputBuf) //Mobile Equipment Error
+    {
+      std::sscanf(m_inputBuf + 12 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
+      DBG("+CME ERROR: %d result received", m_transactionResult.code);
+      m_transactionResult.result = ATResult::AT_CME_ERROR;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else if(strstr(m_inputBuf, "+CMS ERROR:") == m_inputBuf) //SIM Error
+    {
+      std::sscanf(m_inputBuf + 13 /* =strlen("+CME ERROR: ") */, "%d", &m_transactionResult.code);
+      DBG("+CMS ERROR: %d result received", m_transactionResult.code);
+      m_transactionResult.result = ATResult::AT_CMS_ERROR;
+      m_transactionState = IDLE;
+      int* msg = m_AT2Env.alloc(osWaitForever);
+      *msg = AT_RESULT_READY;
+      m_AT2Env.put(msg); //Command has been processed
+      return OK;
+    }
+    else
+    {
+      DBG("Unprocessed result received: '%s'", m_inputBuf);
+      //Must call transaction processor to complete line processing
+      int ret = m_pTransactionProcessor->onNewATResponseLine(this, m_inputBuf); //Here sendData can be called
+      return ret;
+    }
+  }
+
+  return OK;
+}
+
+int ATCommandsInterface::processEntryPrompt()
+{
+  DBG("Calling prompt handler");
+  int ret = m_pTransactionProcessor->onNewEntryPrompt(this); //Here sendData can be called
+
+  if( ret != NET_MOREINFO ) //A new prompt is expected
+  {
+    DBG("Sending break character");
+    //Send CTRL+Z (break sequence) to exit prompt
+    char seq[2] = {BRK, 0x00};
+    sendData(seq);
+  }
+  return OK;
+}
+
+//Commands that can be called during onNewATResponseLine callback, additionally to close()
+//Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
+int ATCommandsInterface::sendData(const char* data)
+{
+  //m_inputBuf is cleared at this point (and MUST therefore be empty)
+  int dataLen = strlen(data);
+  DBG("Sending raw string of length %d", dataLen);
+  int ret = m_pStream->write((uint8_t*)data, dataLen, osWaitForever);
+  if(ret)
+  {
+    WARN("Could not write to stream (returned %d)", ret);
+    return ret;
+  }
+
+  int dataPos = 0;
+  do
+  {
+    //Read echo
+    size_t readLen;
+    int ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, MIN(dataLen - dataPos, AT_INPUT_BUF_SIZE - 1), osWaitForever); //Make sure we do not read more than needed otherwise it could break the parser
+    if(ret)
+    {
+      WARN("Could not read from stream (returned %d)", ret);
+      return ret;
+    };
+
+    if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
+    {
+      //Echo does not match output
+      WARN("Echo does not match output");
+      return NET_DIFF;
+    }
+
+    dataPos += readLen;
+    //If all characters have not been read yet
+
+  } while(dataPos < dataLen);
+
+  DBG("String sent successfully");
+
+  m_inputPos = 0; //Reset input buffer state
+
+  return OK;
+}
+
+/*static*/ void ATCommandsInterface::staticCallback(void const* p)
+{
+  ((ATCommandsInterface*)p)->process();
+}
+
+int ATCommandsInterface::ATResultToReturnCode(ATResult result) //Helper
+{
+  if(result.result == ATResult::AT_OK)
+  {
+    return OK;
+  }
+  else
+  {
+    return NET_MOREINFO;
+  }
+}
+
+/*virtual*/ int ATCommandsInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) //Default implementation for simple commands handling
+{
+  return OK;
+}
+
+/*virtual*/ int ATCommandsInterface::onNewEntryPrompt(ATCommandsInterface* pInst) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
+{
+  return OK;
+}
+
+void ATCommandsInterface::process() //Processing thread
+{
+  DBG("AT Thread started");
+  while(true)
+  {
+    DBG("AT Processing on hold");
+    m_processingThread.signal_wait(AT_SIG_PROCESSING_START); //Block until the process is started
+
+    m_processingMtx.lock();
+    DBG("AT Processing started");
+    //First of all discard buffer
+    int ret;
+    size_t readLen;
+    do //Drop everything
+    {
+      ret = m_pStream->read((uint8_t*)m_inputBuf, &readLen, AT_INPUT_BUF_SIZE - 1, 0); //Do NOT wait at this point
+    } while(ret == OK);
+    m_inputPos = 0; //Clear input buffer
+    do
+    {
+      DBG("Trying to read a new line");
+      tryReadLine();
+      DBG("Trying to send a pending command");
+      trySendCommand();
+    } while( m_processingThread.signal_wait(AT_SIG_PROCESSING_STOP, 0).status != osEventSignal ); //Loop until the process is interrupted
+    m_processingMtx.unlock();
+    DBG("AT Processing stopped");
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/at/ATCommandsInterface.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,146 @@
+/* ATCommandsInterface.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef ATCOMMANDSINTERFACE_H_
+#define ATCOMMANDSINTERFACE_H_
+
+#include "core/fwk.h"
+#include "rtos.h"
+
+#define MAX_AT_EVENTS_HANDLERS 8
+
+class ATCommandsInterface;
+
+/** Interface implemented by components handling AT events
+ *
+ */
+class IATEventsHandler
+{
+protected:
+  virtual bool isATCodeHandled(const char* atCode) = 0; //Is this AT code handled
+  virtual void onDispatchStart() = 0;
+  virtual void onDispatchStop() = 0;
+  virtual void onEvent(const char* atCode, const char* evt) = 0;
+  friend class ATCommandsInterface;
+};
+
+/** Interface implemented by components executing complex AT commands
+ *
+ */
+class IATCommandsProcessor
+{
+protected:
+  virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) = 0;
+  virtual int onNewEntryPrompt(ATCommandsInterface* pInst) = 0;
+  friend class ATCommandsInterface;
+};
+
+#define AT_INPUT_BUF_SIZE 64
+
+//Signals to be sent to the processing thread
+#define AT_SIG_PROCESSING_START 1
+#define AT_SIG_PROCESSING_STOP 2
+//Messages to be sent to the processing thread
+#define AT_CMD_READY 1
+#define AT_TIMEOUT 2
+#define AT_STOP 3
+//Messages to be sent from the processing thread
+#define AT_RESULT_READY 1
+
+/** AT Commands interface class
+ *
+ */
+class ATCommandsInterface : protected IATCommandsProcessor
+{
+public:
+  ATCommandsInterface(IOStream* pStream);
+
+  //Open connection to AT Interface in order to execute command & register/unregister events
+  int open();
+
+  //Initialize AT link
+  int init();
+
+  //Close connection
+  int close();
+  
+  bool isOpen();
+
+  class ATResult
+  {
+  public:
+    enum { AT_OK, AT_ERROR, AT_CONNECT, AT_CMS_ERROR, AT_CME_ERROR } result;
+    int code;
+  };
+
+  int executeSimple(const char* command, ATResult* pResult, uint32_t timeout=1000);
+  int execute(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
+  int registerEventsHandler(IATEventsHandler* pHdlr);
+  int deregisterEventsHandler(IATEventsHandler* pHdlr);
+
+  //Commands that can be called during onNewATResponseLine callback, additionally to close()
+  //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
+  int sendData(const char* data);
+
+  static void staticCallback(void const* p);
+private:
+  int tryReadLine();
+  int trySendCommand();
+  int processReadLine();
+  int processEntryPrompt();
+
+  int ATResultToReturnCode(ATResult result); //Helper
+
+  virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line); //Default implementation for simple commands handling
+  virtual int onNewEntryPrompt(ATCommandsInterface* pInst); //Default implementation (just sends Ctrl+Z to exit the prompt)
+
+  void process(); //Processing thread
+
+  IOStream* m_pStream;
+  bool m_open;
+
+  const char* m_transactionCommand;
+  const char* m_transactionData;
+
+  IATCommandsProcessor* m_pTransactionProcessor;
+  ATResult m_transactionResult;
+
+  enum { IDLE, COMMAND_SENT, READING_RESULT, ABORTED } m_transactionState;
+
+  char m_inputBuf[AT_INPUT_BUF_SIZE];
+  int m_inputPos;
+
+  Mutex m_transactionMtx;
+
+  Mail<int,1> m_env2AT;
+  Mail<int,1> m_AT2Env;
+
+  IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS];
+
+  Mutex m_processingMtx;
+  Thread m_processingThread;
+
+  Mutex m_eventsMtx;
+};
+
+#endif /* ATCOMMANDSINTERFACE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/serial/io/IOSerialStream.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,257 @@
+/* IOSerialStream.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 0 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "IOSerialStream.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <stdio.h>
+
+#include "IOSerialStream.h"
+
+IOSerialStream::IOSerialStream(mbed::Serial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
+m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
+{
+  m_availableSphre.wait();
+  m_spaceSphre.wait();
+  //Attach interrupts
+  m_serial.attach(this, &IOSerialStream::readable, mbed::Serial::RxIrq);
+  m_serial.attach(this, &IOSerialStream::writeable, mbed::Serial::TxIrq);
+}
+
+/*virtual*/ IOSerialStream::~IOSerialStream()
+{
+  m_serial.attach(NULL, mbed::Serial::RxIrq);
+  m_serial.attach(NULL, mbed::Serial::TxIrq);
+}
+
+//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
+{
+  DBG("Trying to read at most %d chars", maxLength);
+  int ret = waitAvailable(timeout);
+  if(ret)
+  {
+    WARN("Error %d while waiting for incoming data");
+    return ret;
+  }
+  int readLen = MIN( available(), maxLength );
+  *pLength = readLen;
+  setupReadableISR(false);
+  while(readLen--)
+  {
+    m_inBuf.dequeue(buf);
+    buf++;
+  }
+  setupReadableISR(true);
+  DBG("Read %d chars successfully", *pLength);
+  return OK;
+}
+
+/*virtual*/ size_t IOSerialStream::available()
+{
+  setupReadableISR(false); //m_inBuf.available() is not reentrant
+  size_t len = m_inBuf.available();
+  setupReadableISR(true);
+  return len;
+}
+
+/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
+{
+  int ret;
+  if(available()) //Is data already available?
+  {
+    m_availableSphre.wait(0); //Clear the queue as data is available
+    return OK;
+  }
+
+  DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
+  ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
+  if(ret <= 0)
+  {
+    DBG("Timeout");
+    return NET_TIMEOUT;
+  }
+  if(!available()) //Even if abort has been called, return that data is available
+  {
+    DBG("Aborted");
+    return NET_INTERRUPTED;
+  }
+  DBG("Finished waiting");
+  m_availableSphre.wait(0); //Clear the queue as data is available
+  return OK;
+}
+
+/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation
+{
+  if( !available() ) //If there is data pending, no need to abort
+  {
+    m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
+  }
+  else
+  {
+    DBG("Serial is readable"); ;
+  }
+  return OK;
+}
+
+void IOSerialStream::setupReadableISR(bool en)
+{
+  if(en)
+  {
+    ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 0;
+  }
+  else
+  {
+    ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 0);
+  }
+}
+
+void IOSerialStream::readable() //Callback from m_serial when new data is available
+{
+  do
+  {
+    m_inBuf.queue(((LPC_UART_TypeDef *)UART_3)->RBR); //FIXME mbed libraries this is an awful kludge
+  } while(m_serial.readable());
+  m_availableSphre.release(); //Force exiting the waiting state
+}
+
+//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
+{
+  DBG("Trying to write %d chars", length);
+  int ret = waitSpace(timeout);
+  if(ret)
+  {
+    WARN("Error %d while waiting for space");
+    return ret;
+  }
+  DBG("Writing %d chars", length);
+  setupWriteableISR(false);
+  while(length)
+  {
+    m_outBuf.queue(*buf);
+    buf++;
+    length--;
+    if(length && !space())
+    {
+      DBG("Waiting to write remaining %d chars", length);
+      setupWriteableISR(true);
+      ret = waitSpace(timeout);
+      if(ret)
+      {
+        WARN("Error %d while waiting for space");
+        return ret;
+      }
+      setupWriteableISR(false);
+    }
+  }
+  //If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
+  if( m_outBuf.available() && m_serialTxFifoEmpty )
+  {
+    m_serialTxFifoEmpty = false;
+    uint8_t c;
+    m_outBuf.dequeue(&c);
+    //m_serial.putc((char)c);
+    ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
+  }
+  setupWriteableISR(true);
+  DBG("Write successful");
+  return OK;
+}
+
+/*virtual*/ size_t IOSerialStream::space()
+{
+  setupWriteableISR(false); //m_outBuf.available() is not reentrant
+  size_t len = CIRCBUF_SIZE - m_outBuf.available();
+  setupWriteableISR(true);
+  return len;
+}
+
+/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
+{
+  int ret;
+  if(space()) //Is still space already left?
+  {
+    m_spaceSphre.wait(0); //Clear the queue as space is available
+    return OK;
+  }
+
+  DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
+  ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
+  if(ret <= 0)
+  {
+    DBG("Timeout");
+    return NET_TIMEOUT;
+  }
+  if(!space()) //Even if abort has been called, return that space is available
+  {
+    DBG("Aborted");
+    return NET_INTERRUPTED;
+  }
+  m_spaceSphre.wait(0); //Clear the queue as space is available
+  return OK;
+}
+
+/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
+{
+  if( !space() ) //If there is space left, no need to abort
+  {
+    m_spaceSphre.release(); //Force exiting the waiting state
+  }
+  return OK;
+}
+
+void IOSerialStream::setupWriteableISR(bool en)
+{
+  if(en)
+  {
+    ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 1;
+  }
+  else
+  {
+    ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 1);
+  }
+}
+
+void IOSerialStream::writeable() //Callback from m_serial when new space is available
+{
+  if(m_outBuf.isEmpty())
+  {
+    m_serialTxFifoEmpty = true;
+  }
+  else
+  {
+    while(m_serial.writeable() && !m_outBuf.isEmpty())
+    {
+      uint8_t c;
+      m_outBuf.dequeue(&c);
+      //m_serial.putc((char)c);
+      ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
+    }
+  }
+  m_spaceSphre.release(); //Force exiting the waiting state
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/serial/io/IOSerialStream.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,77 @@
+/* IOSerialStream.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef IOSERIALSTREAM_H_
+#define IOSERIALSTREAM_H_
+
+#include "core/fwk.h"
+
+#include "Serial.h"
+
+#include "rtos.h"
+#include "core/MtxCircBuffer.h"
+
+/** Input Serial Stream for physical serial interfaces (UART...)
+This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
+*/
+#define CIRCBUF_SIZE 255
+class IOSerialStream : public IOStream
+{
+public:
+  IOSerialStream(mbed::Serial& serial);
+  /*virtual*/ ~IOSerialStream();
+
+  //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+  virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
+  virtual size_t available();
+  virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
+  virtual int abortRead(); //Abort current reading (or waiting) operation
+
+
+  //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+  virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
+  virtual size_t space();
+  virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
+  virtual int abortWrite(); //Abort current writing (or waiting) operation
+
+private:
+
+  mbed::Serial& m_serial;
+  volatile bool m_serialTxFifoEmpty;
+
+  void setupReadableISR(bool en);
+  void readable(); //Callback from m_serial when new data is available
+
+  Semaphore m_availableSphre; //Used for signalling
+
+  void setupWriteableISR(bool en);
+  void writeable(); //Callback from m_serial when new space is available
+
+  Semaphore m_spaceSphre; //Used for signalling
+
+  MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
+  MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
+
+};
+
+#endif /* IOSERIALSTREAM_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/serial/usb/USBSerialStream.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,237 @@
+/* USBSerialStream.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 0 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "USBSerialStream.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include <stdio.h>
+
+#include "USBSerialStream.h"
+
+
+USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
+m_availableSphre(1), m_spaceSphre(1), m_inBuf()
+{
+  m_availableSphre.wait();
+  m_spaceSphre.wait();
+  //Attach interrupts
+  m_serial.attach(this);
+}
+
+/*virtual*/ USBSerialStream::~USBSerialStream()
+{
+  m_serial.attach(NULL);
+}
+
+//0 for non-blocking (returns immediately), -1 for infinite blocking
+/*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
+{
+  DBG("Trying to read at most %d chars", maxLength);
+  int ret = waitAvailable(timeout);
+  if(ret)
+  {
+    WARN("Error %d while waiting for incoming data", ret);
+    return ret;
+  }
+  int readLen = MIN( available(), maxLength );
+  *pLength = readLen;
+
+  setupReadableISR(false);
+  while(readLen--)
+  {
+    m_inBuf.dequeue(buf);
+    buf++;
+  }
+  setupReadableISR(true);
+  DBG("Read %d chars successfully", *pLength);
+  return OK;
+}
+
+/*virtual*/ size_t USBSerialStream::available()
+{
+  setupReadableISR(false); //m_inBuf.available() is not reentrant
+  size_t len = m_inBuf.available();
+  setupReadableISR(true);
+  return len;
+}
+
+/*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
+{
+  int ret;
+  if(available()) //Is data already available?
+  {
+    m_availableSphre.wait(0); //Clear the queue as data is available
+    return OK;
+  }
+
+  DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
+  ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
+  if(ret <= 0)
+  {
+    DBG("Timeout");
+    return NET_TIMEOUT;
+  }
+  if(!m_inBuf.available()) //Even if abort has been called, return that data is available
+  {
+    DBG("Aborted");
+    return NET_INTERRUPTED;
+  }
+  DBG("Finished waiting");
+  m_availableSphre.wait(0); //Clear the queue as data is available
+  return OK;
+}
+
+/*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
+{
+  if( /*!available()*/true ) //If there is data pending, no need to abort
+  {
+    m_availableSphre.release(); //Force exiting the waiting state
+  }
+  else
+  {
+    DBG("Serial is readable"); ;
+  }
+  return OK;
+}
+
+void USBSerialStream::setupReadableISR(bool en)
+{
+  m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
+}
+
+void USBSerialStream::readable() //Callback from m_serial when new data is available
+{
+  while(m_serial.readable())
+  {
+    m_inBuf.queue(m_serial.getc());
+  }
+  m_serial.readPacket(); //Start read of next packet
+  m_availableSphre.release(); //Force exiting the waiting state
+}
+
+//0 for non-blocking (returns immediately), -1 for infinite blocking
+/*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
+{
+  DBG("Trying to write %d chars", length);
+  do
+  {
+    int ret = waitSpace(timeout);
+    if(ret)
+    {
+      WARN("Error %d while waiting for space");
+      return ret;
+    }
+    int writeLen = MIN( space(), length );
+    DBG("Writing %d chars", length);
+    setupWriteableISR(false);
+    while(writeLen)
+    {
+      m_outBuf.queue(*buf);
+      buf++;
+      length--;
+      writeLen--;
+    }
+    setupWriteableISR(true);
+  } while(length);
+  //If m_serial tx fifo is empty we need to start the packet write
+  setupWriteableISR(false);
+  if( m_outBuf.available() && m_serialTxFifoEmpty )
+  {
+    writeable();
+  }
+  setupWriteableISR(true);
+  DBG("Write successful");
+  return OK;
+}
+
+/*virtual*/ size_t USBSerialStream::space()
+{
+  setupWriteableISR(false); //m_outBuf.available() is not reentrant
+  size_t len = CIRCBUF_SIZE - m_outBuf.available();
+  setupWriteableISR(true);
+  return len;
+}
+
+/*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
+{
+  int ret;
+  if(space()) //Is still space already left?
+  {
+    m_spaceSphre.wait(0); //Clear the queue as space is available
+    return OK;
+  }
+
+  DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
+  ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
+  if(ret <= 0)
+  {
+    DBG("Timeout");
+    return NET_TIMEOUT;
+  }
+  if(!space()) //Even if abort has been called, return that space is available
+  {
+    DBG("Aborted");
+    return NET_INTERRUPTED;
+  }
+  m_spaceSphre.wait(0); //Clear the queue as space is available
+  return OK;
+}
+
+/*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
+{
+  if( !space() ) //If there is space left, no need to abort
+  {
+    m_spaceSphre.release(); //Force exiting the waiting state
+  }
+  return OK;
+}
+
+void USBSerialStream::setupWriteableISR(bool en)
+{
+  m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
+}
+
+void USBSerialStream::writeable() //Callback from m_serial when new space is available
+{
+  if(m_outBuf.isEmpty())
+  {
+    m_serialTxFifoEmpty = true;
+  }
+  else
+  {
+    m_serialTxFifoEmpty = false;
+    while(m_serial.writeable() && !m_outBuf.isEmpty())
+    {
+      uint8_t c;
+      m_outBuf.dequeue(&c);
+      m_serial.putc((char)c);
+    }
+    static volatile int i=0;
+    m_serial.writePacket(); //Start packet write
+  }
+  m_spaceSphre.release(); //Force exiting the waiting state
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/drv/serial/usb/USBSerialStream.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,77 @@
+/* USBSerialStream.h */
+/*
+Copyright (C) 2011 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef USBSERIALSTREAM_H_
+#define USBSERIALSTREAM_H_
+
+
+#include "core/fwk.h"
+
+#include "USB3GModule/IUSBHostSerial.h"
+#include "USB3GModule/IUSBHostSerialListener.h"
+
+#include "rtos.h"
+#include "core/MtxCircBuffer.h"
+
+/* Input Serial Stream for USB virtual serial ports interfaces
+This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
+*/
+#define CIRCBUF_SIZE 255
+class USBSerialStream : public IOStream, IUSBHostSerialListener
+{
+public:
+  USBSerialStream(IUSBHostSerial& serial);
+  /*virtual*/ ~USBSerialStream();
+
+  //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+  virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
+  virtual size_t available();
+  virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
+  virtual int abortRead(); //Abort current reading (or waiting) operation
+
+
+  //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
+  virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
+  virtual size_t space();
+  virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
+  virtual int abortWrite(); //Abort current writing (or waiting) operation
+
+private:
+  IUSBHostSerial& m_serial;
+  volatile bool m_serialTxFifoEmpty;
+
+  void setupReadableISR(bool en);
+  virtual void readable(); //Callback from m_serial when new data is available
+
+  Semaphore m_availableSphre; //Used for signalling
+
+  void setupWriteableISR(bool en);
+  virtual void writeable(); //Callback from m_serial when new space is available
+
+  Semaphore m_spaceSphre; //Used for signalling
+
+  MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
+  MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
+};
+
+#endif /* USBSERIALSTREAM_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/info/DongleDeviceInfo.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ * DongleDeviceInfo.h
+ *
+ *  Created on: 16 déc. 2011
+ *      Author: Donatien
+ */
+
+#ifndef DONGLEDEVICEINFO_H_
+#define DONGLEDEVICEINFO_H_
+
+#include "core/fwk.h"
+#include "drv/modemtransport/ModemTransport.h"
+
+class DongleDeviceInfo : protected ModemTransportUser
+{
+
+};
+
+#endif /* DONGLEDEVICEINFO_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ip/PPPIPInterface.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,262 @@
+/* PPPIPInterface.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 2 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "PPPIPInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+#include "rtos.h"
+
+#include "PPPIPInterface.h"
+
+extern "C" {
+#include "lwip/ip_addr.h"
+#include "lwip/inet.h"
+#include "netif/ppp/ppp.h"
+}
+
+#if NET_PPP
+
+PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
+{
+  m_linkStatusSphre.wait();
+}
+
+/*virtual*/ PPPIPInterface::~PPPIPInterface()
+{
+
+}
+
+/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
+{
+  DBG("Initializing LwIP");
+  LwIPInterface::init(); //Init LwIP, NOT including PPP
+  DBG("Initializing PPP");
+  pppInit();
+  DBG("Done");
+  return OK;
+}
+
+int PPPIPInterface::setup(const char* user, const char* pw)
+{
+  DBG("Configuring PPP authentication method");
+  pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
+  DBG("Done");
+  return OK;
+}
+
+/*virtual*/ int PPPIPInterface::connect()
+{
+  DBG("Trying to connect with PPP");
+  m_linkStatusSphre.wait(0);
+  if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
+  {
+    return NET_INVALID;
+  }
+  int ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
+  if(ret < 0)
+  {
+    switch(ret)
+    {
+    case PPPERR_OPEN:
+    default:
+      return NET_FULL; //All available resources are already used
+    }
+  }
+  m_pppd = ret; //PPP descriptor
+  m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
+  if(m_pppErrCode != PPPERR_NONE)
+  {
+    m_pppd = -1;
+  }
+  switch(m_pppErrCode)
+  {
+  case PPPERR_NONE: //Connected OK
+    return OK;
+  case PPPERR_CONNECT: //Connection lost
+    return NET_INTERRUPTED;
+  case PPPERR_AUTHFAIL: //Authentication failed
+    return NET_AUTH;
+  case PPPERR_PROTOCOL: //Protocol error
+    return NET_PROTOCOL;
+  default:
+    return NET_UNKNOWN;
+  }
+}
+
+/*virtual*/ int PPPIPInterface::disconnect()
+{
+  int ret = m_linkStatusSphre.wait(0);
+  if(ret > 0) //Already disconnected?
+  {
+    m_pppd = -1; //Discard PPP descriptor
+    switch(m_pppErrCode)
+      {
+      case PPPERR_CONNECT: //Connection terminated
+      case PPPERR_AUTHFAIL: //Authentication failed
+      case PPPERR_PROTOCOL: //Protocol error
+      case PPPERR_USER:
+        return OK;
+      default:
+        return NET_UNKNOWN;
+      }
+  }
+  else
+  {
+    if(m_pppd == -1)
+    {
+      return NET_INVALID;
+    }
+    pppClose(m_pppd);
+    do
+    {
+      m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
+      DBG("Received PPP err code %d", m_pppErrCode);
+    } while(m_pppErrCode != PPPERR_USER);
+    m_pppd = -1; //Discard PPP descriptor
+  }
+  return OK;
+}
+
+/*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
+{
+  PPPIPInterface* pIf = (PPPIPInterface*)ctx;
+  struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
+
+  switch(errCode)
+  {
+  case PPPERR_NONE:
+    WARN("Connected via PPP.");
+    DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
+    DBG("Netmask: %s", inet_ntoa(addrs->netmask));
+    DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
+    DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
+    DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
+    break;
+  case PPPERR_CONNECT: //Connection lost
+    WARN("Connection lost/terminated");
+    break;
+  case PPPERR_AUTHFAIL: //Authentication failed
+    WARN("Authentication failed");
+    break;
+  case PPPERR_PROTOCOL: //Protocol error
+    WARN("Protocol error");
+    break;
+  case PPPERR_USER:
+    WARN("Disconnected by user");
+    break;
+  default:
+    WARN("Unknown error (%d)", errCode);
+    break;
+  }
+
+  pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
+  pIf->m_pppErrCode = errCode;
+  pIf->m_linkStatusSphre.release();
+}
+
+//LwIP PPP implementation
+extern "C"
+{
+
+/**
+ * Writes to the serial device.
+ *
+ * @param fd serial device handle
+ * @param data pointer to data to send
+ * @param len length (in bytes) of data to send
+ * @return number of bytes actually sent
+ *
+ * @note This function will block until all data can be sent.
+ */
+u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
+{
+  DBG("sio_write");
+  PPPIPInterface* pIf = (PPPIPInterface*)fd;
+  int ret;
+  if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+  {
+    return 0;
+  }
+  ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
+  if(ret != OK)
+  {
+    return 0;
+  }
+  return len;
+}
+
+/**
+ * Reads from the serial device.
+ *
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
+ *
+ * @note This function will block until data can be received. The blocking
+ * can be cancelled by calling sio_read_abort().
+ */
+u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
+{
+  DBG("sio_read");
+  PPPIPInterface* pIf = (PPPIPInterface*)fd;
+  int ret;
+  size_t readLen;
+  if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+  {
+    WARN("EXIT NOT AVAIL");
+    return 0;
+  }
+  ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
+  if(ret != OK)
+  {
+    return 0;
+  }
+  DBG("ret");
+  return readLen;
+}
+
+/**
+ * Aborts a blocking sio_read() call.
+ *
+ * @param fd serial device handle
+ */
+void sio_read_abort(sio_fd_t fd)
+{
+  DBG("sio_read_abort");
+  PPPIPInterface* pIf = (PPPIPInterface*)fd;
+  if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
+  {
+    return;
+  }
+  pIf->m_pStream->abortRead();
+  DBG("ret");
+}
+
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ip/PPPIPInterface.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,67 @@
+/* PPPIPInterface.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef PPPIPINTERFACE_H_
+#define PPPIPINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "LwIPInterface.h"
+
+#include "lwip/sio.h"
+
+namespace rtos {
+class Semaphore;
+}
+using namespace rtos;
+
+/** Interface using PPP to connect to an IP-based network
+ *
+ */
+class PPPIPInterface : public LwIPInterface
+{
+public:
+	PPPIPInterface(IOStream* pStream);
+	virtual ~PPPIPInterface();
+
+	virtual int init(); //Init PPP-specific stuff, create the right bindings, etc
+	int setup(const char* user, const char* pw); //Setup authentication
+  virtual int connect();
+  virtual int disconnect();
+
+private:
+	static void linkStatusCb(void *ctx, int errCode, void *arg); //PPP link status
+	Semaphore m_linkStatusSphre;
+	int m_pppErrCode;
+
+	IOStream* m_pStream; //Serial stream
+	bool m_streamAvail;
+
+	int m_pppd;
+
+	friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
+	friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
+	friend void sio_read_abort(sio_fd_t fd);
+};
+
+#endif /* PPPIPINTERFACE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/sms/SMSInterface.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,390 @@
+/* SMSInterface.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 4
+#ifndef __MODULE__
+#define __MODULE__ "SMSInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "SMSInterface.h"
+
+#include <cstdio>
+
+#define DEFAULT_TIMEOUT 10000
+
+SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL), /*m_msgCount(0),*/
+m_msgRefListCount(0), m_needsUpdate(true), m_state(SMS_IDLE)
+{
+  m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
+}
+
+int SMSInterface::init()
+{
+  DBG("Set format");
+  //Set Text mode format
+  int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
+  if(ret != OK)
+  {
+    return NET_PROTOCOL;
+  }
+
+  DBG("Setup new messages indication");
+  //Setup new messages indication
+  ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
+  if(ret != OK)
+  {
+    return NET_PROTOCOL;
+  }
+
+  DBG("Try to fetch inbox");
+  m_inboxMtx.lock();
+  if( m_needsUpdate )
+  {
+    ret = updateInbox(); //Fetch existing messages references
+    if(ret)
+    {
+      m_inboxMtx.unlock();
+      return NET_PROTOCOL;
+    }
+  }
+  m_inboxMtx.unlock();
+
+  DBG("Initialization done");
+  return OK;
+}
+
+int SMSInterface::send(const char* number, const char* message)
+{
+  if( strlen(number) > 16 )
+  {
+    return NET_INVALID; //Number too long to match 3GPP spec
+  }
+
+  int ret;
+
+  //Prepare infos
+  m_state = SMS_SEND_CMD_SENT;
+  m_msg = (char*) message;
+
+  DBG("Send SM");
+  //Send command
+  char cmd[32];
+  std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
+  ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+
+  if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
+  {
+    WARN("ret %d, state %d", ret, m_state);
+    m_state = SMS_IDLE;
+    return NET_PROTOCOL;
+  }
+
+  DBG("SM sent");
+  m_state = SMS_IDLE;
+  return OK;
+}
+
+
+int SMSInterface::get(char* number, char* message, size_t maxLength)
+{
+  if( maxLength < 1  )
+  {
+    return NET_INVALID; //Buffer too short
+  }
+
+  int ret;
+
+  DBG("Get next message");
+  m_inboxMtx.lock();
+  if(m_msgRefListCount == 0 && m_needsUpdate)
+  {
+    ret = updateInbox();
+    if (ret)
+    {
+      m_inboxMtx.unlock();
+      return ret;
+    }
+  }
+
+  if(m_msgRefListCount == 0)
+  {
+    m_inboxMtx.unlock();
+    return NET_EMPTY; //No message to read
+  }
+
+  //Prepare infos
+  m_state = SMS_GET_CMD_SENT;
+  m_msisdn = (char*) number;
+  m_msg = (char*) message;
+  m_maxMsgLength = maxLength;
+
+  DBG("Get SMS");
+  //List command
+  char cmd[32];
+  std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
+  ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
+  if( ret != OK )
+  {
+    WARN("AT+CMGR returned %d", ret);
+    m_state = SMS_IDLE;
+    m_inboxMtx.unlock();
+    return NET_PROTOCOL;
+  }
+
+  if (m_state != SMS_CMD_PROCESSED)
+  {
+    m_state = SMS_IDLE;
+    m_inboxMtx.unlock();
+    return NET_EMPTY;
+  }
+
+  m_state = SMS_IDLE;
+
+  DBG("Deleting message");
+  //Delete message from outbox
+  std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
+  ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
+  if(ret != OK)
+  {
+    m_inboxMtx.unlock();
+    WARN("Could not delete message");
+  }
+
+  //Remove message from list
+  std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1);
+  m_msgRefListCount--;
+
+  m_inboxMtx.unlock();
+
+  return OK;
+}
+
+
+int SMSInterface::getCount(size_t* pCount)
+{
+  int ret;
+
+  m_inboxMtx.lock();
+  if( m_needsUpdate )
+  {
+    ret = updateInbox();
+    if(ret)
+    {
+      m_inboxMtx.unlock();
+      return NET_PROTOCOL;
+    }
+  }
+
+  *pCount = m_msgRefListCount;
+  m_inboxMtx.unlock();
+
+  return OK;
+}
+
+
+/*virtual*/ int SMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
+{
+  if(m_state == SMS_SEND_CMD_SENT)
+  {
+    if( std::sscanf(line, "+CMGS: %*d") == 0 )
+    {
+      DBG("SM sent");
+      m_state = SMS_CMD_PROCESSED;
+    }
+  }
+  else if(m_state == SMS_GET_CMD_SENT)
+  {
+    DBG("Header: %s", line);
+    if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
+    {
+      m_state = SMS_GET_HDR_RECEIVED;
+    }
+  }
+  else if(m_state == SMS_GET_HDR_RECEIVED)
+  {
+    DBG("Message: %s", line);
+    size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
+    std::memcpy( m_msg, line, cpyLen );
+    m_msg[cpyLen] = '\0';
+    m_state = SMS_CMD_PROCESSED;
+  }
+  else if(m_state == SMS_GET_COUNT_CMD_SENT)
+  {
+    DBG("Header: %s", line);
+    int msgRef;
+    if( std::sscanf(line, "+CMGL: %d", &msgRef) == 1 )
+    {
+      m_state = SMS_GET_COUNT_HDR_RECEIVED;
+      //Add message to list
+      if(m_msgRefListCount < MAX_SM)
+      {
+        m_msgRefList[m_msgRefListCount] = msgRef;
+      }
+      m_msgRefListCount++; //Always count message
+      DBG("m_msgRefListCount=%d",m_msgRefListCount);
+    }
+  }
+  else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
+  {
+    DBG("Message (debug only): %s", line); //For debug only
+    m_state = SMS_GET_COUNT_CMD_SENT;
+  }
+  return OK;
+}
+
+/*virtual*/ int SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
+{
+  if(m_state == SMS_SEND_CMD_SENT)
+  {
+    char* crPtr = strchr(m_msg, CR);
+    if(crPtr != NULL)
+    {
+      int crPos = crPtr - m_msg;
+      //Replace m_inputBuf[crPos] with null-terminating char
+      m_msg[crPos] = '\x0';
+
+      //If there is a CR char, split message there
+
+      //Do print the message
+      int ret = pInst->sendData(m_msg);
+      if(ret)
+      {
+        return ret;
+      }
+
+      char cr[2] = {CR, '\0'};
+      ret = pInst->sendData(cr);
+      if(ret)
+      {
+        return ret;
+      }
+
+      m_msg += crPos;
+
+      if(m_msg[0] == LF)
+      {
+        m_msg++; //Discard LF char as well
+      }
+
+      return NET_MOREINFO;
+    }
+    else
+    {
+      //Do print the message
+      pInst->sendData(m_msg);
+      return OK;
+    }
+  }
+
+  return OK;
+}
+
+/*virtual*/ bool SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
+{
+  DBG("AT code is %s", atCode);
+  if( strcmp("+CMTI", atCode) == 0 )
+  {
+    return true;
+  }
+
+  DBG("Not handled");
+  return false;
+}
+
+/*virtual*/ void SMSInterface::onDispatchStart()
+{
+
+
+}
+
+/*virtual*/ void SMSInterface::onDispatchStop()
+{
+
+}
+
+/*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt)
+{
+  if( strcmp("+CMTI", atCode) != 0 )
+  {
+    return; //Not supported
+  }
+
+  DBG("Unsollicited result code: %s - %s", atCode, evt);
+
+  //Get index
+  int msgRef;
+  if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 )
+  {
+    DBG("Adding message to list (ref %d)", msgRef);
+    m_inboxMtx.lock();
+    //Add message to list
+    if(m_msgRefListCount < MAX_SM)
+    {
+      m_msgRefList[m_msgRefListCount] = msgRef;
+    }
+    else
+    {
+      m_needsUpdate = true;
+    }
+    m_msgRefListCount++; //Always count message
+    m_inboxMtx.unlock();
+  }
+}
+
+int SMSInterface::updateInbox()
+{
+  //Get memory indexes of unread messages
+  m_state = SMS_GET_COUNT_CMD_SENT;
+
+  DBG("Updating inbox");
+  m_msgRefListCount = 0; //Reset list
+
+  int ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
+  if( ret != OK )
+  {
+    WARN("AT+CMGL returned %d", ret);
+    m_state = SMS_IDLE;
+    m_msgRefListCount = 0; //List could be invalid
+    m_needsUpdate = true;
+    return NET_PROTOCOL;
+  }
+
+  DBG("%d incoming messages in inbox", m_msgRefListCount);
+
+  if( m_msgRefListCount > MAX_SM )
+  {
+    m_needsUpdate = true;
+  }
+  else
+  {
+    m_needsUpdate = false;
+  }
+
+  m_state = SMS_IDLE;
+
+  return OK;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/sms/SMSInterface.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,105 @@
+/* SMSInterface.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef SMSINTERFACE_H_
+#define SMSINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "rtos.h"
+
+#include "drv/at/ATCommandsInterface.h"
+
+#define MAX_SM 8
+
+/** Component to use the Short Messages Service (SMS)
+ *
+ */
+class SMSInterface : protected IATCommandsProcessor, IATEventsHandler
+{
+public:
+  /** Create SMSInterface instance
+     @param pIf Pointer to the ATCommandsInterface instance to use
+   */
+  SMSInterface(ATCommandsInterface* pIf);
+
+  /** Initialize interface
+    Configure SMS commands & register for SMS-related unsolicited result codes
+   */
+  int init();
+
+  /** Send a SM
+     @param number The receiver's phone number
+     @param message The message to send
+     @return 0 on success, error code on failure
+   */
+  int send(const char* number, const char* message);
+
+
+  /** Receive a SM
+     @param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the space for the null-terminating char)
+     @param message Pointer to a buffer to store the the incoming message
+     @param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
+     @return 0 on success, error code on failure
+   */
+  int get(char* number, char* message, size_t maxLength);
+
+
+  /** Get the number of SMs in the incoming box
+     @param pCount pointer to store the number of unprocessed SMs on
+     @return 0 on success, error code on failure
+   */
+  int getCount(size_t* pCount);
+
+protected:
+  //IATCommandsProcessor
+  virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
+  virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
+
+  //IATEventsHandler
+  virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
+  virtual void onDispatchStart();
+  virtual void onDispatchStop();
+  virtual void onEvent(const char* atCode, const char* evt);
+
+  //Updates messages count/references
+  int updateInbox();
+
+private:
+  ATCommandsInterface* m_pIf;
+
+  //Current message
+  char* m_msg;
+  size_t m_maxMsgLength;
+  char* m_msisdn;
+
+  //Messages list
+  int m_msgRefList[MAX_SM];
+  size_t m_msgRefListCount;
+  bool m_needsUpdate;
+  Mutex m_inboxMtx; //To protect concurrent accesses btw the user's thread and the AT thread
+
+  enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_GET_COUNT_HDR_RECEIVED, SMS_CMD_PROCESSED } m_state;
+};
+
+#endif /* SMSINTERFACE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ussd/USSDInterface.cpp	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,152 @@
+/* USSDInterface.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 4
+#ifndef __MODULE__
+#define __MODULE__ "USSDInterface.cpp"
+#endif
+
+#include "core/fwk.h"
+
+#include "USSDInterface.h"
+
+#include <cstdio>
+
+#define DEFAULT_TIMEOUT 10000
+#define USSD_TIMEOUT 15000
+
+USSDInterface::USSDInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_responseMtx(), m_responseSphre(1), m_result(NULL), m_maxResultLength(0)
+{
+  m_responseSphre.wait(0); //Take ownership of the semaphore
+  m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
+}
+
+int USSDInterface::init()
+{
+  DBG("Initialization done");
+  return OK;
+}
+
+int USSDInterface::send(const char* command, char* result, size_t maxLength)
+{
+  if (strlen(command) > 20) //Prevent buffer overflow
+  {
+    return NET_TOOSMALL;
+  }
+
+  m_responseMtx.lock();
+  m_result = result;
+  m_maxResultLength = maxLength;
+  m_responseMtx.unlock();
+
+  m_responseSphre.wait(0); //Make sure there is not a pending result that needs to be discarded
+
+  DBG("Send USSD command & register for unsolicited result codes");
+  //Send USSD command to the network
+  char cmd[32];
+  std::sprintf(cmd, "AT+CUSD=1,\"%s\"", command);
+  int ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
+  if( ret != OK )
+  {
+    return NET_PROTOCOL;
+  }
+
+  //Now wait for response
+  int res = m_responseSphre.wait(USSD_TIMEOUT);
+
+  //Reset data
+  m_responseMtx.lock();
+  m_result = NULL;
+  m_maxResultLength = 0;
+  m_responseMtx.unlock();
+
+  if(res <= 0)
+  {
+    DBG("No result received");
+    ret = m_pIf->executeSimple("AT+CUSD=2", NULL, DEFAULT_TIMEOUT); //Cancel command
+    if( ret != OK )
+    {
+      return NET_PROTOCOL;
+    }
+    return NET_TIMEOUT;
+  }
+
+  DBG("Result received: %s", result);
+
+  return OK;
+
+}
+
+/*virtual*/ bool USSDInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
+{
+  DBG("AT code is %s", atCode);
+  if( strcmp("+CUSD", atCode) == 0 )
+  {
+    return true;
+  }
+
+  DBG("Not handled");
+  return false;
+}
+
+/*virtual*/ void USSDInterface::onDispatchStart()
+{
+
+
+}
+
+/*virtual*/ void USSDInterface::onDispatchStop()
+{
+
+}
+
+/*virtual*/ void USSDInterface::onEvent(const char* atCode, const char* evt)
+{
+  if( strcmp("+CUSD", atCode) != 0 )
+  {
+    return; //Not supported
+  }
+
+  char* pStart = (char*) strchr(evt,'\"');
+  if(pStart==NULL)
+  {
+    return; //Invalid/incomplete response
+  }
+  pStart++; //Point to first char of response
+  char* pEnd = (char*) strchr(pStart,'\"');
+  if(pEnd==NULL)
+  {
+    return; //Invalid/incomplete response
+  }
+  m_responseMtx.lock();
+  if(m_maxResultLength == 0) //No pending command
+  {
+    m_responseMtx.unlock();
+    return;
+  }
+  size_t cpyLen = MIN( pEnd - pStart, m_maxResultLength - 1 );
+  memcpy(m_result, pStart, cpyLen);
+  m_result[cpyLen] = '\0';
+  m_responseMtx.unlock();
+  m_responseSphre.release(); //Signal user thread that response is ready
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/if/ussd/USSDInterface.h	Thu May 24 16:40:40 2012 +0000
@@ -0,0 +1,76 @@
+/* USSDInterface.h */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef USSDINTERFACE_H_
+#define USSDINTERFACE_H_
+
+#include "core/fwk.h"
+
+#include "rtos.h"
+
+#include "drv/at/ATCommandsInterface.h"
+
+/** Component to send/receive Unstructured Supplementary Service Data (USSD)
+ *
+ */
+class USSDInterface : protected IATEventsHandler
+{
+public:
+  /** Create USSDInterface instance
+     @param pIf Pointer to the ATCommandsInterface instance to use
+   */
+  USSDInterface(ATCommandsInterface* pIf);
+
+  /** Initialize interface
+   Configure USSD commands & register for USSD-related unsolicited result codes
+  */
+  int init();
+
+  /** Send a USSD command & wait for its result
+    @param command The command to send
+    @param result Buffer in which to store the result
+    @param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
+    @return 0 on success, error code on failure
+  */
+  int send(const char* command, char* result, size_t maxLength);
+
+protected:
+  //IATEventsHandler
+  virtual bool isATCodeHandled(const char* atCode); //Is this AT code handled
+  virtual void onDispatchStart();
+  virtual void onDispatchStop();
+  virtual void onEvent(const char* atCode, const char* evt);
+
+private:
+  ATCommandsInterface* m_pIf;
+  Mutex m_responseMtx; //To protect concurrent accesses btw the user's thread and the AT thread
+  Semaphore m_responseSphre;
+
+  //Result
+  char* m_result;
+  size_t m_maxResultLength;
+
+};
+
+
+#endif /* USSDINTERFACE_H_ */