Nicholas Herriot / VodafoneK3770Lib
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SMSInterface.cpp Source File

SMSInterface.cpp

00001 /* SMSInterface.cpp */
00002 /*
00003 Copyright (C) 2012 ARM Limited.
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy of
00006 this software and associated documentation files (the "Software"), to deal in
00007 the Software without restriction, including without limitation the rights to
00008 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
00009 of the Software, and to permit persons to whom the Software is furnished to do
00010 so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in all
00013 copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00021 SOFTWARE.
00022 */
00023 
00024 #define __DEBUG__ 4
00025 #ifndef __MODULE__
00026 #define __MODULE__ "SMSInterface.cpp"
00027 #endif
00028 
00029 #include "core/fwk.h"
00030 
00031 #include "SMSInterface.h"
00032 
00033 #include <cstdio>
00034 
00035 #define DEFAULT_TIMEOUT 10000
00036 
00037 SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL), /*m_msgCount(0),*/
00038 m_msgRefListCount(0), m_needsUpdate(true), m_state(SMS_IDLE)
00039 {
00040   m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
00041 }
00042 
00043 int SMSInterface::init()
00044 {
00045   DBG("Set format");
00046   //Set Text mode format
00047   int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
00048   if(ret != OK)
00049   {
00050     return NET_PROTOCOL;
00051   }
00052 
00053   DBG("Setup new messages indication");
00054   //Setup new messages indication
00055   ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
00056   if(ret != OK)
00057   {
00058     return NET_PROTOCOL;
00059   }
00060 
00061   DBG("Try to fetch inbox");
00062   m_inboxMtx.lock();
00063   if( m_needsUpdate )
00064   {
00065     ret = updateInbox(); //Fetch existing messages references
00066     if(ret)
00067     {
00068       m_inboxMtx.unlock();
00069       return NET_PROTOCOL;
00070     }
00071   }
00072   m_inboxMtx.unlock();
00073 
00074   DBG("Initialization done");
00075   return OK;
00076 }
00077 
00078 int SMSInterface::send(const char* number, const char* message)
00079 {
00080   if( strlen(number) > 16 )
00081   {
00082     return NET_INVALID; //Number too long to match 3GPP spec
00083   }
00084 
00085   int ret;
00086 
00087   //Prepare infos
00088   m_state = SMS_SEND_CMD_SENT;
00089   m_msg = (char*) message;
00090 
00091   DBG("Send SM");
00092   //Send command
00093   char cmd[32];
00094   std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
00095   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00096 
00097   if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
00098   {
00099     WARN("ret %d, state %d", ret, m_state);
00100     m_state = SMS_IDLE;
00101     return NET_PROTOCOL;
00102   }
00103 
00104   DBG("SM sent");
00105   m_state = SMS_IDLE;
00106   return OK;
00107 }
00108 
00109 
00110 int SMSInterface::get(char* number, char* message, size_t maxLength)
00111 {
00112   if( maxLength < 1  )
00113   {
00114     return NET_INVALID; //Buffer too short
00115   }
00116 
00117   int ret;
00118 
00119   DBG("Get next message");
00120   m_inboxMtx.lock();
00121   if(m_msgRefListCount == 0 && m_needsUpdate)
00122   {
00123     ret = updateInbox();
00124     if (ret)
00125     {
00126       m_inboxMtx.unlock();
00127       return ret;
00128     }
00129   }
00130 
00131   if(m_msgRefListCount == 0)
00132   {
00133     m_inboxMtx.unlock();
00134     return NET_EMPTY; //No message to read
00135   }
00136 
00137   //Prepare infos
00138   m_state = SMS_GET_CMD_SENT;
00139   m_msisdn = (char*) number;
00140   m_msg = (char*) message;
00141   m_maxMsgLength = maxLength;
00142 
00143   DBG("Get SMS");
00144   //List command
00145   char cmd[32];
00146   std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
00147   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00148   if( ret != OK )
00149   {
00150     WARN("AT+CMGR returned %d", ret);
00151     m_state = SMS_IDLE;
00152     m_inboxMtx.unlock();
00153     return NET_PROTOCOL;
00154   }
00155 
00156   if (m_state != SMS_CMD_PROCESSED)
00157   {
00158     m_state = SMS_IDLE;
00159     m_inboxMtx.unlock();
00160     return NET_EMPTY;
00161   }
00162 
00163   m_state = SMS_IDLE;
00164 
00165   DBG("Deleting message");
00166   //Delete message from outbox
00167   std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
00168   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
00169   if(ret != OK)
00170   {
00171     m_inboxMtx.unlock();
00172     WARN("Could not delete message");
00173   }
00174 
00175   //Remove message from list
00176   std::memmove(m_msgRefList, m_msgRefList+1, m_msgRefListCount-1);
00177   m_msgRefListCount--;
00178 
00179   m_inboxMtx.unlock();
00180 
00181   return OK;
00182 }
00183 
00184 
00185 int SMSInterface::getCount(size_t* pCount)
00186 {
00187   int ret;
00188 
00189   m_inboxMtx.lock();
00190   if( m_needsUpdate )
00191   {
00192     ret = updateInbox();
00193     if(ret)
00194     {
00195       m_inboxMtx.unlock();
00196       return NET_PROTOCOL;
00197     }
00198   }
00199 
00200   *pCount = m_msgRefListCount;
00201   m_inboxMtx.unlock();
00202 
00203   return OK;
00204 }
00205 
00206 
00207 /*virtual*/ int SMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00208 {
00209   if(m_state == SMS_SEND_CMD_SENT)
00210   {
00211     if( std::sscanf(line, "+CMGS: %*d") == 0 )
00212     {
00213       DBG("SM sent");
00214       m_state = SMS_CMD_PROCESSED;
00215     }
00216   }
00217   else if(m_state == SMS_GET_CMD_SENT)
00218   {
00219     DBG("Header: %s", line);
00220     if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
00221     {
00222       m_state = SMS_GET_HDR_RECEIVED;
00223     }
00224   }
00225   else if(m_state == SMS_GET_HDR_RECEIVED)
00226   {
00227     DBG("Message: %s", line);
00228     size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
00229     std::memcpy( m_msg, line, cpyLen );
00230     m_msg[cpyLen] = '\0';
00231     m_state = SMS_CMD_PROCESSED;
00232   }
00233   else if(m_state == SMS_GET_COUNT_CMD_SENT)
00234   {
00235     DBG("Header: %s", line);
00236     int msgRef;
00237     if( std::sscanf(line, "+CMGL: %d", &msgRef) == 1 )
00238     {
00239       m_state = SMS_GET_COUNT_HDR_RECEIVED;
00240       //Add message to list
00241       if(m_msgRefListCount < MAX_SM)
00242       {
00243         m_msgRefList[m_msgRefListCount] = msgRef;
00244       }
00245       m_msgRefListCount++; //Always count message
00246       DBG("m_msgRefListCount=%d",m_msgRefListCount);
00247     }
00248   }
00249   else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
00250   {
00251     DBG("Message (debug only): %s", line); //For debug only
00252     m_state = SMS_GET_COUNT_CMD_SENT;
00253   }
00254   return OK;
00255 }
00256 
00257 /*virtual*/ int SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
00258 {
00259   if(m_state == SMS_SEND_CMD_SENT)
00260   {
00261     char* crPtr = strchr(m_msg, CR);
00262     if(crPtr != NULL)
00263     {
00264       int crPos = crPtr - m_msg;
00265       //Replace m_inputBuf[crPos] with null-terminating char
00266       m_msg[crPos] = '\x0';
00267 
00268       //If there is a CR char, split message there
00269 
00270       //Do print the message
00271       int ret = pInst->sendData(m_msg);
00272       if(ret)
00273       {
00274         return ret;
00275       }
00276 
00277       char cr[2] = {CR, '\0'};
00278       ret = pInst->sendData(cr);
00279       if(ret)
00280       {
00281         return ret;
00282       }
00283 
00284       m_msg += crPos;
00285 
00286       if(m_msg[0] == LF)
00287       {
00288         m_msg++; //Discard LF char as well
00289       }
00290 
00291       return NET_MOREINFO;
00292     }
00293     else
00294     {
00295       //Do print the message
00296       pInst->sendData(m_msg);
00297       return OK;
00298     }
00299   }
00300 
00301   return OK;
00302 }
00303 
00304 /*virtual*/ bool SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
00305 {
00306   DBG("AT code is %s", atCode);
00307   if( strcmp("+CMTI", atCode) == 0 )
00308   {
00309     return true;
00310   }
00311 
00312   DBG("Not handled");
00313   return false;
00314 }
00315 
00316 /*virtual*/ void SMSInterface::onDispatchStart()
00317 {
00318 
00319 
00320 }
00321 
00322 /*virtual*/ void SMSInterface::onDispatchStop()
00323 {
00324 
00325 }
00326 
00327 /*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt)
00328 {
00329   if( strcmp("+CMTI", atCode) != 0 )
00330   {
00331     return; //Not supported
00332   }
00333 
00334   DBG("Unsollicited result code: %s - %s", atCode, evt);
00335 
00336   //Get index
00337   int msgRef;
00338   if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 )
00339   {
00340     DBG("Adding message to list (ref %d)", msgRef);
00341     m_inboxMtx.lock();
00342     //Add message to list
00343     if(m_msgRefListCount < MAX_SM)
00344     {
00345       m_msgRefList[m_msgRefListCount] = msgRef;
00346     }
00347     else
00348     {
00349       m_needsUpdate = true;
00350     }
00351     m_msgRefListCount++; //Always count message
00352     m_inboxMtx.unlock();
00353   }
00354 }
00355 
00356 int SMSInterface::updateInbox()
00357 {
00358   //Get memory indexes of unread messages
00359   m_state = SMS_GET_COUNT_CMD_SENT;
00360 
00361   DBG("Updating inbox");
00362   m_msgRefListCount = 0; //Reset list
00363 
00364   int ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
00365   if( ret != OK )
00366   {
00367     WARN("AT+CMGL returned %d", ret);
00368     m_state = SMS_IDLE;
00369     m_msgRefListCount = 0; //List could be invalid
00370     m_needsUpdate = true;
00371     return NET_PROTOCOL;
00372   }
00373 
00374   DBG("%d incoming messages in inbox", m_msgRefListCount);
00375 
00376   if( m_msgRefListCount > MAX_SM )
00377   {
00378     m_needsUpdate = true;
00379   }
00380   else
00381   {
00382     m_needsUpdate = false;
00383   }
00384 
00385   m_state = SMS_IDLE;
00386 
00387   return OK;
00388 }
00389 
00390