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:
Wed Oct 10 14:44:11 2012 +0000
Parent:
5:a2a739fc2bed
Child:
7:098c2adcc17a
Commit message:
SMS Support

Changed in this revision

sms/SMSInterface.cpp Show annotated file Show diff for this revision Revisions of this file
sms/SMSInterface.h Show annotated file Show diff for this revision Revisions of this file
--- a/sms/SMSInterface.cpp	Wed Oct 10 08:29:50 2012 +0000
+++ b/sms/SMSInterface.cpp	Wed Oct 10 14:44:11 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
+#define __DEBUG__ 0
 #ifndef __MODULE__
 #define __MODULE__ "SMSInterface.cpp"
 #endif
@@ -32,44 +32,19 @@
 
 SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
 {
-  m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
 }
 
 int SMSInterface::init()
 {
-  m_msgRefListCount = 0;
-  m_needsUpdate = true;
   m_state = SMS_IDLE;
 
-  DBG("Set format");
-  //Set Text mode format
-  int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
-  if(ret != OK)
+  DBG("Get number of messages in the different inboxes");
+  int ret = updateInbox();
+  if(ret)
   {
     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;
 }
@@ -78,30 +53,63 @@
 {
   if( strlen(number) > 16 )
   {
-    return NET_INVALID; //Number too long to match 3GPP spec
+    return NET_INVALID; //Number too long
   }
 
   int ret;
 
   //Prepare infos
   m_state = SMS_SEND_CMD_SENT;
-  m_msg = (char*) message;
+  
+  bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
 
   DBG("Send SM");
   //Send command
-  char cmd[32];
-  std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
+  char cmd[32+strlen(message)];
+  std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
 
-  if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
+  if(ret != OK)
   {
-    WARN("ret %d, state %d", ret, m_state);
+    WARN("ret %d", ret);
     m_state = SMS_IDLE;
     return NET_PROTOCOL;
   }
 
-  DBG("SM sent");
-  m_state = SMS_IDLE;
+  DBG("Check status");
+  m_txState = SMS_PENDING;
+  
+  int tries = 10;
+  while(tries--)
+  {
+    m_state = SMS_GET_TX_STATUS_CMD_SENT;
+    ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
+    if(ret)
+    {
+      m_state = SMS_IDLE;
+      return ret;
+    }
+    m_state = SMS_IDLE;
+    if(m_txState == SMS_PENDING) //Wait more
+    {
+      Thread::wait(1000);
+      continue;
+    }
+    else if(m_txState == SMS_FAILED)
+    {
+      ERR("The modem could not send the SM");
+      return NET_CONN; //Probably a conenction issue, the user can retry
+    }
+    else
+    {
+      break;
+    }
+  }
+  if(!tries)
+  {
+    ERR("The is still trying to send the SM");
+    return NET_TIMEOUT;
+  }
   return OK;
 }
 
@@ -116,24 +124,35 @@
   int ret;
 
   DBG("Get next message");
-  m_inboxMtx.lock();
-  if(m_msgRefListCount == 0 && m_needsUpdate)
+  if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
   {
     DBG("Message list count is 0 and needs updating. Running updateInbox.");
     ret = updateInbox();
-    
     if (ret)
     {
-      m_inboxMtx.unlock();
       return ret;
     }
   }
 
-  if(m_msgRefListCount == 0)
+  if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
+  {
+    DBG("Message list count is 0");
+    return NET_EMPTY; //No message to read
+  }
+  
+  //Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
+  int index;
+  if(m_msgInListsCount[2])
   {
-    m_inboxMtx.unlock();
-    DBG("Message list count is 0, I think it's empty and returning.");
-    return NET_EMPTY; //No message to read
+    index = 3;
+  }
+  else if(m_msgInListsCount[0])
+  {
+    index = 1;
+  }
+  else //if(m_msgInListsCount[1])
+  {
+    index = 2;
   }
 
   //Prepare infos
@@ -141,46 +160,65 @@
   m_msisdn = (char*) number;
   m_msg = (char*) message;
   m_maxMsgLength = maxLength;
+  m_headersToRead = 3;
+  
+  m_msisdn[0] = '\0';
 
   DBG("Get SMS");
-  //List command
+  //Read command
   char cmd[32];
-  std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
+  std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
   if( ret != OK )
   {
-    WARN("AT+CMGR returned %d", ret);
+    WARN("AT!GSMS returned %d", ret);
     m_state = SMS_IDLE;
-    m_inboxMtx.unlock();
     return NET_PROTOCOL;
   }
-
-  if (m_state != SMS_CMD_PROCESSED)
+  
+  //If message is not read, it will be put at the end of the read list
+  int item;
+  if( index != 3 )
   {
-    WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
+    //Decrement count in relevant list
+    m_msgInListsCount[index-1]--;  
+    //Increment count in read list
+    m_msgInListsCount[3-1]++;  
+    item = m_msgInListsCount[3-1];
+    //Normally item should be equal to 1 as we'd have read any older messages first
+    if( item != 1 )
+    {
+      WARN("Still some older messages pending in the read inbox");
+    }
   }
-
-  DBG("Deleting message from index number: %d", m_msgRefList[0] );
-  //Delete message from outbox
-  std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
+  else
+  {
+    //The item is still the oldest one
+    item = 1;
+  }
+  
+  DBG("Deleting message");
+  //Delete message from inbox
+  std::sprintf(cmd, "AT!DSMS=3"/*%d", item*/); //FIXME why doesn't that works when specifying the index??
   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
   if(ret != OK)
   {
     ERR("Could not delete message");
   }
-  //Remove message from list
-  std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1);
-  m_msgRefListCount--;
+  else
+  {
+    //Now we can decrease the number of read messages
+    m_msgInListsCount[3-1]--; 
+  }
   
   if (m_state != SMS_CMD_PROCESSED)
   {
+    WARN("Message could not be retrieved properly");
     m_state = SMS_IDLE;
-    m_inboxMtx.unlock();
     return NET_EMPTY;
   }
   
   m_state = SMS_IDLE;
