USB Host Library for Sprint Dongles

Dependencies:   Socket USBHostWANDongleSprint lwip-sys lwip

Dependents:   SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more

Fork of SprintUSBModem_bleedingedge by Donatien Garnier

Files at this revision

API Documentation at this revision

Comitter:
donatien
Date:
Tue Oct 30 12:40:18 2012 +0000
Parent:
7:098c2adcc17a
Child:
11:7e1056a4ca50
Commit message:
Extensive support for unsolicited result codes

Changed in this revision

at/ATCommandsInterface.cpp Show annotated file Show diff for this revision Revisions of this file
at/ATCommandsInterface.h Show annotated file Show diff for this revision Revisions of this file
--- a/at/ATCommandsInterface.cpp	Wed Oct 24 15:14:24 2012 +0000
+++ b/at/ATCommandsInterface.cpp	Tue Oct 30 12:40:18 2012 +0000
@@ -17,7 +17,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#define __DEBUG__  2//ERR+WARN
+#define __DEBUG__  2 //ERR+WARN
 #ifndef __MODULE__
 #define __MODULE__ "ATCommandsInterface.cpp"
 #endif
@@ -34,7 +34,7 @@
 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()
+   m_eventsMgmtMtx(), m_eventsProcessingMtx()
 {
   memset(m_eventsHandlers, 0, MAX_AT_EVENTS_HANDLERS * sizeof(IATEventsHandler*));
 
@@ -57,32 +57,25 @@
 
   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
+//Initialize AT link & start events processing
 int ATCommandsInterface::init()
 {
   DBG("Sending ATZ E1 V1");
+  
+  //Lock transaction mutex
+  m_transactionMtx.lock();
+  
   //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
+    err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
     if(err && tries)
     {
       WARN("No response, trying again");
@@ -92,10 +85,17 @@
   if( err )
   {
     ERR("Sending ATZ E1 V1 returned with err code %d", err);
+    m_transactionMtx.unlock();
     return err;
   }
+  
+  //Enable events handling and execute events enabling commands
+  enableEvents();
 
   DBG("AT interface initialized");
+  
+  //Unlock transaction mutex
+  m_transactionMtx.unlock();
 
   return OK;
 }
@@ -124,16 +124,8 @@
   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();
+  //Disable events handling and advertize this to the events handlers
+  disableEvents();
 
   DBG("AT interface closed");
   return OK;
@@ -151,7 +143,6 @@
 
 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!");
@@ -160,6 +151,60 @@
 
   //Lock transaction mutex
   m_transactionMtx.lock();
+  
+  disableEvents(); //Disable unsollicited result codes
+  int ret = executeInternal(command, pProcessor, pResult, timeout);
+  enableEvents(); //Re-enable unsollicited result codes whatever the result of the command is
+  
+  //Unlock transaction mutex
+  m_transactionMtx.unlock();
+  
+  return ret;
+}
+
+int ATCommandsInterface::registerEventsHandler(IATEventsHandler* pHdlr)
+{
+  m_eventsMgmtMtx.lock();
+  m_eventsProcessingMtx.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_eventsProcessingMtx.unlock();
+      m_eventsMgmtMtx.unlock();
+      return OK;
+    }
+  }
+  m_eventsProcessingMtx.unlock();
+  m_eventsMgmtMtx.unlock();
+  return NET_OOM; //No room left
+}
+
+int ATCommandsInterface::deregisterEventsHandler(IATEventsHandler* pHdlr)
+{
+  m_eventsMgmtMtx.lock();
+  m_eventsProcessingMtx.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_eventsProcessingMtx.unlock();
+      m_eventsMgmtMtx.unlock();
+      return OK;
+    }
+  }
+  m_eventsProcessingMtx.unlock();
+  m_eventsMgmtMtx.unlock();
+  return NET_NOTFOUND; //Not found
+}
+
+//Private methods
+
+int ATCommandsInterface::executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout/*=1000*/)
+{
+  DBG("Executing command %s", command);
 
   //Discard previous result if it arrived too late
   osEvent evt = m_AT2Env.get(0);
@@ -181,8 +226,6 @@
     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
@@ -209,7 +252,6 @@
     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);
@@ -229,45 +271,9 @@
 
   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;
@@ -597,7 +603,7 @@
       }
     }
     //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();
+    m_eventsProcessingMtx.lock();
     //Go through the list
     for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
     {
@@ -610,7 +616,7 @@
         }
       }
     }
-    m_eventsMtx.unlock();
+    m_eventsProcessingMtx.unlock();
     if(found)
     {
       return OK;
@@ -712,6 +718,54 @@
   return OK;
 }
 
