fork of VodafoneUSBModem with updated USBHost library

Dependencies:   Socket USBHost lwip-sys lwip

Dependents:   VodafoneUSBModemSMSTest

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SMSInterface.cpp Source File

SMSInterface.cpp

00001 /* SMSInterface.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__ 2
00021 #ifndef __MODULE__
00022 #define __MODULE__ "SMSInterface.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 
00027 #include "SMSInterface.h"
00028 
00029 #include <cstdio>
00030 
00031 #define DEFAULT_TIMEOUT 10000
00032 
00033 SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
00034 {
00035   m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
00036 }
00037 
00038 int SMSInterface::init()
00039 {
00040   m_msgRefListCount = 0;
00041   m_needsUpdate = true;
00042   m_state = SMS_IDLE;
00043 
00044   DBG("Set format");
00045   //Set Text mode format
00046   int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
00047   if(ret != OK)
00048   {
00049     return NET_PROTOCOL;
00050   }
00051 
00052   DBG("Setup new messages indication");
00053   //Setup new messages indication
00054   ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
00055   if(ret != OK)
00056   {
00057     return NET_PROTOCOL;
00058   }
00059 
00060   DBG("Try to fetch inbox");
00061   m_inboxMtx.lock();
00062   if( m_needsUpdate )
00063   {
00064     ret = updateInbox(); //Fetch existing messages references
00065     if(ret)
00066     {
00067       m_inboxMtx.unlock();
00068       return NET_PROTOCOL;
00069     }
00070   }
00071   m_inboxMtx.unlock();
00072 
00073   DBG("Initialization done");
00074   return OK;
00075 }
00076 
00077 int SMSInterface::send(const char* number, const char* message)
00078 {
00079   if( strlen(number) > 16 )
00080   {
00081     return NET_INVALID; //Number too long to match 3GPP spec
00082   }
00083 
00084   int ret;
00085 
00086   //Prepare infos
00087   m_state = SMS_SEND_CMD_SENT;
00088   m_msg = (char*) message;
00089 
00090   DBG("Send SM");
00091   //Send command
00092   char cmd[32];
00093   std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
00094   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00095 
00096   if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
00097   {
00098     WARN("ret %d, state %d", ret, m_state);
00099     m_state = SMS_IDLE;
00100     return NET_PROTOCOL;
00101   }
00102 
00103   DBG("SM sent");
00104   m_state = SMS_IDLE;
00105   return OK;
00106 }
00107 
00108 
00109 int SMSInterface::get(char* number, char* message, size_t maxLength)
00110 {
00111   if( maxLength < 1  )
00112   {
00113     return NET_INVALID; //Buffer too short
00114   }
00115 
00116   int ret;
00117 
00118   DBG("Get next message");
00119   m_inboxMtx.lock();
00120   if(m_msgRefListCount == 0 && m_needsUpdate)
00121   {
00122     DBG("Message list count is 0 and needs updating. Running updateInbox.");
00123     ret = updateInbox();
00124     
00125     if (ret)
00126     {
00127       m_inboxMtx.unlock();
00128       return ret;
00129     }
00130   }
00131 
00132   if(m_msgRefListCount == 0)
00133   {
00134     m_inboxMtx.unlock();
00135     DBG("Message list count is 0, I think it's empty and returning.");
00136     return NET_EMPTY; //No message to read
00137   }
00138 
00139   //Prepare infos
00140   m_state = SMS_GET_CMD_SENT;
00141   m_msisdn = (char*) number;
00142   m_msg = (char*) message;
00143   m_maxMsgLength = maxLength;
00144 
00145   DBG("Get SMS");
00146   //List command
00147   char cmd[32];
00148   std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
00149   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00150   if( ret != OK )
00151   {
00152     WARN("AT+CMGR returned %d", ret);
00153     m_state = SMS_IDLE;
00154     m_inboxMtx.unlock();
00155     return NET_PROTOCOL;
00156   }
00157 
00158   if (m_state != SMS_CMD_PROCESSED)
00159   {
00160     WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
00161   }
00162 
00163   DBG("Deleting message from index number: %d", m_msgRefList[0] );
00164   //Delete message from outbox
00165   std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
00166   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
00167   if(ret != OK)
00168   {
00169     ERR("Could not delete message");
00170   }
00171   //Remove message from list
00172   std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1);
00173   m_msgRefListCount--;
00174   
00175   if (m_state != SMS_CMD_PROCESSED)
00176   {
00177     m_state = SMS_IDLE;
00178     m_inboxMtx.unlock();
00179     return NET_EMPTY;
00180   }
00181   
00182   m_state = SMS_IDLE;
00183   m_inboxMtx.unlock();
00184 
00185   return OK;
00186 }
00187 
00188 
00189 int SMSInterface::getCount(size_t* pCount)
00190 {
00191   int ret;
00192 
00193   m_inboxMtx.lock();
00194   if( m_needsUpdate )
00195   {
00196     ret = updateInbox();
00197     if(ret)
00198     {
00199       m_inboxMtx.unlock();
00200       return NET_PROTOCOL;
00201     }
00202   }
00203 
00204   *pCount = m_msgRefListCount;
00205   m_inboxMtx.unlock();
00206 
00207   return OK;
00208 }
00209 
00210 
00211 /*virtual*/ int SMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00212 {
00213   if(m_state == SMS_SEND_CMD_SENT)
00214   {
00215     if( std::sscanf(line, "+CMGS: %*d") == 0 )
00216     {
00217       DBG("SM sent");
00218       m_state = SMS_CMD_PROCESSED;
00219     }
00220   }
00221   else if(m_state == SMS_GET_CMD_SENT)
00222   {
00223     DBG("Header: %s", line);
00224     if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
00225     {
00226       m_state = SMS_GET_HDR_RECEIVED;
00227     }
00228   }
00229   else if(m_state == SMS_GET_HDR_RECEIVED)
00230   {
00231     DBG("Message: %s", line);
00232     size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
00233     std::memcpy( m_msg, line, cpyLen );
00234     m_msg[cpyLen] = '\0';
00235     m_state = SMS_CMD_PROCESSED;
00236   }
00237   else if(m_state == SMS_GET_COUNT_CMD_SENT)
00238   {
00239     DBG("Header: %s", line);
00240     int msgRef;
00241     if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages 
00242     {
00243       m_state = SMS_GET_COUNT_HDR_RECEIVED;
00244       //Add message to list
00245       if(m_msgRefListCount < MAX_SM)
00246       {
00247         m_msgRefList[m_msgRefListCount] = msgRef;
00248       }
00249       m_msgRefListCount++; //Always count message
00250       DBG("m_msgRefListCount=%d",m_msgRefListCount);
00251     }
00252   }
00253   else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
00254   {
00255     DBG("Message (debug only): %s", line); //For debug only
00256     m_state = SMS_GET_COUNT_CMD_SENT;
00257   }
00258   return OK;
00259 }
00260 
00261 /*virtual*/ int SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
00262 {
00263   if(m_state == SMS_SEND_CMD_SENT)
00264   {
00265     char* crPtr = strchr(m_msg, CR);
00266     if(crPtr != NULL)
00267     {
00268       int crPos = crPtr - m_msg;
00269       //Replace m_inputBuf[crPos] with null-terminating char
00270       m_msg[crPos] = '\x0';
00271 
00272       //If there is a CR char, split message there
00273 
00274       //Do print the message
00275       int ret = pInst->sendData(m_msg);
00276       if(ret)
00277       {
00278         return ret;
00279       }
00280 
00281       char cr[2] = {CR, '\0'};
00282       ret = pInst->sendData(cr);
00283       if(ret)
00284       {
00285         return ret;
00286       }
00287 
00288       m_msg += crPos;
00289 
00290       if(m_msg[0] == LF)
00291       {
00292         m_msg++; //Discard LF char as well
00293       }
00294 
00295       return NET_MOREINFO;
00296     }
00297     else
00298     {
00299       //Do print the message
00300       pInst->sendData(m_msg);
00301       return OK;
00302     }
00303   }
00304 
00305   return OK;
00306 }
00307 
00308 /*virtual*/ bool SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
00309 {
00310   DBG("AT code is %s", atCode);
00311   if( strcmp("+CMTI", atCode) == 0 )
00312   {
00313     return true;
00314   }
00315 
00316   DBG("Not handled");
00317   return false;
00318 }
00319 
00320 /*virtual*/ void SMSInterface::onDispatchStart()
00321 {
00322 
00323 
00324 }
00325 
00326 /*virtual*/ void SMSInterface::onDispatchStop()
00327 {
00328 
00329 }
00330 
00331 /*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt)
00332 {
00333   if( strcmp("+CMTI", atCode) != 0 )
00334   {
00335     return; //Not supported
00336   }
00337 
00338   DBG("Unsollicited result code: %s - %s", atCode, evt);
00339 
00340   //Get index
00341   int msgRef;
00342   if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 )
00343   {
00344     DBG("Adding message to list (ref %d)", msgRef);
00345     if(m_inboxMtx.trylock())
00346     {
00347       //Add message to list
00348       if(m_msgRefListCount < MAX_SM)
00349       {
00350         m_msgRefList[m_msgRefListCount] = msgRef;
00351       }
00352       else
00353       {
00354         m_needsUpdate = true;
00355       }
00356       m_msgRefListCount++; //Always count message
00357       m_inboxMtx.unlock();
00358     }
00359     else
00360     {
00361       WARN("Could not get lock");
00362       m_needsUpdate = true;
00363     }
00364   }
00365 }
00366 
00367 int SMSInterface::updateInbox()
00368 {
00369   //Get memory indexes of unread messages
00370 
00371   DBG("Updating inbox");
00372   m_msgRefListCount = 0; //Reset list
00373   m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
00374 
00375   //First list the "REC READ" messages that were not processed in the previous session
00376   m_state = SMS_GET_COUNT_CMD_SENT;
00377   int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
00378   if( ret != OK )
00379   {
00380     WARN("AT+CMGL returned %d", ret);
00381     m_state = SMS_IDLE;
00382     m_msgRefListCount = 0; //List could be invalid
00383     m_needsUpdate = true;
00384     return NET_PROTOCOL;
00385   }
00386   
00387   //Now list the "REC UNREAD" messages that were received by the modem since
00388   m_state = SMS_GET_COUNT_CMD_SENT;
00389   ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
00390   if( ret != OK )
00391   {
00392     WARN("AT+CMGL returned %d", ret);
00393     m_state = SMS_IDLE;
00394     m_msgRefListCount = 0; //List could be invalid
00395     m_needsUpdate = true;
00396     return NET_PROTOCOL;
00397   }
00398 
00399   DBG("%d incoming messages in inbox", m_msgRefListCount);
00400 
00401   if( m_msgRefListCount > MAX_SM )
00402   {
00403     m_needsUpdate = true;
00404   }
00405 
00406   m_state = SMS_IDLE;
00407 
00408   return OK;
00409 }
00410 
00411