u-blox USB modems (GSM and CDMA)
Dependencies: CellularUSBModem
Dependents: C027_CANInterfaceComm C027_ModemTransparentUSBCDC_revb UbloxModemHTTPClientTest C027_HTTPClientTest ... more
UbloxUSBGSMModem.cpp
00001 /* UbloxUSBGSMModem.cpp */ 00002 /* Copyright (C) 2012 mbed.org, MIT License 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00007 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00008 * furnished to do so, subject to the following conditions: 00009 * 00010 * The above copyright notice and this permission notice shall be included in all copies or 00011 * substantial portions of the Software. 00012 * 00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00018 */ 00019 00020 #define __DEBUG__ 3 00021 #ifndef __MODULE__ 00022 #define __MODULE__ "UbloxUSBGSMModem.cpp" 00023 #endif 00024 00025 #include "core/fwk.h" 00026 00027 #include "UbloxUSBGSMModem.h" 00028 #include "UbloxGSMModemInitializer.h" 00029 #include "USBHost.h" 00030 00031 UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) : 00032 m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects) 00033 m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel. 00034 m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel. 00035 m_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel 00036 m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface 00037 m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface 00038 m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface 00039 m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel 00040 m_dongleConnected(false), // Dongle is initially not ready for anything 00041 m_ipInit(false), // PPIPInterface connection is initially down 00042 m_smsInit(false), // SMSInterface starts un-initialised 00043 m_ussdInit(false), // USSDInterface starts un-initialised 00044 m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised 00045 m_atOpen(false), // ATCommandsInterface starts in a closed state 00046 m_powerGatingPin(powerGatingPin), // set power gating pin 00047 m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) // set state semantics for power gating pin 00048 { 00049 USBHost* host = USBHost::getHostInst(); 00050 m_dongle.addInitializer(new UbloxGSMModemInitializer(host)); 00051 if( m_powerGatingPin != NC ) 00052 { 00053 power(false); //Dongle will have to be powered on manually 00054 } 00055 } 00056 00057 class CREGProcessor : public IATCommandsProcessor 00058 { 00059 public: 00060 CREGProcessor() : status(STATUS_REGISTERING) 00061 { 00062 00063 } 00064 enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED }; 00065 REGISTERING_STATUS getStatus() 00066 { 00067 return status; 00068 } 00069 private: 00070 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00071 { 00072 int r; 00073 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) 00074 { 00075 switch(r) 00076 { 00077 case 1: 00078 case 5: 00079 status = STATUS_OK; 00080 break; 00081 case 0: 00082 case 2: 00083 status = STATUS_REGISTERING; 00084 break; 00085 case 3: 00086 default: 00087 status = STATUS_FAILED; 00088 break; 00089 } 00090 } 00091 return OK; 00092 } 00093 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) 00094 { 00095 return OK; 00096 } 00097 volatile REGISTERING_STATUS status; 00098 }; 00099 00100 #if 0 00101 class COPSProcessor : public IATCommandsProcessor 00102 { 00103 public: 00104 COPSProcessor() : valid(false) 00105 { 00106 network[0] = '\0'; 00107 apn[0] = '\0'; 00108 bearer[0] = '\0'; 00109 } 00110 char* getNetwork() 00111 { 00112 return network; 00113 } 00114 char* getAPN() 00115 { 00116 return apn; 00117 } 00118 char* getBearer() 00119 { 00120 return bearer; 00121 } 00122 bool isValid() 00123 { 00124 return valid; 00125 } 00126 private: 00127 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00128 { 00129 int networkId; 00130 int bearerId; 00131 int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId); 00132 if( s == 2 ) 00133 { 00134 switch(networkId) 00135 { 00136 case 23415: 00137 strcpy(network, "Vodafone UK"); 00138 strcpy(apn, "pp.vodafone.co.uk"); 00139 valid = true; 00140 break; 00141 case 20810: 00142 strcpy(network, "SFR FR"); 00143 strcpy(apn, "websfr"); 00144 valid = true; 00145 break; 00146 default: 00147 break; 00148 } 00149 } 00150 else 00151 { 00152 return OK; 00153 } 00154 switch(bearerId) 00155 { 00156 case 0: strcpy(bearer, "GSM"); break; 00157 case 1: strcpy(bearer, "GSM Compact"); break; 00158 case 2: strcpy(bearer, "UTRAN"); break; 00159 case 3: strcpy(bearer, "GSM w/EGPRS"); break; 00160 case 4: strcpy(bearer, "UTRAN w/HSDPA"); break; 00161 case 5: strcpy(bearer, "UTRAN w/HSUPA"); break; 00162 case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break; 00163 case 7: strcpy(bearer, "E-UTRAN"); break; 00164 00165 default: 00166 break; 00167 } 00168 return OK; 00169 } 00170 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) 00171 { 00172 return OK; 00173 } 00174 char network[24]; 00175 char bearer[24]; 00176 char apn[24]; 00177 volatile bool valid; 00178 }; 00179 #endif 00180 00181 int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* password) 00182 { 00183 if( !m_ipInit ) 00184 { 00185 m_ipInit = true; 00186 m_ppp.init(); 00187 } 00188 m_ppp.setup(user, password, DEFAULT_MSISDN_GSM); 00189 00190 int ret = init(); 00191 if(ret) 00192 { 00193 return ret; 00194 } 00195 00196 #if USE_ONE_PORT 00197 m_smsInit = false; //SMS status reset 00198 m_ussdInit = false; //USSD status reset 00199 m_linkMonitorInit = false; //Link monitor status reset 00200 #endif 00201 00202 ATCommandsInterface::ATResult result; 00203 00204 #if 0 00205 //Get network info & select corresponding APN 00206 COPSProcessor copsProcessor; 00207 DBG("Get network info & select APN from DB"); 00208 ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id 00209 DBG("Result of command: Err code=%d", ret); 00210 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00211 00212 if(!copsProcessor.isValid()) 00213 { 00214 WARN("Connected to an unknown network, try to connect with default parameters"); 00215 DBG("Connected with %s", copsProcessor.getBearer()); 00216 } 00217 else 00218 { 00219 DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer()); 00220 char cmd[48]; 00221 int tries = 3; 00222 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN()); 00223 do //Try 3 times because for some reasons it can fail with the K3772-Z dongle 00224 { 00225 ret = m_at.executeSimple(cmd, &result); 00226 DBG("Result of command: Err code=%d", ret); 00227 } while(ret && --tries); 00228 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00229 DBG("APN set to %s", copsProcessor.getAPN()); 00230 } 00231 #else 00232 if(apn != NULL) 00233 { 00234 char cmd[48]; 00235 int tries = 30; 00236 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn); 00237 do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle 00238 { 00239 ret = m_at.executeSimple(cmd, &result); 00240 DBG("Result of command: Err code=%d", ret); 00241 if(ret) 00242 { 00243 Thread::wait(500); 00244 } 00245 } while(ret && --tries); 00246 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00247 DBG("APN set to %s", apn); 00248 } 00249 #endif 00250 00251 00252 //Connect 00253 DBG("Connecting"); 00254 #if 0 00255 ret = m_at.executeSimple("ATDT *99#", &result); 00256 DBG("Result of command: Err code=%d", ret); 00257 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00258 #endif 00259 #if USE_ONE_PORT 00260 m_at.close(); // Closing AT parser 00261 m_atOpen = false; //Will need to be reinitialized afterwards 00262 #endif 00263 00264 #if 0 00265 DBG("AT Parser closed"); 00266 if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT)) 00267 { 00268 ERR("Could not connect"); 00269 return ret; //Could not connect 00270 } 00271 #endif 00272 DBG("Connecting PPP"); 00273 00274 ret = m_ppp.connect(); 00275 DBG("Result of connect: Err code=%d", ret); 00276 return ret; 00277 } 00278 00279 00280 int UbloxUSBGSMModem::disconnect() 00281 { 00282 DBG("Disconnecting from PPP"); 00283 int ret = m_ppp.disconnect(); 00284 if(ret) 00285 { 00286 ERR("Disconnect returned %d, still trying to disconnect", ret); 00287 } 00288 00289 //Ugly but leave dongle time to recover 00290 Thread::wait(500); 00291 00292 #if USE_ONE_PORT 00293 ATCommandsInterface::ATResult result; 00294 DBG("Starting AT thread"); 00295 ret = m_at.open(); 00296 if(ret) 00297 { 00298 return ret; 00299 } 00300 #endif 00301 00302 DBG("Trying to hangup"); 00303 00304 #if 0 //Does not appear to work 00305 int tries = 10; 00306 do 00307 { 00308 ret = m_at.executeSimple("+++", &result, 1000); 00309 DBG("Result of command: Err code=%d\n", ret); 00310 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00311 } while(tries-- && ret); 00312 if(!ret) 00313 { 00314 ret = m_at.executeSimple("ATH", &result); 00315 DBG("Result of command: Err code=%d\n", ret); 00316 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00317 } 00318 #endif 00319 00320 #if USE_ONE_PORT 00321 //Reinit AT parser 00322 ret = m_at.init(); 00323 DBG("Result of command: Err code=%d\n", ret); 00324 if(ret) 00325 { 00326 m_at.close(); // Closing AT parser 00327 DBG("AT Parser closed, could not complete disconnection"); 00328 return NET_TIMEOUT; 00329 } 00330 00331 #if 0 00332 m_at.close(); // Closing AT parser 00333 DBG("AT Parser closed"); 00334 #endif 00335 #endif 00336 return OK; 00337 } 00338 00339 int UbloxUSBGSMModem::sendSM(const char* number, const char* message) 00340 { 00341 int ret = init(); 00342 if(ret) 00343 { 00344 return ret; 00345 } 00346 00347 if(!m_smsInit) 00348 { 00349 ret = m_sms.init(); 00350 if(ret) 00351 { 00352 return ret; 00353 } 00354 m_smsInit = true; 00355 } 00356 00357 ret = m_sms.send(number, message); 00358 if(ret) 00359 { 00360 return ret; 00361 } 00362 00363 return OK; 00364 } 00365 00366 int UbloxUSBGSMModem::getSM(char* number, char* message, size_t maxLength) 00367 { 00368 int ret = init(); 00369 if(ret) 00370 { 00371 return ret; 00372 } 00373 00374 if(!m_smsInit) 00375 { 00376 ret = m_sms.init(); 00377 if(ret) 00378 { 00379 return ret; 00380 } 00381 m_smsInit = true; 00382 } 00383 00384 ret = m_sms.get(number, message, maxLength); 00385 if(ret) 00386 { 00387 return ret; 00388 } 00389 00390 return OK; 00391 } 00392 00393 int UbloxUSBGSMModem::getSMCount(size_t* pCount) 00394 { 00395 int ret = init(); 00396 if(ret) 00397 { 00398 return ret; 00399 } 00400 00401 if(!m_smsInit) 00402 { 00403 ret = m_sms.init(); 00404 if(ret) 00405 { 00406 return ret; 00407 } 00408 m_smsInit = true; 00409 } 00410 00411 ret = m_sms.getCount(pCount); 00412 if(ret) 00413 { 00414 return ret; 00415 } 00416 00417 return OK; 00418 } 00419 00420 int UbloxUSBGSMModem::sendUSSD(const char* command, char* result, size_t maxLength) 00421 { 00422 int ret = init(); 00423 if(ret) 00424 { 00425 return ret; 00426 } 00427 00428 if(!m_ussdInit) 00429 { 00430 ret = m_ussd.init(); 00431 if(ret) 00432 { 00433 return ret; 00434 } 00435 m_ussdInit = true; 00436 } 00437 00438 ret = m_ussd.send(command, result, maxLength); 00439 if(ret) 00440 { 00441 return ret; 00442 } 00443 00444 return OK; 00445 } 00446 00447 int UbloxUSBGSMModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer) 00448 { 00449 int ret = init(); 00450 if(ret) 00451 { 00452 return ret; 00453 } 00454 00455 if(!m_linkMonitorInit) 00456 { 00457 ret = m_linkMonitor.init(); 00458 if(ret) 00459 { 00460 return ret; 00461 } 00462 m_linkMonitorInit = true; 00463 } 00464 00465 ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer); 00466 if(ret) 00467 { 00468 return ret; 00469 } 00470 00471 return OK; 00472 } 00473 00474 00475 ATCommandsInterface* UbloxUSBGSMModem::getATCommandsInterface() 00476 { 00477 return &m_at; 00478 } 00479 00480 int UbloxUSBGSMModem::power(bool enable) 00481 { 00482 if( m_powerGatingPin == NC ) 00483 { 00484 return NET_INVALID; //A pin name has not been provided in the constructor 00485 } 00486 00487 if(!enable) //Will force components to re-init 00488 { 00489 cleanup(); 00490 } 00491 00492 DigitalOut powerGatingOut(m_powerGatingPin); 00493 powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable; 00494 00495 return OK; 00496 } 00497 00498 bool UbloxUSBGSMModem::power() 00499 { 00500 if( m_powerGatingPin == NC ) 00501 { 00502 return true; //Assume power is always on 00503 } 00504 00505 DigitalOut powerGatingOut(m_powerGatingPin); 00506 return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut; 00507 } 00508 00509 int UbloxUSBGSMModem::init() 00510 { 00511 if( !m_dongleConnected ) 00512 { 00513 if(!power()) 00514 { 00515 //Obviously cannot initialize the dongle if it is disconnected... 00516 ERR("Power is off"); 00517 return NET_INVALID; 00518 } 00519 m_dongleConnected = true; 00520 while( !m_dongle.connected() ) 00521 { 00522 m_dongle.tryConnect(); 00523 Thread::wait(10); 00524 } 00525 } 00526 00527 if(m_atOpen) 00528 { 00529 return OK; 00530 } 00531 00532 DBG("Starting AT thread if needed"); 00533 int ret = m_at.open(); 00534 if(ret) 00535 { 00536 return ret; 00537 } 00538 00539 DBG("Sending initialisation commands"); 00540 ret = m_at.init(); 00541 if(ret) 00542 { 00543 return ret; 00544 } 00545 00546 if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200) 00547 { 00548 INFO("Using a u-blox LISA-U"); 00549 } 00550 else 00551 { 00552 WARN("Using an Unknown Dongle"); 00553 } 00554 00555 ATCommandsInterface::ATResult result; 00556 00557 //Wait for network registration 00558 CREGProcessor cregProcessor; 00559 do 00560 { 00561 DBG("Waiting for network registration"); 00562 ret = m_at.execute("AT+CREG?", &cregProcessor, &result); 00563 DBG("Result of command: Err code=%d\n", ret); 00564 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00565 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) 00566 { 00567 Thread::wait(3000); 00568 } 00569 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING); 00570 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) 00571 { 00572 ERR("Registration denied"); 00573 return NET_AUTH; 00574 } 00575 00576 m_atOpen = true; 00577 00578 return OK; 00579 } 00580 00581 int UbloxUSBGSMModem::cleanup() 00582 { 00583 if(m_ppp.isConnected()) 00584 { 00585 WARN("Data connection is still open"); //Try to encourage good behaviour from the user 00586 m_ppp.disconnect(); 00587 } 00588 00589 m_smsInit = false; 00590 m_ussdInit = false; 00591 m_linkMonitorInit = false; 00592 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once 00593 00594 if(m_atOpen) 00595 { 00596 m_at.close(); 00597 m_atOpen = false; 00598 } 00599 00600 m_dongle.disconnect(); 00601 m_dongleConnected = false; 00602 00603 return OK; 00604 } 00605
Generated on Tue Jul 12 2022 19:17:01 by 1.7.2