Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 16:40:12 by
1.7.2