Vodafone K3770/K3772-Z modems driver & networking library

Dependencies:   Socket USBHostWANDongle lwip-sys lwip

Dependents:   VodafoneUSBModemHTTPClientTest VodafoneUSBModemNTPClientTest VodafoneUSBModemSMSTest VodafoneUSBModemUSSDTest ... more

Fork of VodafoneUSBModem_bleedingedge by Donatien Garnier

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