CDMASMSInterface.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* CDMASMSInterface.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__ 0
  20. #ifndef __MODULE__
  21. #define __MODULE__ "CDMASMSInterface.cpp"
  22. #endif
  23. #include "core/fwk.h"
  24. #include "CDMASMSInterface.h"
  25. #include <cstdio>
  26. #include <cstring>
  27. using std::sscanf;
  28. #define DEFAULT_TIMEOUT 10000
  29. CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
  30. {
  31. }
  32. int CDMASMSInterface::init()
  33. {
  34. m_state = SMS_IDLE;
  35. DBG("Get number of messages in the different inboxes");
  36. int ret = updateInbox();
  37. if(ret)
  38. {
  39. return NET_PROTOCOL;
  40. }
  41. DBG("Initialization done");
  42. return OK;
  43. }
  44. int CDMASMSInterface::send(const char* number, const char* message)
  45. {
  46. if( strlen(number) > 16 )
  47. {
  48. return NET_INVALID; //Number too long
  49. }
  50. int ret;
  51. //Prepare infos
  52. m_state = SMS_SEND_CMD_SENT;
  53. bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
  54. DBG("Send SM");
  55. //Send command
  56. char cmd[32+strlen(message)];
  57. std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
  58. ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
  59. if(ret != OK)
  60. {
  61. WARN("ret %d", ret);
  62. m_state = SMS_IDLE;
  63. return NET_PROTOCOL;
  64. }
  65. DBG("Check status");
  66. m_txState = SMS_PENDING;
  67. int tries = 10;
  68. while(tries--)
  69. {
  70. m_state = SMS_GET_TX_STATUS_CMD_SENT;
  71. ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
  72. if(ret)
  73. {
  74. m_state = SMS_IDLE;
  75. return ret;
  76. }
  77. m_state = SMS_IDLE;
  78. if(m_txState == SMS_PENDING) //Wait more
  79. {
  80. Thread::wait(1000);
  81. continue;
  82. }
  83. else if(m_txState == SMS_FAILED)
  84. {
  85. ERR("The modem could not send the SM");
  86. return NET_CONN; //Probably a conenction issue, the user can retry
  87. }
  88. else
  89. {
  90. break;
  91. }
  92. }
  93. if(!tries)
  94. {
  95. ERR("The is still trying to send the SM");
  96. return NET_TIMEOUT;
  97. }
  98. return OK;
  99. }
  100. int CDMASMSInterface::get(char* number, char* message, size_t maxLength)
  101. {
  102. if( maxLength < 1 )
  103. {
  104. return NET_INVALID; //Buffer too short
  105. }
  106. int ret;
  107. DBG("Get next message");
  108. if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
  109. {
  110. DBG("Message list count is 0 and needs updating. Running updateInbox.");
  111. ret = updateInbox();
  112. if (ret)
  113. {
  114. return ret;
  115. }
  116. }
  117. if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
  118. {
  119. DBG("Message list count is 0");
  120. return NET_EMPTY; //No message to read
  121. }
  122. //Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
  123. int index;
  124. if(m_msgInListsCount[2])
  125. {
  126. index = 3;
  127. }
  128. else if(m_msgInListsCount[0])
  129. {
  130. index = 1;
  131. }
  132. else //if(m_msgInListsCount[1])
  133. {
  134. index = 2;
  135. }
  136. //Prepare infos
  137. m_state = SMS_GET_CMD_SENT;
  138. m_msisdn = (char*) number;
  139. m_msg = (char*) message;
  140. m_maxMsgLength = maxLength;
  141. m_headersToRead = 3;
  142. m_msisdn[0] = '\0';
  143. DBG("Get SMS");
  144. //Read command
  145. char cmd[32];
  146. std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
  147. ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
  148. if( ret != OK )
  149. {
  150. WARN("AT!GSMS returned %d", ret);
  151. m_state = SMS_IDLE;
  152. return NET_PROTOCOL;
  153. }
  154. //If message is not read, it will be put at the end of the read list
  155. int item;
  156. if( index != 3 )
  157. {
  158. //Decrement count in relevant list
  159. m_msgInListsCount[index-1]--;
  160. //Increment count in read list
  161. m_msgInListsCount[3-1]++;
  162. item = m_msgInListsCount[3-1];
  163. //Normally item should be equal to 1 as we'd have read any older messages first
  164. if( item != 1 )
  165. {
  166. WARN("Still some older messages pending in the read inbox");
  167. }
  168. }
  169. else
  170. {
  171. //The item is still the oldest one
  172. item = 1;
  173. }
  174. DBG("Deleting message");
  175. //Delete message from inbox
  176. std::sprintf(cmd, "AT!DSMS=3"/*,%d", item*/); //FIXME why doesn't that work when specifying the index??
  177. ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
  178. if(ret != OK)
  179. {
  180. ERR("Could not delete message");
  181. }
  182. else
  183. {
  184. //Now we can decrease the number of read messages
  185. m_msgInListsCount[3-1]--;
  186. }
  187. if (m_state != SMS_CMD_PROCESSED)
  188. {
  189. WARN("Message could not be retrieved properly");
  190. m_state = SMS_IDLE;
  191. return NET_EMPTY;
  192. }
  193. m_state = SMS_IDLE;
  194. return OK;
  195. }
  196. int CDMASMSInterface::getCount(size_t* pCount)
  197. {
  198. int ret = updateInbox();
  199. if(ret)
  200. {
  201. return NET_PROTOCOL;
  202. }
  203. *pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
  204. return OK;
  205. }
  206. /*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
  207. {
  208. if(m_state == SMS_SEND_CMD_SENT)
  209. {
  210. DBG("SMS Send: %s", line);
  211. }
  212. else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
  213. {
  214. if(!strcmp(line, "sent"))
  215. {
  216. m_txState = SMS_SENT;
  217. m_state = SMS_CMD_PROCESSED;
  218. }
  219. else if(!strcmp(line, "failed"))
  220. {
  221. m_txState = SMS_FAILED;
  222. m_state = SMS_CMD_PROCESSED;
  223. }
  224. else if(!strcmp(line, "none"))
  225. {
  226. m_txState = SMS_NONE;
  227. m_state = SMS_CMD_PROCESSED;
  228. }
  229. else if(!strcmp(line, "pending"))
  230. {
  231. m_txState = SMS_PENDING;
  232. m_state = SMS_CMD_PROCESSED;
  233. }
  234. }
  235. else if(m_state == SMS_GET_CMD_SENT)
  236. {
  237. DBG("Header: %s", line);
  238. if(m_msisdn[0]=='\0')
  239. {
  240. sscanf(line, "From: %16s", m_msisdn);
  241. }
  242. m_headersToRead--;
  243. if(m_headersToRead==0) //End of headers
  244. {
  245. if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
  246. {
  247. m_state = SMS_GET_HDR_RECEIVED;
  248. }
  249. else
  250. {
  251. m_state = SMS_IDLE; //Error, signal it
  252. }
  253. }
  254. }
  255. else if(m_state == SMS_GET_HDR_RECEIVED)
  256. {
  257. DBG("Message: %s", line);
  258. size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
  259. std::memcpy( m_msg, line, cpyLen );
  260. m_msg[cpyLen] = '\0';
  261. m_state = SMS_CMD_PROCESSED;
  262. }
  263. else if(m_state == SMS_GET_COUNT_CMD_SENT)
  264. {
  265. DBG("Inbox: %s", line);
  266. int index;
  267. size_t count;
  268. if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
  269. {
  270. if((index > 0) && (index <=4))
  271. {
  272. m_msgInListsCount[index-1] = count;
  273. }
  274. if(index == 4)
  275. {
  276. m_state = SMS_CMD_PROCESSED;
  277. }
  278. }
  279. }
  280. return OK;
  281. }
  282. /*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
  283. {
  284. return OK;
  285. }
  286. int CDMASMSInterface::updateInbox()
  287. {
  288. //Get number of unread/read messages
  289. DBG("Updating inbox");
  290. m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
  291. //Get counts
  292. m_state = SMS_GET_COUNT_CMD_SENT;
  293. int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
  294. if( ret != OK )
  295. {
  296. WARN("AT!CNTSMS returned %d", ret);
  297. m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
  298. m_state = SMS_IDLE;
  299. return NET_PROTOCOL;
  300. }
  301. return OK;
  302. }