Base library for cellular modem implementations

Dependencies:   Socket lwip-sys lwip

Dependents:   CellularUSBModem CellularUSBModem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CDMASMSInterface.cpp Source File

CDMASMSInterface.cpp

00001 /* CDMASMSInterface.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 #define __DEBUG__ 0
00021 #ifndef __MODULE__
00022 #define __MODULE__ "CDMASMSInterface.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 
00027 #include "CDMASMSInterface.h"
00028 
00029 #include <cstdio>
00030 #include <cstring>
00031 
00032 using std::sscanf;
00033 
00034 #define DEFAULT_TIMEOUT 10000
00035 
00036 CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
00037 {
00038 }
00039 
00040 int CDMASMSInterface::init()
00041 {
00042   m_state = SMS_IDLE;
00043 
00044   DBG("Get number of messages in the different inboxes");
00045   int ret = updateInbox();
00046   if(ret)
00047   {
00048     return NET_PROTOCOL;
00049   }
00050   
00051   DBG("Initialization done");
00052   return OK;
00053 }
00054 
00055 int CDMASMSInterface::send(const char* number, const char* message)
00056 {
00057   if( strlen(number) > 16 )
00058   {
00059     return NET_INVALID; //Number too long
00060   }
00061 
00062   int ret;
00063 
00064   //Prepare infos
00065   m_state = SMS_SEND_CMD_SENT;
00066   
00067   bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
00068 
00069   DBG("Send SM");
00070   //Send command
00071   char cmd[32+strlen(message)];
00072   std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
00073   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00074 
00075   if(ret != OK)
00076   {
00077     WARN("ret %d", ret);
00078     m_state = SMS_IDLE;
00079     return NET_PROTOCOL;
00080   }
00081 
00082   DBG("Check status");
00083   m_txState = SMS_PENDING;
00084   
00085   int tries = 10;
00086   while(tries--)
00087   {
00088     m_state = SMS_GET_TX_STATUS_CMD_SENT;
00089     ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
00090     if(ret)
00091     {
00092       m_state = SMS_IDLE;
00093       return ret;
00094     }
00095     m_state = SMS_IDLE;
00096     if(m_txState == SMS_PENDING) //Wait more
00097     {
00098       Thread::wait(1000);
00099       continue;
00100     }
00101     else if(m_txState == SMS_FAILED)
00102     {
00103       ERR("The modem could not send the SM");
00104       return NET_CONN; //Probably a conenction issue, the user can retry
00105     }
00106     else
00107     {
00108       break;
00109     }
00110   }
00111   if(!tries)
00112   {
00113     ERR("The is still trying to send the SM");
00114     return NET_TIMEOUT;
00115   }
00116   return OK;
00117 }
00118 
00119 
00120 int CDMASMSInterface::get(char* number, char* message, size_t maxLength)
00121 {
00122   if( maxLength < 1  )
00123   {
00124     return NET_INVALID; //Buffer too short
00125   }
00126 
00127   int ret;
00128 
00129   DBG("Get next message");
00130   if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
00131   {
00132     DBG("Message list count is 0 and needs updating. Running updateInbox.");
00133     ret = updateInbox();
00134     if (ret)
00135     {
00136       return ret;
00137     }
00138   }
00139 
00140   if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
00141   {
00142     DBG("Message list count is 0");
00143     return NET_EMPTY; //No message to read
00144   }
00145   
00146   //Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
00147   int index;
00148   if(m_msgInListsCount[2])
00149   {
00150     index = 3;
00151   }
00152   else if(m_msgInListsCount[0])
00153   {
00154     index = 1;
00155   }
00156   else //if(m_msgInListsCount[1])
00157   {
00158     index = 2;
00159   }
00160 
00161   //Prepare infos
00162   m_state = SMS_GET_CMD_SENT;
00163   m_msisdn = (char*) number;
00164   m_msg = (char*) message;
00165   m_maxMsgLength = maxLength;
00166   m_headersToRead = 3;
00167   
00168   m_msisdn[0] = '\0';
00169 
00170   DBG("Get SMS");
00171   //Read command
00172   char cmd[32];
00173   std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
00174   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00175   if( ret != OK )
00176   {
00177     WARN("AT!GSMS returned %d", ret);
00178     m_state = SMS_IDLE;
00179     return NET_PROTOCOL;
00180   }
00181   
00182   //If message is not read, it will be put at the end of the read list
00183   int item;
00184   if( index != 3 )
00185   {
00186     //Decrement count in relevant list
00187     m_msgInListsCount[index-1]--;  
00188     //Increment count in read list
00189     m_msgInListsCount[3-1]++;  
00190     item = m_msgInListsCount[3-1];
00191     //Normally item should be equal to 1 as we'd have read any older messages first
00192     if( item != 1 )
00193     {
00194       WARN("Still some older messages pending in the read inbox");
00195     }
00196   }
00197   else
00198   {
00199     //The item is still the oldest one
00200     item = 1;
00201   }
00202   
00203   DBG("Deleting message");
00204   //Delete message from inbox
00205   std::sprintf(cmd, "AT!DSMS=3"/*,%d", item*/); //FIXME why doesn't that work when specifying the index??
00206   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
00207   if(ret != OK)
00208   {
00209     ERR("Could not delete message");
00210   }
00211   else
00212   {
00213     //Now we can decrease the number of read messages
00214     m_msgInListsCount[3-1]--; 
00215   }
00216   
00217   if (m_state != SMS_CMD_PROCESSED)
00218   {
00219     WARN("Message could not be retrieved properly");
00220     m_state = SMS_IDLE;
00221     return NET_EMPTY;
00222   }
00223   
00224   m_state = SMS_IDLE;
00225 
00226   return OK;
00227 }
00228 
00229 
00230 int CDMASMSInterface::getCount(size_t* pCount)
00231 {
00232   int ret = updateInbox();
00233   if(ret)
00234   {
00235       return NET_PROTOCOL;
00236   }
00237 
00238   *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
00239 
00240   return OK;
00241 }
00242 
00243 
00244 /*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00245 {
00246   if(m_state == SMS_SEND_CMD_SENT)
00247   {
00248     DBG("SMS Send: %s", line);
00249   }
00250   else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
00251   {
00252     if(!strcmp(line, "sent"))
00253     {
00254       m_txState = SMS_SENT;
00255       m_state = SMS_CMD_PROCESSED;
00256     }
00257     else if(!strcmp(line, "failed"))
00258     {
00259       m_txState = SMS_FAILED;
00260       m_state = SMS_CMD_PROCESSED;
00261     }
00262     else if(!strcmp(line, "none"))
00263     {
00264       m_txState = SMS_NONE;
00265       m_state = SMS_CMD_PROCESSED;
00266     }
00267     else if(!strcmp(line, "pending"))
00268     {
00269       m_txState = SMS_PENDING;
00270       m_state = SMS_CMD_PROCESSED;
00271     }
00272   }
00273   else if(m_state == SMS_GET_CMD_SENT)
00274   {
00275     DBG("Header: %s", line);
00276     
00277     if(m_msisdn[0]=='\0')
00278     {
00279       sscanf(line, "From: %16s", m_msisdn);
00280     }
00281     
00282     m_headersToRead--;
00283     
00284     if(m_headersToRead==0) //End of headers
00285     {
00286       if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
00287       {
00288         m_state = SMS_GET_HDR_RECEIVED;
00289       }
00290       else
00291       {
00292         m_state = SMS_IDLE; //Error, signal it
00293       }
00294     }
00295   }
00296   else if(m_state == SMS_GET_HDR_RECEIVED)
00297   {
00298     DBG("Message: %s", line);
00299     size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
00300     std::memcpy( m_msg, line, cpyLen );
00301     m_msg[cpyLen] = '\0';
00302     m_state = SMS_CMD_PROCESSED;
00303   }
00304   else if(m_state == SMS_GET_COUNT_CMD_SENT)
00305   {
00306     DBG("Inbox: %s", line);
00307     int index;
00308     size_t count;
00309     if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
00310     {
00311       if((index > 0) && (index <=4))
00312       {
00313         m_msgInListsCount[index-1] = count;
00314       }
00315       if(index == 4)
00316       {
00317         m_state = SMS_CMD_PROCESSED;
00318       }
00319     }
00320   }
00321   return OK;
00322 }
00323 
00324 /*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
00325 {
00326   return OK;
00327 }
00328 
00329 
00330 int CDMASMSInterface::updateInbox()
00331 {
00332   //Get number of unread/read messages
00333 
00334   DBG("Updating inbox");
00335   m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
00336 
00337   //Get counts
00338   m_state = SMS_GET_COUNT_CMD_SENT;
00339   int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
00340   if( ret != OK )
00341   {
00342     WARN("AT!CNTSMS returned %d", ret);
00343     m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
00344     m_state = SMS_IDLE;
00345     return NET_PROTOCOL;
00346   }
00347 
00348   return OK;
00349 }
00350