-  m_inboxMtx.unlock();
 
   return OK;
 }
@@ -188,21 +226,13 @@
 
 int SMSInterface::getCount(size_t* pCount)
 {
-  int ret;
-
-  m_inboxMtx.lock();
-  if( m_needsUpdate )
+  int ret = updateInbox();
+  if(ret)
   {
-    ret = updateInbox();
-    if(ret)
-    {
-      m_inboxMtx.unlock();
       return NET_PROTOCOL;
-    }
   }
 
-  *pCount = m_msgRefListCount;
-  m_inboxMtx.unlock();
+  *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
 
   return OK;
 }
@@ -212,18 +242,52 @@
 {
   if(m_state == SMS_SEND_CMD_SENT)
   {
-    if( std::sscanf(line, "+CMGS: %*d") == 0 )
+    DBG("SMS Send: %s", line);
+  }
+  else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
+  {
+    if(!strcmp(line, "sent"))
+    {
+      m_txState = SMS_SENT;
+      m_state = SMS_CMD_PROCESSED;
+    }
+    else if(!strcmp(line, "failed"))
     {
-      DBG("SM sent");
+      m_txState = SMS_FAILED;
+      m_state = SMS_CMD_PROCESSED;
+    }
+    else if(!strcmp(line, "none"))
+    {
+      m_txState = SMS_NONE;
+      m_state = SMS_CMD_PROCESSED;
+    }
+    else if(!strcmp(line, "pending"))
+    {
+      m_txState = SMS_PENDING;
       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
+    
+    if(m_msisdn[0]=='\0')
     {
-      m_state = SMS_GET_HDR_RECEIVED;
+      sscanf(line, "From: %16s", m_msisdn);
+    }
+    
+    m_headersToRead--;
+    
+    if(m_headersToRead==0) //End of headers
+    {
+      if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
+      {
+        m_state = SMS_GET_HDR_RECEIVED;
+      }
+      else
+      {
+        m_state = SMS_IDLE; //Error, signal it
+      }
     }
   }
   else if(m_state == SMS_GET_HDR_RECEIVED)
@@ -236,175 +300,48 @@
   }
   else if(m_state == SMS_GET_COUNT_CMD_SENT)
   {
-    DBG("Header: %s", line);
-    int msgRef;
-    if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages 
+    DBG("Inbox: %s", line);
+    int index;
+    size_t count;
+    if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
     {
-      m_state = SMS_GET_COUNT_HDR_RECEIVED;
-      //Add message to list
-      if(m_msgRefListCount < MAX_SM)
+      if((index > 0) && (index <=4))
       {
-        m_msgRefList[m_msgRefListCount] = msgRef;
+        m_msgInListsCount[index-1] = count;
       }
-      m_msgRefListCount++; //Always count message
-      DBG("m_msgRefListCount=%d",m_msgRefListCount);
+      if(index == 4)
+      {
+        m_state = SMS_CMD_PROCESSED;
+      }
     }
   }
-  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';
+  return OK;
+}
+
 
