GSMSMSInterface.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* GSMSMSInterface.cpp */
  2. /* Copyright (C) 2012 mbed.org, MIT License
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  6. * including without limitation the rights to use, copy, modify, merge, publish, distribute,
  7. * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all copies or
  11. * substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
  14. * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  16. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. */
  19. #define __DEBUG__ 2
  20. #ifndef __MODULE__
  21. #define __MODULE__ "GSMSMSInterface.cpp"
  22. #endif
  23. #include "core/fwk.h"
  24. #include "GSMSMSInterface.h"
  25. #include <cstdio>
  26. #include <cstring>
  27. #define DEFAULT_TIMEOUT 10000
  28. GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
  29. {
  30. m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
  31. }
  32. int GSMSMSInterface::init()
  33. {
  34. m_msgRefListCount = 0;
  35. m_needsUpdate = true;
  36. m_state = SMS_IDLE;
  37. DBG("Set format");
  38. //Set Text mode format
  39. int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
  40. if(ret != OK)
  41. {
  42. return NET_PROTOCOL;
  43. }
  44. DBG("Setup new messages indication");
  45. //Setup new messages indication
  46. ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
  47. if(ret != OK)
  48. {
  49. return NET_PROTOCOL;
  50. }
  51. DBG("Try to fetch inbox");
  52. m_inboxMtx.lock();
  53. if( m_needsUpdate )
  54. {
  55. ret = updateInbox(); //Fetch existing messages references
  56. if(ret)
  57. {
  58. m_inboxMtx.unlock();
  59. return NET_PROTOCOL;
  60. }
  61. }
  62. m_inboxMtx.unlock();
  63. DBG("Initialization done");
  64. return OK;
  65. }
  66. int GSMSMSInterface::send(const char* number, const char* message)
  67. {
  68. if( strlen(number) > 16 )
  69. {
  70. return NET_INVALID; //Number too long to match 3GPP spec
  71. }
  72. int ret;
  73. //Prepare infos
  74. m_state = SMS_SEND_CMD_SENT;
  75. m_msg = (char*) message;
  76. DBG("Send SM");
  77. //Send command
  78. char cmd[32];
  79. std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
  80. ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
  81. if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
  82. {
  83. WARN("ret %d, state %d", ret, m_state);
  84. m_state = SMS_IDLE;
  85. return NET_PROTOCOL;
  86. }
  87. DBG("SM sent");
  88. m_state = SMS_IDLE;
  89. return OK;
  90. }
  91. int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
  92. {
  93. if( maxLength < 1 )
  94. {
  95. return NET_INVALID; //Buffer too short
  96. }
  97. int ret;
  98. DBG("Get next message");
  99. m_inboxMtx.lock();
  100. if( ((m_msgRefListCount == 0) && m_needsUpdate) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
  101. {
  102. DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
  103. ret = updateInbox();
  104. if (ret)
  105. {
  106. m_inboxMtx.unlock();
  107. return ret;
  108. }
  109. }
  110. DBG("%d messages to read", m_msgRefListCount);
  111. if(m_msgRefListCount == 0)
  112. {
  113. m_inboxMtx.unlock();
  114. DBG("Message list count is 0, I think it's empty and returning.");
  115. return NET_EMPTY; //No message to read
  116. }
  117. //Prepare infos
  118. m_state = SMS_GET_CMD_SENT;
  119. m_msisdn = (char*) number;
  120. m_msg = (char*) message;
  121. m_maxMsgLength = maxLength;
  122. DBG("Get SMS");
  123. //List command
  124. char cmd[32];
  125. std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
  126. ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
  127. if( ret != OK )
  128. {
  129. WARN("AT+CMGR returned %d", ret);
  130. m_state = SMS_IDLE;
  131. m_inboxMtx.unlock();
  132. return NET_PROTOCOL;
  133. }
  134. if (m_state != SMS_CMD_PROCESSED)
  135. {
  136. WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
  137. }
  138. DBG("Deleting message from index number: %d", m_msgRefList[0] );
  139. //Delete message from outbox
  140. std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
  141. ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
  142. if(ret != OK)
  143. {
  144. ERR("Could not delete message");
  145. }
  146. //Remove message from list
  147. std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
  148. m_msgRefListCount--;
  149. if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
  150. {
  151. DBG("Last message index is unknown, will need to be updated");
  152. m_msgRefList[MAX_SM - 1] = -1;
  153. }
  154. DBG("%d messages to read", m_msgRefListCount);
  155. if (m_state != SMS_CMD_PROCESSED)
  156. {
  157. m_state = SMS_IDLE;
  158. m_inboxMtx.unlock();
  159. return NET_EMPTY;
  160. }
  161. m_state = SMS_IDLE;
  162. m_inboxMtx.unlock();
  163. return OK;
  164. }
  165. int GSMSMSInterface::getCount(size_t* pCount)
  166. {
  167. int ret;
  168. m_inboxMtx.lock();
  169. if( m_needsUpdate )
  170. {
  171. ret = updateInbox();
  172. if(ret)
  173. {
  174. m_inboxMtx.unlock();
  175. return NET_PROTOCOL;
  176. }
  177. }
  178. *pCount = m_msgRefListCount;
  179. m_inboxMtx.unlock();
  180. return OK;
  181. }
  182. /*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
  183. {
  184. if(m_state == SMS_SEND_CMD_SENT)
  185. {
  186. if( std::sscanf(line, "+CMGS: %*d") == 0 )
  187. {
  188. DBG("SM sent");
  189. m_state = SMS_CMD_PROCESSED;
  190. }
  191. }
  192. else if(m_state == SMS_GET_CMD_SENT)
  193. {
  194. DBG("Header: %s", line);
  195. if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
  196. {
  197. m_state = SMS_GET_HDR_RECEIVED;
  198. }
  199. }
  200. else if(m_state == SMS_GET_HDR_RECEIVED)
  201. {
  202. DBG("Message: %s", line);
  203. size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
  204. std::memcpy( m_msg, line, cpyLen );
  205. m_msg[cpyLen] = '\0';
  206. m_state = SMS_CMD_PROCESSED;
  207. }
  208. else if(m_state == SMS_GET_COUNT_CMD_SENT)
  209. {
  210. DBG("Header: %s", line);
  211. int msgRef;
  212. if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages
  213. {
  214. m_state = SMS_GET_COUNT_HDR_RECEIVED;
  215. //Add message to list
  216. if(m_msgRefListCount < MAX_SM)
  217. {
  218. m_msgRefList[m_msgRefListCount] = msgRef;
  219. }
  220. m_msgRefListCount++; //Always count message
  221. DBG("m_msgRefListCount=%d",m_msgRefListCount);
  222. }
  223. }
  224. else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
  225. {
  226. DBG("Message (debug only): %s", line); //For debug only
  227. m_state = SMS_GET_COUNT_CMD_SENT;
  228. }
  229. return OK;
  230. }
  231. /*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
  232. {
  233. if(m_state == SMS_SEND_CMD_SENT)
  234. {
  235. char* crPtr = strchr(m_msg, CR);
  236. if(crPtr != NULL)
  237. {
  238. int crPos = crPtr - m_msg;
  239. //Replace m_inputBuf[crPos] with null-terminating char
  240. m_msg[crPos] = '\x0';
  241. //If there is a CR char, split message there
  242. //Do print the message
  243. int ret = pInst->sendData(m_msg);
  244. if(ret)
  245. {
  246. return ret;
  247. }
  248. char cr[2] = {CR, '\0'};
  249. ret = pInst->sendData(cr);
  250. if(ret)
  251. {
  252. return ret;
  253. }
  254. m_msg += crPos;
  255. if(m_msg[0] == LF)
  256. {
  257. m_msg++; //Discard LF char as well
  258. }
  259. return NET_MOREINFO;
  260. }
  261. else
  262. {
  263. //Do print the message
  264. pInst->sendData(m_msg);
  265. return OK;
  266. }
  267. }
  268. return OK;
  269. }
  270. /*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
  271. {
  272. DBG("AT code is %s", atCode);
  273. if( strcmp("+CMTI", atCode) == 0 )
  274. {
  275. return true;
  276. }
  277. DBG("Not handled");
  278. return false;
  279. }
  280. /*virtual*/ void GSMSMSInterface::onDispatchStart()
  281. {
  282. }
  283. /*virtual*/ void GSMSMSInterface::onDispatchStop()
  284. {
  285. }
  286. /*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
  287. {
  288. return "AT+CNMI=2,1,0,0,0";
  289. }
  290. /*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
  291. {
  292. return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
  293. }
  294. /*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
  295. {
  296. if( strcmp("+CMTI", atCode) != 0 )
  297. {
  298. return; //Not supported
  299. }
  300. DBG("Unsollicited result code: %s - %s", atCode, evt);
  301. //Get index
  302. int msgRef;
  303. if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) ||
  304. ( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
  305. {
  306. DBG("Adding message to list (ref %d)", msgRef);
  307. if(m_inboxMtx.trylock())
  308. {
  309. //Add message to list
  310. if(m_msgRefListCount < MAX_SM)
  311. {
  312. m_msgRefList[m_msgRefListCount] = msgRef;
  313. }
  314. m_msgRefListCount++; //Always count message
  315. m_inboxMtx.unlock();
  316. }
  317. else
  318. {
  319. WARN("Could not get lock");
  320. m_needsUpdate = true;
  321. }
  322. }
  323. }
  324. int GSMSMSInterface::updateInbox()
  325. {
  326. //Get memory indexes of unread messages
  327. DBG("Updating inbox");
  328. m_msgRefListCount = 0; //Reset list
  329. m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
  330. //First list the "REC READ" messages that were not processed in the previous session
  331. m_state = SMS_GET_COUNT_CMD_SENT;
  332. int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
  333. if( ret != OK )
  334. {
  335. WARN("AT+CMGL returned %d", ret);
  336. m_state = SMS_IDLE;
  337. m_msgRefListCount = 0; //List could be invalid
  338. m_needsUpdate = true;
  339. return NET_PROTOCOL;
  340. }
  341. //Now list the "REC UNREAD" messages that were received by the modem since
  342. m_state = SMS_GET_COUNT_CMD_SENT;
  343. ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
  344. if( ret != OK )
  345. {
  346. WARN("AT+CMGL returned %d", ret);
  347. m_state = SMS_IDLE;
  348. m_msgRefListCount = 0; //List could be invalid
  349. m_needsUpdate = true;
  350. return NET_PROTOCOL;
  351. }
  352. DBG("%d incoming messages in inbox", m_msgRefListCount);
  353. m_state = SMS_IDLE;
  354. return OK;
  355. }