1 /* UbloxUSBGSMModem.cpp */
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__ "UbloxUSBGSMModem.cpp"
27 #include "UbloxUSBGSMModem.h"
28 #include "UbloxGSMModemInitializer.h"
31 UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin
/*= NC*/, bool powerGatingOnWhenPinHigh
/* = true*/) :
32 m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
33 m_atStream(m_dongle
.getSerial(1)), // AT commands are sent down one serial channel.
34 m_pppStream(m_dongle
.getSerial(0)), // PPP connections are managed via another serial channel.
35 m_at(&m_atStream
), // Construct ATCommandsInterface with the AT serial channel
36 m_sms(&m_at
), // Construct SMSInterface with the ATCommandsInterface
37 m_ussd(&m_at
), // Construct USSDInterface with the ATCommandsInterface
38 m_linkMonitor(&m_at
), // Construct LinkMonitor with the ATCommandsInterface
39 m_ppp(&m_pppStream
), // Construct PPPIPInterface with the PPP serial channel
40 m_dongleConnected(false), // Dongle is initially not ready for anything
41 m_ipInit(false), // PPIPInterface connection is initially down
42 m_smsInit(false), // SMSInterface starts un-initialised
43 m_ussdInit(false), // USSDInterface starts un-initialised
44 m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
45 m_atOpen(false), // ATCommandsInterface starts in a closed state
46 m_powerGatingPin(powerGatingPin
), // set power gating pin
47 m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh
) // set state semantics for power gating pin
49 USBHost
* host
= USBHost::getHostInst();
50 m_dongle
.addInitializer(new UbloxGSMModemInitializer(host
));
51 if( m_powerGatingPin
!= NC
)
53 power(false); //Dongle will have to be powered on manually
57 class CREGProcessor
: public IATCommandsProcessor
60 CREGProcessor() : status(STATUS_REGISTERING
)
64 enum REGISTERING_STATUS
{ STATUS_REGISTERING
, STATUS_OK
, STATUS_FAILED
};
65 REGISTERING_STATUS
getStatus()
70 virtual int onNewATResponseLine(ATCommandsInterface
* pInst
, const char* line
)
73 if( sscanf(line
, "+CREG: %*d,%d", &r
) == 1 )
83 status
= STATUS_REGISTERING
;
87 status
= STATUS_FAILED
;
93 virtual int onNewEntryPrompt(ATCommandsInterface
* pInst
)
97 volatile REGISTERING_STATUS status
;
101 class COPSProcessor
: public IATCommandsProcessor
104 COPSProcessor() : valid(false)
127 virtual int onNewATResponseLine(ATCommandsInterface
* pInst
, const char* line
)
131 int s
= sscanf(line
, "+COPS: %*d,%*d,\"%d\",%d", &networkId
, &bearerId
);
137 strcpy(network
, "Vodafone UK");
138 strcpy(apn
, "pp.vodafone.co.uk");
142 strcpy(network
, "SFR FR");
143 strcpy(apn
, "websfr");
156 case 0: strcpy(bearer
, "GSM"); break;
157 case 1: strcpy(bearer
, "GSM Compact"); break;
158 case 2: strcpy(bearer
, "UTRAN"); break;
159 case 3: strcpy(bearer
, "GSM w/EGPRS"); break;
160 case 4: strcpy(bearer
, "UTRAN w/HSDPA"); break;
161 case 5: strcpy(bearer
, "UTRAN w/HSUPA"); break;
162 case 6: strcpy(bearer
, "UTRAN w/HSDPA and HSUPA"); break;
163 case 7: strcpy(bearer
, "E-UTRAN"); break;
170 virtual int onNewEntryPrompt(ATCommandsInterface
* pInst
)
181 int UbloxUSBGSMModem::connect(const char* apn
, const char* user
, const char* password
)
188 m_ppp
.setup(user
, password
, DEFAULT_MSISDN_GSM
);
197 m_smsInit
= false; //SMS status reset
198 m_ussdInit
= false; //USSD status reset
199 m_linkMonitorInit
= false; //Link monitor status reset
202 ATCommandsInterface::ATResult result
;
205 //Get network info & select corresponding APN
206 COPSProcessor copsProcessor
;
207 DBG("Get network info & select APN from DB");
208 ret
= m_at
.execute("AT+COPS=,2;+COPS?", &copsProcessor
, &result
); //Configure to get operator's info in numeric code & get operator's id
209 DBG("Result of command: Err code=%d", ret
);
210 DBG("ATResult: AT return=%d (code %d)", result
.result
, result
.code
);
212 if(!copsProcessor
.isValid())
214 WARN("Connected to an unknown network, try to connect with default parameters");
215 DBG("Connected with %s", copsProcessor
.getBearer());
219 DBG("Connected to %s with %s", copsProcessor
.getNetwork(), copsProcessor
.getBearer());
222 sprintf(cmd
, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor
.getAPN());
223 do //Try 3 times because for some reasons it can fail with the K3772-Z dongle
225 ret
= m_at
.executeSimple(cmd
, &result
);
226 DBG("Result of command: Err code=%d", ret
);
227 } while(ret
&& --tries
);
228 DBG("ATResult: AT return=%d (code %d)", result
.result
, result
.code
);
229 DBG("APN set to %s", copsProcessor
.getAPN());
236 sprintf(cmd
, "AT+CGDCONT=1,\"IP\",\"%s\"", apn
);
237 do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
239 ret
= m_at
.executeSimple(cmd
, &result
);
240 DBG("Result of command: Err code=%d", ret
);
245 } while(ret
&& --tries
);
246 DBG("ATResult: AT return=%d (code %d)", result
.result
, result
.code
);
247 DBG("APN set to %s", apn
);
255 ret
= m_at
.executeSimple("ATDT *99#", &result
);
256 DBG("Result of command: Err code=%d", ret
);
257 DBG("ATResult: AT return=%d (code %d)", result
.result
, result
.code
);
260 m_at
.close(); // Closing AT parser
261 m_atOpen
= false; //Will need to be reinitialized afterwards
265 DBG("AT Parser closed");
266 if( (ret
!=NET_MOREINFO
) || (result
.result
!= ATCommandsInterface::ATResult::AT_CONNECT
))
268 ERR("Could not connect");
269 return ret
; //Could not connect
272 DBG("Connecting PPP");
274 ret
= m_ppp
.connect();
275 DBG("Result of connect: Err code=%d", ret
);
280 int UbloxUSBGSMModem::disconnect()
282 DBG("Disconnecting from PPP");
283 int ret
= m_ppp
.disconnect();
286 ERR("Disconnect returned %d, still trying to disconnect", ret
);
289 //Ugly but leave dongle time to recover
293 ATCommandsInterface::ATResult result
;
294 DBG("Starting AT thread");
302 DBG("Trying to hangup");
304 #if 0 //Does not appear to work
308 ret
= m_at
.executeSimple("+++", &result
, 1000);
309 DBG("Result of command: Err code=%d\n", ret
);
310 DBG("ATResult: AT return=%d (code %d)\n", result
.result
, result
.code
);
311 } while(tries
-- && ret
);
314 ret
= m_at
.executeSimple("ATH", &result
);
315 DBG("Result of command: Err code=%d\n", ret
);
316 DBG("ATResult: AT return=%d (code %d)\n", result
.result
, result
.code
);
323 DBG("Result of command: Err code=%d\n", ret
);
326 m_at
.close(); // Closing AT parser
327 DBG("AT Parser closed, could not complete disconnection");
332 m_at
.close(); // Closing AT parser
333 DBG("AT Parser closed");
339 int UbloxUSBGSMModem::sendSM(const char* number
, const char* message
)
357 ret
= m_sms
.send(number
, message
);
366 int UbloxUSBGSMModem::getSM(char* number
, char* message
, size_t maxLength
)
384 ret
= m_sms
.get(number
, message
, maxLength
);
393 int UbloxUSBGSMModem::getSMCount(size_t* pCount
)
411 ret
= m_sms
.getCount(pCount
);
420 int UbloxUSBGSMModem::sendUSSD(const char* command
, char* result
, size_t maxLength
)
438 ret
= m_ussd
.send(command
, result
, maxLength
);
447 int UbloxUSBGSMModem::getLinkState(int* pRssi
, LinkMonitor::REGISTRATION_STATE
* pRegistrationState
, LinkMonitor::BEARER
* pBearer
)
455 if(!m_linkMonitorInit
)
457 ret
= m_linkMonitor
.init();
462 m_linkMonitorInit
= true;
465 ret
= m_linkMonitor
.getState(pRssi
, pRegistrationState
, pBearer
);
475 ATCommandsInterface
* UbloxUSBGSMModem::getATCommandsInterface()
480 int UbloxUSBGSMModem::power(bool enable
)
482 if( m_powerGatingPin
== NC
)
484 return NET_INVALID
; //A pin name has not been provided in the constructor
487 if(!enable
) //Will force components to re-init
492 DigitalOut
powerGatingOut(m_powerGatingPin
);
493 powerGatingOut
= m_powerGatingOnWhenPinHigh
?enable
:!enable
;
498 bool UbloxUSBGSMModem::power()
500 if( m_powerGatingPin
== NC
)
502 return true; //Assume power is always on
505 DigitalOut
powerGatingOut(m_powerGatingPin
);
506 return m_powerGatingOnWhenPinHigh
?powerGatingOut
:!powerGatingOut
;
509 int UbloxUSBGSMModem::init()
511 if( !m_dongleConnected
)
515 //Obviously cannot initialize the dongle if it is disconnected...
519 m_dongleConnected
= true;
520 while( !m_dongle
.connected() )
522 m_dongle
.tryConnect();
532 DBG("Starting AT thread if needed");
533 int ret
= m_at
.open();
539 DBG("Sending initialisation commands");
546 if(m_dongle
.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200
)
548 INFO("Using a u-blox LISA-U");
552 WARN("Using an Unknown Dongle");
555 ATCommandsInterface::ATResult result
;
557 //Wait for network registration
558 CREGProcessor cregProcessor
;
561 DBG("Waiting for network registration");
562 ret
= m_at
.execute("AT+CREG?", &cregProcessor
, &result
);
563 DBG("Result of command: Err code=%d\n", ret
);
564 DBG("ATResult: AT return=%d (code %d)\n", result
.result
, result
.code
);
565 if(cregProcessor
.getStatus() == CREGProcessor::STATUS_REGISTERING
)
569 } while(cregProcessor
.getStatus() == CREGProcessor::STATUS_REGISTERING
);
570 if(cregProcessor
.getStatus() == CREGProcessor::STATUS_FAILED
)
572 ERR("Registration denied");
581 int UbloxUSBGSMModem::cleanup()
583 if(m_ppp
.isConnected())
585 WARN("Data connection is still open"); //Try to encourage good behaviour from the user
591 m_linkMonitorInit
= false;
592 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
600 m_dongle
.disconnect();
601 m_dongleConnected
= false;