]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / net / cellular / CellularModem / sms / GSMSMSInterface.cpp
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
20 #define __DEBUG__ 2
21 #ifndef __MODULE__
22 #define __MODULE__ "GSMSMSInterface.cpp"
23 #endif
24
25 #include "core/fwk.h"
26
27 #include "GSMSMSInterface.h"
28
29 #include <cstdio>
30 #include <cstring>
31
32 #define DEFAULT_TIMEOUT 10000
33
34 GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
35 {
36   m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
37 }
38
39 int GSMSMSInterface::init()
40 {
41   m_msgRefListCount = 0;
42   m_needsUpdate = true;
43   m_state = SMS_IDLE;
44
45   DBG("Set format");
46   //Set Text mode format
47   int ret = m_pIf->executeSimple("AT+CMGF=1", NULL, DEFAULT_TIMEOUT);
48   if(ret != OK)
49   {
50     return NET_PROTOCOL;
51   }
52
53   DBG("Setup new messages indication");
54   //Setup new messages indication
55   ret = m_pIf->executeSimple("AT+CNMI=2,1,0,0,0", NULL, DEFAULT_TIMEOUT);
56   if(ret != OK)
57   {
58     return NET_PROTOCOL;
59   }
60
61   DBG("Try to fetch inbox");
62   m_inboxMtx.lock();
63   if( m_needsUpdate )
64   {
65     ret = updateInbox(); //Fetch existing messages references
66     if(ret)
67     {
68       m_inboxMtx.unlock();
69       return NET_PROTOCOL;
70     }
71   }
72   m_inboxMtx.unlock();
73
74   DBG("Initialization done");
75   return OK;
76 }
77
78 int GSMSMSInterface::send(const char* number, const char* message)
79 {
80   if( strlen(number) > 16 )
81   {
82     return NET_INVALID; //Number too long to match 3GPP spec
83   }
84
85   int ret;
86
87   //Prepare infos
88   m_state = SMS_SEND_CMD_SENT;
89   m_msg = (char*) message;
90
91   DBG("Send SM");
92   //Send command
93   char cmd[32];
94   std::sprintf(cmd, "AT+CMGS=\"%s\"", number);
95   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
96
97   if( (ret != OK) || (m_state != SMS_CMD_PROCESSED) )
98   {
99     WARN("ret %d, state %d", ret, m_state);
100     m_state = SMS_IDLE;
101     return NET_PROTOCOL;
102   }
103
104   DBG("SM sent");
105   m_state = SMS_IDLE;
106   return OK;
107 }
108
109
110 int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
111 {
112   if( maxLength < 1  )
113   {
114     return NET_INVALID; //Buffer too short
115   }
116
117   int ret;
118
119   DBG("Get next message");
120   m_inboxMtx.lock();
121   if( ((m_msgRefListCount == 0) && m_needsUpdate) || ((m_msgRefListCount > 0) && (m_msgRefList[0] == -1)) )
122   {
123     DBG("Message list count is 0 and needs updating or next index is unknown, calling updateInbox()");
124     ret = updateInbox();
125     
126     if (ret)
127     {
128       m_inboxMtx.unlock();
129       return ret;
130     }
131   }
132   
133   DBG("%d messages to read", m_msgRefListCount);
134
135   if(m_msgRefListCount == 0)
136   {
137     m_inboxMtx.unlock();
138     DBG("Message list count is 0, I think it's empty and returning.");
139     return NET_EMPTY; //No message to read
140   }
141
142   //Prepare infos
143   m_state = SMS_GET_CMD_SENT;
144   m_msisdn = (char*) number;
145   m_msg = (char*) message;
146   m_maxMsgLength = maxLength;
147
148   DBG("Get SMS");
149   //List command
150   char cmd[32];
151   std::sprintf(cmd, "AT+CMGR=%d", m_msgRefList[0]);
152   ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
153   if( ret != OK )
154   {
155     WARN("AT+CMGR returned %d", ret);
156     m_state = SMS_IDLE;
157     m_inboxMtx.unlock();
158     return NET_PROTOCOL;
159   }
160
161   if (m_state != SMS_CMD_PROCESSED)
162   {
163     WARN("State variable is not 'SMS_CMD_PROCESSED' - returning 'NET_EMPTY'");
164   }
165
166   DBG("Deleting message from index number: %d", m_msgRefList[0] );
167   //Delete message from outbox
168   std::sprintf(cmd, "AT+CMGD=%d", m_msgRefList[0]);
169   ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
170   if(ret != OK)
171   {
172     ERR("Could not delete message");
173   }
174   //Remove message from list
175   std::memmove(&m_msgRefList[0], &m_msgRefList[1], MIN(m_msgRefListCount-1,MAX_SM-1)*sizeof(m_msgRefList[0]));
176   m_msgRefListCount--;
177   
178   if(m_msgRefListCount > MAX_SM - 1) //Last message index is unknown, so put -1 to tell the lib to fetch it when needed
179   {
180     DBG("Last message index is unknown, will need to be updated");
181     m_msgRefList[MAX_SM - 1] = -1;
182   }
183   
184   DBG("%d messages to read", m_msgRefListCount);
185   
186   if (m_state != SMS_CMD_PROCESSED)
187   {
188     m_state = SMS_IDLE;
189     m_inboxMtx.unlock();
190     return NET_EMPTY;
191   }
192   
193   m_state = SMS_IDLE;
194   m_inboxMtx.unlock();
195
196   return OK;
197 }
198
199
200 int GSMSMSInterface::getCount(size_t* pCount)
201 {
202   int ret;
203
204   m_inboxMtx.lock();
205   if( m_needsUpdate )
206   {
207     ret = updateInbox();
208     if(ret)
209     {
210       m_inboxMtx.unlock();
211       return NET_PROTOCOL;
212     }
213   }
214
215   *pCount = m_msgRefListCount;
216   m_inboxMtx.unlock();
217
218   return OK;
219 }
220
221
222 /*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
223 {
224   if(m_state == SMS_SEND_CMD_SENT)
225   {
226     if( std::sscanf(line, "+CMGS: %*d") == 0 )
227     {
228       DBG("SM sent");
229       m_state = SMS_CMD_PROCESSED;
230     }
231   }
232   else if(m_state == SMS_GET_CMD_SENT)
233   {
234     DBG("Header: %s", line);
235     if( std::sscanf(line, "+CMGR: %*[^,],\"%16[^\"]\"", m_msisdn) == 1 ) //Get message ref
236     {
237       m_state = SMS_GET_HDR_RECEIVED;
238     }
239   }
240   else if(m_state == SMS_GET_HDR_RECEIVED)
241   {
242     DBG("Message: %s", line);
243     size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
244     std::memcpy( m_msg, line, cpyLen );
245     m_msg[cpyLen] = '\0';
246     m_state = SMS_CMD_PROCESSED;
247   }
248   else if(m_state == SMS_GET_COUNT_CMD_SENT)
249   {
250     DBG("Header: %s", line);
251     int msgRef;
252     if( std::sscanf(line, "+CMGL: %d,\"REC", &msgRef) == 1 ) //Filter on REC READ and REC UNREAD messages 
253     {
254       m_state = SMS_GET_COUNT_HDR_RECEIVED;
255       //Add message to list
256       if(m_msgRefListCount < MAX_SM)
257       {
258         m_msgRefList[m_msgRefListCount] = msgRef;
259       }
260       m_msgRefListCount++; //Always count message
261       DBG("m_msgRefListCount=%d",m_msgRefListCount);
262     }
263   }
264   else if(m_state == SMS_GET_COUNT_HDR_RECEIVED)
265   {
266     DBG("Message (debug only): %s", line); //For debug only
267     m_state = SMS_GET_COUNT_CMD_SENT;
268   }
269   return OK;
270 }
271
272 /*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
273 {
274   if(m_state == SMS_SEND_CMD_SENT)
275   {
276     char* crPtr = strchr(m_msg, CR);
277     if(crPtr != NULL)
278     {
279       int crPos = crPtr - m_msg;
280       //Replace m_inputBuf[crPos] with null-terminating char
281       m_msg[crPos] = '\x0';
282
283       //If there is a CR char, split message there
284
285       //Do print the message
286       int ret = pInst->sendData(m_msg);
287       if(ret)
288       {
289         return ret;
290       }
291
292       char cr[2] = {CR, '\0'};
293       ret = pInst->sendData(cr);
294       if(ret)
295       {
296         return ret;
297       }
298
299       m_msg += crPos;
300
301       if(m_msg[0] == LF)
302       {
303         m_msg++; //Discard LF char as well
304       }
305
306       return NET_MOREINFO;
307     }
308     else
309     {
310       //Do print the message
311       pInst->sendData(m_msg);
312       return OK;
313     }
314   }
315
316   return OK;
317 }
318
319 /*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
320 {
321   DBG("AT code is %s", atCode);
322   if( strcmp("+CMTI", atCode) == 0 )
323   {
324     return true;
325   }
326
327   DBG("Not handled");
328   return false;
329 }
330
331 /*virtual*/ void GSMSMSInterface::onDispatchStart()
332 {
333     
334 }
335
336 /*virtual*/ void GSMSMSInterface::onDispatchStop()
337 {
338     
339 }
340
341 /*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
342 {
343   return "AT+CNMI=2,1,0,0,0";
344 }
345
346 /*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
347 {
348   return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
349 }
350
351 /*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
352 {
353   if( strcmp("+CMTI", atCode) != 0 )
354   {
355     return; //Not supported
356   }
357
358   DBG("Unsollicited result code: %s - %s", atCode, evt);
359
360   //Get index
361   int msgRef;
362   if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) || 
363      ( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
364   {
365     DBG("Adding message to list (ref %d)", msgRef);
366     if(m_inboxMtx.trylock())
367     {
368       //Add message to list
369       if(m_msgRefListCount < MAX_SM)
370       {
371         m_msgRefList[m_msgRefListCount] = msgRef;
372       }
373       m_msgRefListCount++; //Always count message
374       m_inboxMtx.unlock();
375     }
376     else
377     {
378       WARN("Could not get lock");
379       m_needsUpdate = true;
380     }
381   }
382 }
383
384 int GSMSMSInterface::updateInbox()
385 {
386   //Get memory indexes of unread messages
387
388   DBG("Updating inbox");
389   m_msgRefListCount = 0; //Reset list
390   m_needsUpdate = false; //Assume we won't need update after this routine (can be set to true by an incoming SM event)
391
392   //First list the "REC READ" messages that were not processed in the previous session
393   m_state = SMS_GET_COUNT_CMD_SENT;
394   int ret = m_pIf->execute("AT+CMGL=\"REC READ\"", this, NULL, DEFAULT_TIMEOUT);
395   if( ret != OK )
396   {
397     WARN("AT+CMGL returned %d", ret);
398     m_state = SMS_IDLE;
399     m_msgRefListCount = 0; //List could be invalid
400     m_needsUpdate = true;
401     return NET_PROTOCOL;
402   }
403   
404   //Now list the "REC UNREAD" messages that were received by the modem since
405   m_state = SMS_GET_COUNT_CMD_SENT;
406   ret = m_pIf->execute("AT+CMGL=\"REC UNREAD\"", this, NULL, DEFAULT_TIMEOUT);
407   if( ret != OK )
408   {
409     WARN("AT+CMGL returned %d", ret);
410     m_state = SMS_IDLE;
411     m_msgRefListCount = 0; //List could be invalid
412     m_needsUpdate = true;
413     return NET_PROTOCOL;
414   }
415
416   DBG("%d incoming messages in inbox", m_msgRefListCount);
417
418   m_state = SMS_IDLE;
419
420   return OK;
421 }
422
423