u-blox USB modems (GSM and CDMA)
Dependencies: CellularUSBModem
Dependents: C027_CANInterfaceComm C027_ModemTransparentUSBCDC_revb UbloxModemHTTPClientTest C027_HTTPClientTest ... more
UbloxModem.cpp
00001 /* UbloxModem.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__ "UbloxModem.cpp" 00023 #endif 00024 00025 #include "core/fwk.h" 00026 #include "sms/GSMSMSInterface.h" 00027 #include "sms/CDMASMSInterface.h" 00028 00029 #include "UbloxModem.h" 00030 00031 UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) : 00032 m_at(atStream), // Construct ATCommandsInterface with the AT serial channel 00033 m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface 00034 m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface 00035 m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface 00036 m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface 00037 m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel 00038 m_ipInit(false), // PPIPInterface connection is initially down 00039 m_smsInit(false), // SMSInterface starts un-initialised 00040 m_ussdInit(false), // USSDInterface starts un-initialised 00041 m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised 00042 m_atOpen(false), // ATCommandsInterface starts in a closed state 00043 m_onePort(pppStream == NULL), 00044 m_type(UNKNOWN) 00045 { 00046 } 00047 00048 00049 genericAtProcessor::genericAtProcessor() 00050 { 00051 i = 0; 00052 str[0] = '\0'; 00053 } 00054 00055 const char* genericAtProcessor::getResponse(void) 00056 { 00057 return str; 00058 } 00059 00060 int genericAtProcessor::onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00061 { 00062 int l = strlen(line); 00063 if (i + l + 2 > sizeof(str)) 00064 return NET_OVERFLOW; 00065 if (i) str[i++] = ','; 00066 strcat(&str[i], line); 00067 i += l; 00068 return OK; 00069 } 00070 00071 int genericAtProcessor::onNewEntryPrompt(ATCommandsInterface* pInst) 00072 { 00073 return OK; 00074 } 00075 00076 class CREGProcessor : public IATCommandsProcessor 00077 { 00078 public: 00079 CREGProcessor(bool gsm) : status(STATUS_REGISTERING) 00080 { 00081 m_gsm = gsm; 00082 } 00083 enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED }; 00084 REGISTERING_STATUS getStatus() 00085 { 00086 return status; 00087 } 00088 const char* getAtCommand() 00089 { 00090 return m_gsm ? "AT+CREG?" : "AT+CSS?"; 00091 } 00092 private: 00093 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00094 { 00095 int r; 00096 if (m_gsm) 00097 { 00098 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) 00099 { 00100 status = (r == 1 || r == 5) ? STATUS_OK : 00101 (r == 0 || r == 2) ? STATUS_REGISTERING : 00102 // (r == 3) ? STATUS_FAILED : 00103 STATUS_FAILED; 00104 } 00105 } 00106 else 00107 { 00108 char bc[3] = ""; 00109 if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1) 00110 { 00111 status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK; 00112 } 00113 } 00114 return OK; 00115 } 00116 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) 00117 { 00118 return OK; 00119 } 00120 volatile REGISTERING_STATUS status; 00121 bool m_gsm; 00122 }; 00123 00124 int UbloxModem::connect(const char* apn, const char* user, const char* password) 00125 { 00126 if( !m_ipInit ) 00127 { 00128 m_ipInit = true; 00129 m_ppp.init(); 00130 } 00131 m_ppp.setup(user, password, (m_type != LISA_C200) ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA); 00132 00133 int ret = init(); 00134 if(ret) 00135 { 00136 return ret; 00137 } 00138 00139 if (m_onePort) 00140 { 00141 m_smsInit = false; //SMS status reset 00142 m_ussdInit = false; //USSD status reset 00143 m_linkMonitorInit = false; //Link monitor status reset 00144 } 00145 00146 ATCommandsInterface::ATResult result; 00147 00148 if(apn != NULL) 00149 { 00150 char cmd[48]; 00151 int tries = 30; 00152 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn); 00153 do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle 00154 { 00155 ret = m_at.executeSimple(cmd, &result); 00156 DBG("Result of command: Err code=%d", ret); 00157 if(ret) 00158 { 00159 Thread::wait(500); 00160 } 00161 } while(ret && --tries); 00162 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00163 DBG("APN set to %s", apn); 00164 } 00165 00166 //Connect 00167 DBG("Connecting"); 00168 if (m_onePort) 00169 { 00170 m_at.close(); // Closing AT parser 00171 m_atOpen = false; //Will need to be reinitialized afterwards 00172 } 00173 00174 DBG("Connecting PPP"); 00175 00176 ret = m_ppp.connect(); 00177 DBG("Result of connect: Err code=%d", ret); 00178 return ret; 00179 } 00180 00181 00182 int UbloxModem::disconnect() 00183 { 00184 DBG("Disconnecting from PPP"); 00185 int ret = m_ppp.disconnect(); 00186 if(ret) 00187 { 00188 ERR("Disconnect returned %d, still trying to disconnect", ret); 00189 } 00190 00191 //Ugly but leave dongle time to recover 00192 Thread::wait(500); 00193 00194 if (m_onePort) 00195 { 00196 //ATCommandsInterface::ATResult result; 00197 DBG("Starting AT thread"); 00198 ret = m_at.open(); 00199 if(ret) 00200 { 00201 return ret; 00202 } 00203 } 00204 00205 DBG("Trying to hangup"); 00206 00207 if (m_onePort) 00208 { 00209 //Reinit AT parser 00210 ret = m_at.init(false); 00211 DBG("Result of command: Err code=%d\n", ret); 00212 if(ret) 00213 { 00214 m_at.close(); // Closing AT parser 00215 DBG("AT Parser closed, could not complete disconnection"); 00216 return NET_TIMEOUT; 00217 } 00218 00219 } 00220 return OK; 00221 } 00222 00223 int UbloxModem::sendSM(const char* number, const char* message) 00224 { 00225 int ret = init(); 00226 if(ret) 00227 { 00228 return ret; 00229 } 00230 00231 ISMSInterface* sms; 00232 if (m_type == LISA_C200) sms = &m_CdmaSms; 00233 else sms = &m_GsmSms; 00234 if(!m_smsInit) 00235 { 00236 ret = sms->init(); 00237 if(ret) 00238 { 00239 return ret; 00240 } 00241 m_smsInit = true; 00242 } 00243 00244 ret = sms->send(number, message); 00245 if(ret) 00246 { 00247 return ret; 00248 } 00249 00250 return OK; 00251 } 00252 00253 int UbloxModem::getSM(char* number, char* message, size_t maxLength) 00254 { 00255 int ret = init(); 00256 if(ret) 00257 { 00258 return ret; 00259 } 00260 00261 ISMSInterface* sms; 00262 if (m_type == LISA_C200) sms = &m_CdmaSms; 00263 else sms = &m_GsmSms; 00264 if(!m_smsInit) 00265 { 00266 ret = sms->init(); 00267 if(ret) 00268 { 00269 return ret; 00270 } 00271 m_smsInit = true; 00272 } 00273 00274 ret = sms->get(number, message, maxLength); 00275 if(ret) 00276 { 00277 return ret; 00278 } 00279 00280 return OK; 00281 } 00282 00283 int UbloxModem::getSMCount(size_t* pCount) 00284 { 00285 int ret = init(); 00286 if(ret) 00287 { 00288 return ret; 00289 } 00290 00291 ISMSInterface* sms; 00292 if (m_type == LISA_C200) sms = &m_CdmaSms; 00293 else sms = &m_GsmSms; 00294 if(!m_smsInit) 00295 { 00296 ret = sms->init(); 00297 if(ret) 00298 { 00299 return ret; 00300 } 00301 m_smsInit = true; 00302 } 00303 00304 ret = sms->getCount(pCount); 00305 if(ret) 00306 { 00307 return ret; 00308 } 00309 00310 return OK; 00311 } 00312 00313 ATCommandsInterface* UbloxModem::getATCommandsInterface() 00314 { 00315 return &m_at; 00316 } 00317 00318 int UbloxModem::init() 00319 { 00320 if(m_atOpen) 00321 { 00322 return OK; 00323 } 00324 00325 DBG("Starting AT thread if needed"); 00326 int ret = m_at.open(); 00327 if(ret) 00328 { 00329 return ret; 00330 } 00331 00332 DBG("Sending initialisation commands"); 00333 ret = m_at.init(false); 00334 if(ret) 00335 { 00336 return ret; 00337 } 00338 00339 00340 ATCommandsInterface::ATResult result; 00341 genericAtProcessor atiProcessor; 00342 ret = m_at.execute("ATI", &atiProcessor, &result); 00343 if (OK != ret) 00344 return ret; 00345 const char* info = atiProcessor.getResponse(); 00346 INFO("Modem Identification [%s]", info); 00347 if (strstr(info, "LISA-C200")) { 00348 m_type = LISA_C200; 00349 m_onePort = true; // force use of only one port 00350 } 00351 else if (strstr(info, "LISA-U200")) { 00352 m_type = LISA_U200; 00353 } 00354 else if (strstr(info, "SARA-G350")) { 00355 m_type = SARA_G350; 00356 } 00357 00358 // enable the network indicator 00359 if (m_type == SARA_G350) { 00360 m_at.executeSimple("AT+UGPIOC=16,2", &result); 00361 } 00362 else if (m_type == LISA_U200) { 00363 m_at.executeSimple("AT+UGPIOC=20,2", &result); 00364 } 00365 else if (m_type == LISA_C200) { 00366 // LISA-C200 02S/22S : GPIO1 do not support network status indication 00367 // m_at.executeSimple("AT+UGPIOC=20,2", &result); 00368 } 00369 INFO("Modem Identification [%s]", info); 00370 00371 CREGProcessor cregProcessor(m_type != LISA_C200); 00372 //Wait for network registration 00373 do 00374 { 00375 DBG("Waiting for network registration"); 00376 ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result); 00377 DBG("Result of command: Err code=%d\n", ret); 00378 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00379 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) 00380 { 00381 Thread::wait(3000); 00382 } 00383 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING); 00384 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) 00385 { 00386 ERR("Registration denied"); 00387 return NET_AUTH; 00388 } 00389 00390 m_atOpen = true; 00391 00392 return OK; 00393 } 00394 00395 int UbloxModem::cleanup() 00396 { 00397 if(m_ppp.isConnected()) 00398 { 00399 WARN("Data connection is still open"); //Try to encourage good behaviour from the user 00400 m_ppp.disconnect(); 00401 } 00402 00403 m_smsInit = false; 00404 m_ussdInit = false; 00405 m_linkMonitorInit = false; 00406 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once 00407 00408 if(m_atOpen) 00409 { 00410 m_at.close(); 00411 m_atOpen = false; 00412 } 00413 00414 return OK; 00415 } 00416 00417 int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength) 00418 { 00419 int ret = init(); 00420 if(ret) 00421 { 00422 return ret; 00423 } 00424 00425 if(!m_ussdInit) 00426 { 00427 ret = m_ussd.init(); 00428 if(ret) 00429 { 00430 return ret; 00431 } 00432 m_ussdInit = true; 00433 } 00434 00435 ret = m_ussd.send(command, result, maxLength); 00436 if(ret) 00437 { 00438 return ret; 00439 } 00440 00441 return OK; 00442 } 00443 00444 int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer) 00445 { 00446 int ret = init(); 00447 if(ret) 00448 { 00449 return ret; 00450 } 00451 00452 if(!m_linkMonitorInit) 00453 { 00454 ret = m_linkMonitor.init(m_type != LISA_C200); 00455 if(ret) 00456 { 00457 return ret; 00458 } 00459 m_linkMonitorInit = true; 00460 } 00461 00462 ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer); 00463 if(ret) 00464 { 00465 return ret; 00466 } 00467 00468 return OK; 00469 } 00470 00471 int UbloxModem::getPhoneNumber(char* phoneNumber) 00472 { 00473 int ret = init(); 00474 if(ret) 00475 { 00476 return ret; 00477 } 00478 00479 if(!m_linkMonitorInit) 00480 { 00481 ret = m_linkMonitor.init(m_type != LISA_C200); 00482 if(ret) 00483 { 00484 return ret; 00485 } 00486 m_linkMonitorInit = true; 00487 } 00488 00489 ret = m_linkMonitor.getPhoneNumber(phoneNumber); 00490 if(ret) 00491 { 00492 return ret; 00493 } 00494 00495 return OK; 00496 } 00497 00498 #include "USBHost.h" 00499 #include "UbloxGSMModemInitializer.h" 00500 #include "UbloxCDMAModemInitializer.h" 00501 00502 UbloxUSBModem::UbloxUSBModem() : 00503 UbloxModem(&m_atStream, &m_pppStream), 00504 m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects) 00505 m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel. 00506 m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel. 00507 m_dongleConnected(false) // Dongle is initially not ready for anything 00508 { 00509 USBHost* host = USBHost::getHostInst(); 00510 m_dongle.addInitializer(new UbloxGSMModemInitializer(host)); 00511 m_dongle.addInitializer(new UbloxCDMAModemInitializer(host)); 00512 } 00513 00514 int UbloxUSBModem::init() 00515 { 00516 if( !m_dongleConnected ) 00517 { 00518 m_dongleConnected = true; 00519 while( !m_dongle.connected() ) 00520 { 00521 m_dongle.tryConnect(); 00522 Thread::wait(10); 00523 } 00524 if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200) 00525 { 00526 INFO("Using a u-blox LISA-U200 3G/WCDMA Modem"); 00527 m_type = LISA_U200; 00528 } 00529 else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200) 00530 { 00531 INFO("Using a u-blox LISA-C200 CDMA Modem"); 00532 m_type = LISA_C200; 00533 m_onePort = true; 00534 } 00535 else 00536 { 00537 WARN("Using an Unknown Dongle"); 00538 } 00539 } 00540 return UbloxModem::init(); 00541 } 00542 00543 int UbloxUSBModem::cleanup() 00544 { 00545 UbloxModem::cleanup(); 00546 m_dongle.disconnect(); 00547 m_dongleConnected = false; 00548 return OK; 00549 } 00550 00551 UbloxSerModem::UbloxSerModem() : 00552 UbloxModem(&m_atStream, NULL), 00553 m_Serial(P0_15/*MDMTXD*/,P0_16/*MDMRXD*/), 00554 m_atStream(m_Serial) 00555 { 00556 m_Serial.baud(115200/*MDMBAUD*/); 00557 m_Serial.set_flow_control(SerialBase::RTSCTS, P0_22/*MDMRTS*/, P0_17/*MDMCTS*/); 00558 } 00559
Generated on Tue Jul 12 2022 19:17:01 by 1.7.2