2 /* Copyright (C) 2012 mbed.org, MIT License
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:
10 * The above copyright notice and this permission notice shall be included in all copies or
11 * substantial portions of the Software.
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.
22 #define __MODULE__ "UbloxModem.cpp"
26 #include "sms/GSMSMSInterface.h"
27 #include "sms/CDMASMSInterface.h"
29 #include "UbloxModem.h"
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
),
49 genericAtProcessor::genericAtProcessor()
55 const char* genericAtProcessor::getResponse(void)
60 int genericAtProcessor::onNewATResponseLine(ATCommandsInterface
* pInst
, const char* line
)
63 if (i
+ l
+ 2 > sizeof(str
))
65 if (i
) str
[i
++] = ',';
66 strcat(&str
[i
], line
);
71 int genericAtProcessor::onNewEntryPrompt(ATCommandsInterface
* pInst
)
76 class CREGProcessor
: public IATCommandsProcessor
79 CREGProcessor(bool gsm
) : status(STATUS_REGISTERING
)
83 enum REGISTERING_STATUS
{ STATUS_REGISTERING
, STATUS_OK
, STATUS_FAILED
};
84 REGISTERING_STATUS
getStatus()
88 const char* getAtCommand()
90 return m_gsm
? "AT+CREG?" : "AT+CSS?";
93 virtual int onNewATResponseLine(ATCommandsInterface
* pInst
, const char* line
)
98 if( sscanf(line
, "+CREG: %*d,%d", &r
) == 1 )
100 status
= (r
== 1 || r
== 5) ? STATUS_OK
:
101 (r
== 0 || r
== 2) ? STATUS_REGISTERING
:
102 // (r == 3) ? STATUS_FAILED :
109 if(sscanf(line
, "%*s %*c,%2s,%*d",bc
)==1)
111 status
= (strcmp("Z", bc
) == 0) ? STATUS_REGISTERING
: STATUS_OK
;
116 virtual int onNewEntryPrompt(ATCommandsInterface
* pInst
)
120 volatile REGISTERING_STATUS status
;
124 int UbloxModem::connect(const char* apn
, const char* user
, const char* password
)
131 m_ppp
.setup(user
, password
, (m_type
!= LISA_C200
) ? DEFAULT_MSISDN_GSM
: DEFAULT_MSISDN_CDMA
);
141 m_smsInit
= false; //SMS status reset
142 m_ussdInit
= false; //USSD status reset
143 m_linkMonitorInit
= false; //Link monitor status reset
146 ATCommandsInterface::ATResult result
;
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
155 ret
= m_at
.executeSimple(cmd
, &result
);
156 DBG("Result of command: Err code=%d", ret
);
161 } while(ret
&& --tries
);
162 DBG("ATResult: AT return=%d (code %d)", result
.result
, result
.code
);
163 DBG("APN set to %s", apn
);
170 m_at
.close(); // Closing AT parser
171 m_atOpen
= false; //Will need to be reinitialized afterwards
174 DBG("Connecting PPP");
176 ret
= m_ppp
.connect();
177 DBG("Result of connect: Err code=%d", ret
);
182 int UbloxModem::disconnect()
184 DBG("Disconnecting from PPP");
185 int ret
= m_ppp
.disconnect();
188 ERR("Disconnect returned %d, still trying to disconnect", ret
);
191 //Ugly but leave dongle time to recover
196 //ATCommandsInterface::ATResult result;
197 DBG("Starting AT thread");
205 DBG("Trying to hangup");
210 ret
= m_at
.init(false);
211 DBG("Result of command: Err code=%d\n", ret
);
214 m_at
.close(); // Closing AT parser
215 DBG("AT Parser closed, could not complete disconnection");
223 int UbloxModem::sendSM(const char* number
, const char* message
)
232 if (m_type
== LISA_C200
) sms
= &m_CdmaSms
;
233 else sms
= &m_GsmSms
;
244 ret
= sms
->send(number
, message
);
253 int UbloxModem::getSM(char* number
, char* message
, size_t maxLength
)
262 if (m_type
== LISA_C200
) sms
= &m_CdmaSms
;
263 else sms
= &m_GsmSms
;
274 ret
= sms
->get(number
, message
, maxLength
);
283 int UbloxModem::getSMCount(size_t* pCount
)
292 if (m_type
== LISA_C200
) sms
= &m_CdmaSms
;
293 else sms
= &m_GsmSms
;
304 ret
= sms
->getCount(pCount
);
313 ATCommandsInterface
* UbloxModem::getATCommandsInterface()
318 int UbloxModem::init()
325 DBG("Starting AT thread if needed");
326 int ret
= m_at
.open();
332 DBG("Sending initialisation commands");
333 ret
= m_at
.init(false);
340 ATCommandsInterface::ATResult result
;
341 genericAtProcessor atiProcessor
;
342 ret
= m_at
.execute("ATI", &atiProcessor
, &result
);
345 const char* info
= atiProcessor
.getResponse();
346 INFO("Modem Identification [%s]", info
);
347 if (strstr(info
, "LISA-C200")) {
349 m_onePort
= true; // force use of only one port
351 else if (strstr(info
, "LISA-U200")) {
354 else if (strstr(info
, "SARA-G350")) {
358 // enable the network indicator
359 if (m_type
== SARA_G350
) {
360 m_at
.executeSimple("AT+UGPIOC=16,2", &result
);
362 else if (m_type
== LISA_U200
) {
363 m_at
.executeSimple("AT+UGPIOC=20,2", &result
);
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);
369 INFO("Modem Identification [%s]", info
);
371 CREGProcessor
cregProcessor(m_type
!= LISA_C200
);
372 //Wait for network registration
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
)
383 } while(cregProcessor
.getStatus() == CREGProcessor::STATUS_REGISTERING
);
384 if(cregProcessor
.getStatus() == CREGProcessor::STATUS_FAILED
)
386 ERR("Registration denied");
395 int UbloxModem::cleanup()
397 if(m_ppp
.isConnected())
399 WARN("Data connection is still open"); //Try to encourage good behaviour from the user
405 m_linkMonitorInit
= false;
406 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
417 int UbloxModem::sendUSSD(const char* command
, char* result
, size_t maxLength
)
435 ret
= m_ussd
.send(command
, result
, maxLength
);
444 int UbloxModem::getLinkState(int* pRssi
, LinkMonitor::REGISTRATION_STATE
* pRegistrationState
, LinkMonitor::BEARER
* pBearer
)
452 if(!m_linkMonitorInit
)
454 ret
= m_linkMonitor
.init(m_type
!= LISA_C200
);
459 m_linkMonitorInit
= true;
462 ret
= m_linkMonitor
.getState(pRssi
, pRegistrationState
, pBearer
);
471 int UbloxModem::getPhoneNumber(char* phoneNumber
)
479 if(!m_linkMonitorInit
)
481 ret
= m_linkMonitor
.init(m_type
!= LISA_C200
);
486 m_linkMonitorInit
= true;
489 ret
= m_linkMonitor
.getPhoneNumber(phoneNumber
);
499 #include "UbloxGSMModemInitializer.h"
500 #include "UbloxCDMAModemInitializer.h"
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
509 USBHost
* host
= USBHost::getHostInst();
510 m_dongle
.addInitializer(new UbloxGSMModemInitializer(host
));
511 m_dongle
.addInitializer(new UbloxCDMAModemInitializer(host
));
514 int UbloxUSBModem::init()
516 if( !m_dongleConnected
)
518 m_dongleConnected
= true;
519 while( !m_dongle
.connected() )
521 m_dongle
.tryConnect();
524 if(m_dongle
.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200
)
526 INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
529 else if(m_dongle
.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200
)
531 INFO("Using a u-blox LISA-C200 CDMA Modem");
537 WARN("Using an Unknown Dongle");
540 return UbloxModem::init();
543 int UbloxUSBModem::cleanup()
545 UbloxModem::cleanup();
546 m_dongle
.disconnect();
547 m_dongleConnected
= false;
551 UbloxSerModem::UbloxSerModem() :
552 UbloxModem(&m_atStream
, NULL
),
553 m_Serial(P0_15
/*MDMTXD*/,P0_16
/*MDMRXD*/),
556 m_Serial
.baud(115200/*MDMBAUD*/);
557 m_Serial
.set_flow_control(SerialBase::RTSCTS
, P0_22
/*MDMRTS*/, P0_17
/*MDMCTS*/);