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 GSMSMSInterface.cpp Source File

GSMSMSInterface.cpp

00001 /* GSMSMSInterface.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__ "GSMSMSInterface.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 
00027 #include "GSMSMSInterface.h"
00028 
00029 #include <cstdio>
00030 #include <cstring>
00031 
00032 #define DEFAULT_TIMEOUT 10000
00033 
00034 GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
00035 {
00036   m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
00037 }
00038 
00039 int GSMSMSInterface::init()
00040 {
00041   m_msgRefListCount = 0;
00042   m_needsUpdate = true;
00043   m_state = SMS_IDLE;
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 GSMSMSInterface::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 GSMSMSInterface::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) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
00122   {
00123     DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
00124     ret = updateInbox();
00125     
00126     if (ret)
00127     {
00128       m_inboxMtx.unlock();
00129       return ret;
00130     }
00131   }
00132   
00133   DBG("%d messages to read", m_msgRefListCount);
00134 
00135   if(m_msgRefListCount == 0)
00136   {
00137     m_inboxMtx.unlock();
00138     DBG("Message list count is 0, I think it's empty and returning.");
00139     return NET_EMPTY; //No message to read
00140   }
00141 
00142   //Prepare infos
00143   m_state = SMS_GET_CMD_SENT;
00144   m_msisdn = (char*) number;
00145   m_msg = (char*) message;
00146   m_maxMsgLength = maxLength;
00147 
00148   DBG("Get SMS");
00149   //List command
00150   char cmd[32];
00151   std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
00152   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
00153   if( ret != OK )
00154   {
00155     WARN("AT+CMGR returned %d", ret);
00156     m_state = SMS_IDLE;
00157     m_inboxMtx.unlock();
00158     return NET_PROTOCOL;
00159   }
00160 
00161   if (m_state != SMS_CMD_PROCESSED)
00162   {
00163     WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
00164   }
00165 
00166   DBG("Deleting message from index number: %d", m_msgRefList[0] );
00167   //Delete message from outbox
00168   std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
00169   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
00170   if(ret != OK)
00171   {
00172     ERR("Could not delete message");
00173   }
00174   //Remove message from list
00175   std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
00176   m_msgRefListCount--;
00177   
00178   if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
00179   {
00180     DBG("Last message index is unknown, will need to be updated");
00181     m_msgRefList[MAX_SM - 1] = -1;
00182   }
00183   
00184   DBG("%d messages to read", m_msgRefListCount);
00185   
00186   if (m_state != SMS_CMD_PROCESSED)
00187   {
00188     m_state = SMS_IDLE;
00189     m_inboxMtx.unlock();
00190     return NET_EMPTY;
00191   }
00192   
00193   m_state = SMS_IDLE;
00194   m_inboxMtx.unlock();
00195 
00196   return OK;
00197 }
00198 
00199 
00200 int GSMSMSInterface::getCount(size_t* pCount)
00201 {
00202   int ret;
00203 
00204   m_inboxMtx.lock();
00205   if( m_needsUpdate )
00206   {
00207     ret = updateInbox();
00208     if(ret)
00209     {
00210       m_inboxMtx.unlock();
00211       return NET_PROTOCOL;
00212     }
00213   }
00214 
00215   *pCount = m_msgRefListCount;
00216   m_inboxMtx.unlock();
00217 
00218   return OK;
00219 }
00220 
00221 
00222 /*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00223 {
00224   if(m_state == SMS_SEND_CMD_SENT)
00225   {
00226     if( std::sscanf(line, "+CMGS: %*d") == 0 )
00227     {
00228       DBG("SM sent");
00229       m_state = SMS_CMD_PROCESSED;
00230     }
00231   }
00232   else if(m_state == SMS_GET_CMD_SENT)
00233   {
00234     DBG("Header: %s", line);
00235     if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
00236     {
00237       m_state = SMS_GET_HDR_RECEIVED;
00238     }
00239   }
00240   else if(m_state == SMS_GET_HDR_RECEIVED)
00241   {
00242     DBG("Message: %s", line);
00243     size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
00244     std::memcpy( m_msg, line, cpyLen );
00245     m_msg[cpyLen] = '\0';
00246     m_state = SMS_CMD_PROCESSED;
00247   }
00248   else if(m_state == SMS_GET_COUNT_CMD_SENT)
00249   {
00250     DBG("Header: %s", line);
00251     int msgRef;
00252     if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages 
00253     {
00254       m_state = SMS_GET_COUNT_HDR_RECEIVED;
00255       //Add message to list
00256       if(m_msgRefListCount < MAX_SM)
00257       {
00258         m_msgRefList[m_msgRefListCount] = msgRef;
00259       }
00260       m_msgRefListCount++; //Always count message
00261       DBG("m_msgRefListCount=%d",m_msgRefListCount);
00262     }
00263   }
00264   else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
00265   {
00266     DBG("Message (debug only): %s", line); //For debug only
00267     m_state = SMS_GET_COUNT_CMD_SENT;
00268   }
00269   return OK;
00270 }
00271 
00272 /*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
00273 {
00274   if(m_state == SMS_SEND_CMD_SENT)
00275   {
00276     char* crPtr = strchr(m_msg, CR);
00277     if(crPtr != NULL)
00278     {
00279       int crPos = crPtr - m_msg;
00280       //Replace m_inputBuf[crPos] with null-terminating char
00281       m_msg[crPos] = '\x0';
00282 
00283       //If there is a CR char, split message there
00284 
00285       //Do print the message
00286       int ret = pInst->sendData(m_msg);
00287       if(ret)
00288       {
00289         return ret;
00290       }
00291 
00292       char cr[2] = {CR, '\0'};
00293       ret = pInst->sendData(cr);
00294       if(ret)
00295       {
00296         return ret;
00297       }
00298 
00299       m_msg += crPos;
00300 
00301       if(m_msg[0] == LF)
00302       {
00303         m_msg++; //Discard LF char as well
00304       }
00305 
00306       return NET_MOREINFO;
00307     }
00308     else
00309     {
00310       //Do print the message
00311       pInst->sendData(m_msg);
00312       return OK;
00313     }
00314   }
00315 
00316   return OK;
00317 }
00318 
00319 /*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
00320 {
00321   DBG("AT code is %s", atCode);
00322   if( strcmp("+CMTI", atCode) == 0 )
00323   {
00324     return true;
00325   }
00326 
00327   DBG("Not handled");
00328   return false;
00329 }
00330 
00331 /*virtual*/ void GSMSMSInterface::onDispatchStart()
00332 {
00333     
00334 }
00335 
00336 /*virtual*/ void GSMSMSInterface::onDispatchStop()
00337 {
00338     
00339 }
00340 
00341 /*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
00342 {
00343   return "AT+CNMI=2,1,0,0,0";
00344 }
00345 
00346 /*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
00347 {
00348   return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
00349 }
00350 
00351 /*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
00352 {
00353   if( strcmp("+CMTI", atCode) != 0 )
00354   {
00355     return; //Not supported
00356   }
00357 
00358   DBG("Unsollicited result code: %s - %s", atCode, evt);
00359 
00360   //Get index
00361   int msgRef;
00362   if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) || 
00363      ( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
00364   {
00365     DBG("Adding message to list (ref %d)", msgRef);
00366     if(m_inboxMtx.trylock())
00367     {
00368       //Add message to list
00369       if(m_msgRefListCount < MAX_SM)
00370       {
00371         m_msgRefList[m_msgRefListCount] = msgRef;
00372       }
00373       m_msgRefListCount++; //Always count message
00374       m_inboxMtx.unlock();
00375     }
00376     else
00377     {
00378       WARN("Could not get lock");
00379       m_needsUpdate = true;
00380     }
00381   }
00382 }
00383 
00384 int GSMSMSInterface::updateInbox()
00385 {
00386   //Get memory indexes of unread messages
00387 
00388   DBG("Updating inbox");
00389   m_msgRefListCount = 0; //Reset list
00390   m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
00391 
00392   //First list the "REC READ" messages that were not processed in the previous session
00393   m_state = SMS_GET_COUNT_CMD_SENT;
00394   int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
00395   if( ret != OK )
00396   {
00397     WARN("AT+CMGL returned %d", ret);
00398     m_state = SMS_IDLE;
00399     m_msgRefListCount = 0; //List could be invalid
00400     m_needsUpdate = true;
00401     return NET_PROTOCOL;
00402   }
00403   
00404   //Now list the "REC UNREAD" messages that were received by the modem since
00405   m_state = SMS_GET_COUNT_CMD_SENT;
00406   ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
00407   if( ret != OK )
00408   {
00409     WARN("AT+CMGL returned %d", ret);
00410     m_state = SMS_IDLE;
00411     m_msgRefListCount = 0; //List could be invalid
00412     m_needsUpdate = true;
00413     return NET_PROTOCOL;
00414   }
00415 
00416   DBG("%d incoming messages in inbox", m_msgRefListCount);
00417 
00418   m_state = SMS_IDLE;
00419 
00420   return OK;
00421 }
00422 
00423