-      //If there is a CR char, split message there
-
-      //Do print the message
-      int ret = pInst->sendData(m_msg);
-      if(ret)
-      {
-        return ret;
-      }
+int SMSInterface::updateInbox()
+{
+  //Get number of unread/read messages
 
-      char cr[2] = {CR, '\0'};
-      ret = pInst->sendData(cr);
-      if(ret)
-      {
-        return ret;
-      }
-
-      m_msg += crPos;
+  DBG("Updating inbox");
+  m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
 
-      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;
-    }
+  //Get counts
+  m_state = SMS_GET_COUNT_CMD_SENT;
+  int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
+  if( ret != OK )
+  {
+    WARN("AT!CNTSMS returned %d", ret);
+    m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
+    m_state = SMS_IDLE;
+    return NET_PROTOCOL;
   }
 
   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);
-    if(m_inboxMtx.trylock())
-    {
-      //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();
-    }
-    else
-    {
-      WARN("Could not get lock");
-      m_needsUpdate = true;
-    }
-  }
-}
-
-int SMSInterface::updateInbox()
-{
-  //Get memory indexes of unread messages
-
-  DBG("Updating inbox");
-  m_msgRefListCount = 0; //Reset list
-  m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
-
-  //First list the "REC READ" messages that were not processed in the previous session
-  m_state = SMS_GET_COUNT_CMD_SENT;
-  int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", 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;
-  }
-  
-  //Now list the "REC UNREAD" messages that were received by the modem since
-  m_state = SMS_GET_COUNT_CMD_SENT;
-  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;
-  }
-
-  m_state = SMS_IDLE;
-
-  return OK;
-}
-
--- a/sms/SMSInterface.h	Wed Oct 10 08:29:50 2012 +0000
+++ b/sms/SMSInterface.h	Wed Oct 10 14:44:11 2012 +0000
@@ -31,7 +31,7 @@
 /** Component to use the Short Messages Service (SMS)
  *
  */
-class SMSInterface : protected IATCommandsProcessor, IATEventsHandler
+class SMSInterface : protected IATCommandsProcessor
 {
 public:
   /** Create SMSInterface instance
@@ -72,14 +72,7 @@
   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();
+  int updateInbox(); //Update messages count in the different inboxes
 
 private:
   ATCommandsInterface* m_pIf;
@@ -90,12 +83,12 @@
   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;
+  size_t m_msgInListsCount[4]; //4 lists
+  
+  size_t m_headersToRead;
+  
+  enum { SMS_NONE, SMS_SENT, SMS_PENDING, SMS_FAILED } m_txState;
+  enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_TX_STATUS_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_CMD_PROCESSED } m_state;
 };
 
 #endif /* SMSINTERFACE_H_ */