Base library for cellular modem implementations
Dependencies: Socket lwip-sys lwip
Dependents: CellularUSBModem CellularUSBModem
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
Generated on Tue Jul 26 2022 09:42:59 by 1.7.2