+//This will be called on initialization & after the execution of a command
+void ATCommandsInterface::enableEvents()
+{
+  //Advertize this to events handlers
+  m_eventsMgmtMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+  {
+    if( m_eventsHandlers[i] != NULL )
+    {
+      m_eventsHandlers[i]->onDispatchStart();
+      //Enable this kind of events
+      if(m_eventsHandlers[i]->getEventsEnableCommand() != NULL)
+      {
+        int ret = executeInternal(m_eventsHandlers[i]->getEventsEnableCommand(), this, NULL); //Execute enable command
+        if(ret)
+        {
+          WARN("Events enabling command failed");
+        }
+      }
+    }
+  }
+  m_eventsMgmtMtx.unlock();
+}
+
+//This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results
+void ATCommandsInterface::disableEvents()
+{
+  //Advertize this to events handlers
+  m_eventsMgmtMtx.lock();
+  for(int i = 0; i < MAX_AT_EVENTS_HANDLERS; i++) //Find a free slot
+  {
+    if( m_eventsHandlers[i] != NULL )
+    {
+      m_eventsHandlers[i]->onDispatchStart();
+      //Disable this kind of events
+      if(m_eventsHandlers[i]->getEventsDisableCommand() != NULL)
+      {
+        int ret = executeInternal(m_eventsHandlers[i]->getEventsDisableCommand(), this, NULL); //Execute disable command
+        if(ret)
+        {
+          WARN("Events disabling command failed");
+        }
+      }
+    }
+  }
+  m_eventsMgmtMtx.unlock();
+}
+
 //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)
@@ -743,7 +797,8 @@
     if( memcmp(m_inputBuf, data + dataPos, readLen) != 0 )
     {
       //Echo does not match output
-      WARN("Echo does not match output");
+      m_inputBuf[readLen] = '\0';
+      WARN("Echo does not match output, got '%s' instead", m_inputBuf);
       m_inputPos = 0; //Reset input buffer state
       m_inputBuf[0] = '\0'; //Always have a null-terminating char at start of buffer
       return NET_DIFF;
@@ -809,10 +864,10 @@
     m_inputPos = 0; //Clear input buffer
     do
     {
+      DBG("Trying to send a pending command");
+      trySendCommand(); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command
       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");
--- a/at/ATCommandsInterface.h	Wed Oct 24 15:14:24 2012 +0000
+++ b/at/ATCommandsInterface.h	Tue Oct 30 12:40:18 2012 +0000
@@ -36,6 +36,8 @@
   virtual bool isATCodeHandled(const char* atCode) = 0; //Is this AT code handled
   virtual void onDispatchStart() = 0;
   virtual void onDispatchStop() = 0;
+  virtual char* getEventsEnableCommand() = 0;
+  virtual char* getEventsDisableCommand() = 0;
   virtual void onEvent(const char* atCode, const char* evt) = 0;
   friend class ATCommandsInterface;
 };
@@ -91,6 +93,7 @@
 
   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);
 
@@ -100,10 +103,15 @@
 
   static void staticCallback(void const* p);
 private:
+  int executeInternal(const char* command, IATCommandsProcessor* pProcessor, ATResult* pResult, uint32_t timeout=1000);
+  
   int tryReadLine();
   int trySendCommand();
   int processReadLine();
   int processEntryPrompt();
+  
+  void enableEvents();
+  void disableEvents();
 
   int ATResultToReturnCode(ATResult result); //Helper
 
@@ -124,20 +132,22 @@
 
   enum { IDLE, COMMAND_SENT, READING_RESULT, ABORTED } m_transactionState;
 
-  char m_inputBuf[AT_INPUT_BUF_SIZE];
-  int m_inputPos;
+  char m_inputBuf[AT_INPUT_BUF_SIZE]; // Stores characters received from the modem.
+  int m_inputPos; // Current position of fill pointer in the input buffer.
 
   Mutex m_transactionMtx;
 
-  Mail<int,1> m_env2AT;
-  Mail<int,1> m_AT2Env;
+  // These are RTOS queues, concurrent access protected. In this case both only contain an integer.
+  Mail<int,1> m_env2AT; // used by calling function to inform processing thread of events
+  Mail<int,1> m_AT2Env; // used by processing thread to inform calling function of events
 
-  IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS];
+  IATEventsHandler* m_eventsHandlers[MAX_AT_EVENTS_HANDLERS]; // all registered events handlers
 
   Mutex m_processingMtx;
   Thread m_processingThread;
 
-  Mutex m_eventsMtx;
+  Mutex m_eventsMgmtMtx; //Lock events use within the calling thread
+  Mutex m_eventsProcessingMtx; //Lock events use within the processing thread
 };
 
 #endif /* ATCOMMANDSINTERFACE_H_ */