]> git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/UbloxUSBModem/UbloxModem.cpp
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
[tmk_keyboard.git] / tmk_core / tool / mbed / mbed-sdk / libraries / net / cellular / UbloxUSBModem / UbloxModem.cpp
1 /* UbloxModem.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__ 3
21 #ifndef __MODULE__
22 #define __MODULE__ "UbloxModem.cpp"
23 #endif
24
25 #include "core/fwk.h"
26 #include "sms/GSMSMSInterface.h"
27 #include "sms/CDMASMSInterface.h"
28
29 #include "UbloxModem.h"
30
31 UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
32 m_at(atStream), // Construct ATCommandsInterface with the AT serial channel
33 m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
34 m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
35 m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
36 m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
37 m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel
38 m_ipInit(false), // PPIPInterface connection is initially down
39 m_smsInit(false), // SMSInterface starts un-initialised
40 m_ussdInit(false), // USSDInterface starts un-initialised
41 m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
42 m_atOpen(false), // ATCommandsInterface starts in a closed state
43 m_onePort(pppStream == NULL),
44 m_type(UNKNOWN)
45 {
46 }
47
48
49 genericAtProcessor::genericAtProcessor()
50 {
51 i = 0;
52 str[0] = '\0';
53 }
54
55 const char* genericAtProcessor::getResponse(void)
56 {
57 return str;
58 }
59
60 int genericAtProcessor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
61 {
62 int l = strlen(line);
63 if (i + l + 2 > sizeof(str))
64 return NET_OVERFLOW;
65 if (i) str[i++] = ',';
66 strcat(&str[i], line);
67 i += l;
68 return OK;
69 }
70
71 int genericAtProcessor::onNewEntryPrompt(ATCommandsInterface* pInst)
72 {
73 return OK;
74 }
75
76 class CREGProcessor : public IATCommandsProcessor
77 {
78 public:
79 CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
80 {
81 m_gsm = gsm;
82 }
83 enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
84 REGISTERING_STATUS getStatus()
85 {
86 return status;
87 }
88 const char* getAtCommand()
89 {
90 return m_gsm ? "AT+CREG?" : "AT+CSS?";
91 }
92 private:
93 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
94 {
95 int r;
96 if (m_gsm)
97 {
98 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
99 {
100 status = (r == 1 || r == 5) ? STATUS_OK :
101 (r == 0 || r == 2) ? STATUS_REGISTERING :
102 // (r == 3) ? STATUS_FAILED :
103 STATUS_FAILED;
104 }
105 }
106 else
107 {
108 char bc[3] = "";
109 if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
110 {
111 status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
112 }
113 }
114 return OK;
115 }
116 virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
117 {
118 return OK;
119 }
120 volatile REGISTERING_STATUS status;
121 bool m_gsm;
122 };
123
124 int UbloxModem::connect(const char* apn, const char* user, const char* password)
125 {
126 if( !m_ipInit )
127 {
128 m_ipInit = true;
129 m_ppp.init();
130 }
131 m_ppp.setup(user, password, (m_type != LISA_C200) ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
132
133 int ret = init();
134 if(ret)
135 {
136 return ret;
137 }
138
139 if (m_onePort)
140 {
141 m_smsInit = false; //SMS status reset
142 m_ussdInit = false; //USSD status reset
143 m_linkMonitorInit = false; //Link monitor status reset
144 }
145
146 ATCommandsInterface::ATResult result;
147
148 if(apn != NULL)
149 {
150 char cmd[48];
151 int tries = 30;
152 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
153 do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
154 {
155 ret = m_at.executeSimple(cmd, &result);
156 DBG("Result of command: Err code=%d", ret);
157 if(ret)
158 {
159 Thread::wait(500);
160 }
161 } while(ret && --tries);
162 DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
163 DBG("APN set to %s", apn);
164 }
165
166 //Connect
167 DBG("Connecting");
168 if (m_onePort)
169 {
170 m_at.close(); // Closing AT parser
171 m_atOpen = false; //Will need to be reinitialized afterwards
172 }
173
174 DBG("Connecting PPP");
175
176 ret = m_ppp.connect();
177 DBG("Result of connect: Err code=%d", ret);
178 return ret;
179 }
180
181
182 int UbloxModem::disconnect()
183 {
184 DBG("Disconnecting from PPP");
185 int ret = m_ppp.disconnect();
186 if(ret)
187 {
188 ERR("Disconnect returned %d, still trying to disconnect", ret);
189 }
190
191 //Ugly but leave dongle time to recover
192 Thread::wait(500);
193
194 if (m_onePort)
195 {
196 //ATCommandsInterface::ATResult result;
197 DBG("Starting AT thread");
198 ret = m_at.open();
199 if(ret)
200 {
201 return ret;
202 }
203 }
204
205 DBG("Trying to hangup");
206
207 if (m_onePort)
208 {
209 //Reinit AT parser
210 ret = m_at.init(false);
211 DBG("Result of command: Err code=%d\n", ret);
212 if(ret)
213 {
214 m_at.close(); // Closing AT parser
215 DBG("AT Parser closed, could not complete disconnection");
216 return NET_TIMEOUT;
217 }
218
219 }
220 return OK;
221 }
222
223 int UbloxModem::sendSM(const char* number, const char* message)
224 {
225 int ret = init();
226 if(ret)
227 {
228 return ret;
229 }
230
231 ISMSInterface* sms;
232 if (m_type == LISA_C200) sms = &m_CdmaSms;
233 else sms = &m_GsmSms;
234 if(!m_smsInit)
235 {
236 ret = sms->init();
237 if(ret)
238 {
239 return ret;
240 }
241 m_smsInit = true;
242 }
243
244 ret = sms->send(number, message);
245 if(ret)
246 {
247 return ret;
248 }
249
250 return OK;
251 }
252
253 int UbloxModem::getSM(char* number, char* message, size_t maxLength)
254 {
255 int ret = init();
256 if(ret)
257 {
258 return ret;
259 }
260
261 ISMSInterface* sms;
262 if (m_type == LISA_C200) sms = &m_CdmaSms;
263 else sms = &m_GsmSms;
264 if(!m_smsInit)
265 {
266 ret = sms->init();
267 if(ret)
268 {
269 return ret;
270 }
271 m_smsInit = true;
272 }
273
274 ret = sms->get(number, message, maxLength);
275 if(ret)
276 {
277 return ret;
278 }
279
280 return OK;
281 }
282
283 int UbloxModem::getSMCount(size_t* pCount)
284 {
285 int ret = init();
286 if(ret)
287 {
288 return ret;
289 }
290
291 ISMSInterface* sms;
292 if (m_type == LISA_C200) sms = &m_CdmaSms;
293 else sms = &m_GsmSms;
294 if(!m_smsInit)
295 {
296 ret = sms->init();
297 if(ret)
298 {
299 return ret;
300 }
301 m_smsInit = true;
302 }
303
304 ret = sms->getCount(pCount);
305 if(ret)
306 {
307 return ret;
308 }
309
310 return OK;
311 }
312
313 ATCommandsInterface* UbloxModem::getATCommandsInterface()
314 {
315 return &m_at;
316 }
317
318 int UbloxModem::init()
319 {
320 if(m_atOpen)
321 {
322 return OK;
323 }
324
325 DBG("Starting AT thread if needed");
326 int ret = m_at.open();
327 if(ret)
328 {
329 return ret;
330 }
331
332 DBG("Sending initialisation commands");
333 ret = m_at.init(false);
334 if(ret)
335 {
336 return ret;
337 }
338
339
340 ATCommandsInterface::ATResult result;
341 genericAtProcessor atiProcessor;
342 ret = m_at.execute("ATI", &atiProcessor, &result);
343 if (OK != ret)
344 return ret;
345 const char* info = atiProcessor.getResponse();
346 INFO("Modem Identification [%s]", info);
347 if (strstr(info, "LISA-C200")) {
348 m_type = LISA_C200;
349 m_onePort = true; // force use of only one port
350 }
351 else if (strstr(info, "LISA-U200")) {
352 m_type = LISA_U200;
353 }
354 else if (strstr(info, "SARA-G350")) {
355 m_type = SARA_G350;
356 }
357
358 // enable the network indicator
359 if (m_type == SARA_G350) {
360 m_at.executeSimple("AT+UGPIOC=16,2", &result);
361 }
362 else if (m_type == LISA_U200) {
363 m_at.executeSimple("AT+UGPIOC=20,2", &result);
364 }
365 else if (m_type == LISA_C200) {
366 // LISA-C200 02S/22S : GPIO1 do not support network status indication
367 // m_at.executeSimple("AT+UGPIOC=20,2", &result);
368 }
369 INFO("Modem Identification [%s]", info);
370
371 CREGProcessor cregProcessor(m_type != LISA_C200);
372 //Wait for network registration
373 do
374 {
375 DBG("Waiting for network registration");
376 ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
377 DBG("Result of command: Err code=%d\n", ret);
378 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
379 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
380 {
381 Thread::wait(3000);
382 }
383 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
384 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
385 {
386 ERR("Registration denied");
387 return NET_AUTH;
388 }
389
390 m_atOpen = true;
391
392 return OK;
393 }
394
395 int UbloxModem::cleanup()
396 {
397 if(m_ppp.isConnected())
398 {
399 WARN("Data connection is still open"); //Try to encourage good behaviour from the user
400 m_ppp.disconnect();
401 }
402
403 m_smsInit = false;
404 m_ussdInit = false;
405 m_linkMonitorInit = false;
406 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
407
408 if(m_atOpen)
409 {
410 m_at.close();
411 m_atOpen = false;
412 }
413
414 return OK;
415 }
416
417 int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
418 {
419 int ret = init();
420 if(ret)
421 {
422 return ret;
423 }
424
425 if(!m_ussdInit)
426 {
427 ret = m_ussd.init();
428 if(ret)
429 {
430 return ret;
431 }
432 m_ussdInit = true;
433 }
434
435 ret = m_ussd.send(command, result, maxLength);
436 if(ret)
437 {
438 return ret;
439 }
440
441 return OK;
442 }
443
444 int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
445 {
446 int ret = init();
447 if(ret)
448 {
449 return ret;
450 }
451
452 if(!m_linkMonitorInit)
453 {
454 ret = m_linkMonitor.init(m_type != LISA_C200);
455 if(ret)
456 {
457 return ret;
458 }
459 m_linkMonitorInit = true;
460 }
461
462 ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
463 if(ret)
464 {
465 return ret;
466 }
467
468 return OK;
469 }
470
471 int UbloxModem::getPhoneNumber(char* phoneNumber)
472 {
473 int ret = init();
474 if(ret)
475 {
476 return ret;
477 }
478
479 if(!m_linkMonitorInit)
480 {
481 ret = m_linkMonitor.init(m_type != LISA_C200);
482 if(ret)
483 {
484 return ret;
485 }
486 m_linkMonitorInit = true;
487 }
488
489 ret = m_linkMonitor.getPhoneNumber(phoneNumber);
490 if(ret)
491 {
492 return ret;
493 }
494
495 return OK;
496 }
497
498 #include "USBHost.h"
499 #include "UbloxGSMModemInitializer.h"
500 #include "UbloxCDMAModemInitializer.h"
501
502 UbloxUSBModem::UbloxUSBModem() :
503 UbloxModem(&m_atStream, &m_pppStream),
504 m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
505 m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
506 m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
507 m_dongleConnected(false) // Dongle is initially not ready for anything
508 {
509 USBHost* host = USBHost::getHostInst();
510 m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
511 m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
512 }
513
514 int UbloxUSBModem::init()
515 {
516 if( !m_dongleConnected )
517 {
518 m_dongleConnected = true;
519 while( !m_dongle.connected() )
520 {
521 m_dongle.tryConnect();
522 Thread::wait(10);
523 }
524 if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
525 {
526 INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
527 m_type = LISA_U200;
528 }
529 else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
530 {
531 INFO("Using a u-blox LISA-C200 CDMA Modem");
532 m_type = LISA_C200;
533 m_onePort = true;
534 }
535 else
536 {
537 WARN("Using an Unknown Dongle");
538 }
539 }
540 return UbloxModem::init();
541 }
542
543 int UbloxUSBModem::cleanup()
544 {
545 UbloxModem::cleanup();
546 m_dongle.disconnect();
547 m_dongleConnected = false;
548 return OK;
549 }
550
551 UbloxSerModem::UbloxSerModem() :
552 UbloxModem(&m_atStream, NULL),
553 m_Serial(P0_15/*MDMTXD*/,P0_16/*MDMRXD*/),
554 m_atStream(m_Serial)
555 {
556 m_Serial.baud(115200/*MDMBAUD*/);
557 m_Serial.set_flow_control(SerialBase::RTSCTS, P0_22/*MDMRTS*/, P0_17/*MDMCTS*/);
558 }
559
Imprint / Impressum