]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/sms/GSMSMSInterface.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.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
Imprint / Impressum