local fork
Dependencies: Socket USBHostWANDongle_bleedingedge lwip-sys lwip
Fork of VodafoneUSBModem_bleedingedge by
VodafoneUSBModem.cpp
00001 /* VodafoneUSBModem.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 00021 #define __DEBUG__ 0 00022 00023 #ifndef __MODULE__ 00024 #define __MODULE__ "VodafoneUSBModem.cpp" 00025 #endif 00026 00027 #include "core/fwk.h" 00028 00029 #include "VodafoneUSBModem.h" 00030 00031 VodafoneUSBModem::VodafoneUSBModem(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,&m_atStream,&m_at,false), // 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 if( m_powerGatingPin != NC ) 00050 { 00051 power(false); //Dongle will have to be powered on manually 00052 } 00053 } 00054 00055 class CREGProcessor : public IATCommandsProcessor 00056 { 00057 public: 00058 CREGProcessor() : status(STATUS_REGISTERING) 00059 { 00060 00061 } 00062 enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED }; 00063 REGISTERING_STATUS getStatus() 00064 { 00065 return status; 00066 } 00067 private: 00068 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00069 { 00070 int r; 00071 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) 00072 { 00073 switch(r) 00074 { 00075 case 1: 00076 case 5: 00077 status = STATUS_OK; 00078 break; 00079 case 0: 00080 case 2: 00081 status = STATUS_REGISTERING; 00082 break; 00083 case 3: 00084 default: 00085 status = STATUS_FAILED; 00086 break; 00087 } 00088 } 00089 return OK; 00090 } 00091 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) 00092 { 00093 return OK; 00094 } 00095 volatile REGISTERING_STATUS status; 00096 }; 00097 00098 #if 0 00099 class COPSProcessor : public IATCommandsProcessor 00100 { 00101 public: 00102 COPSProcessor() : valid(false) 00103 { 00104 network[0] = '\0'; 00105 apn[0] = '\0'; 00106 bearer[0] = '\0'; 00107 } 00108 char* getNetwork() 00109 { 00110 return network; 00111 } 00112 char* getAPN() 00113 { 00114 return apn; 00115 } 00116 char* getBearer() 00117 { 00118 return bearer; 00119 } 00120 bool isValid() 00121 { 00122 return valid; 00123 } 00124 private: 00125 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) 00126 { 00127 int networkId; 00128 int bearerId; 00129 int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId); 00130 if( s == 2 ) 00131 { 00132 switch(networkId) 00133 { 00134 case 23415: 00135 strcpy(network, "Vodafone UK"); 00136 strcpy(apn, "pp.vodafone.co.uk"); 00137 valid = true; 00138 break; 00139 case 20810: 00140 strcpy(network, "SFR FR"); 00141 strcpy(apn, "websfr"); 00142 valid = true; 00143 break; 00144 default: 00145 break; 00146 } 00147 } 00148 else 00149 { 00150 return OK; 00151 } 00152 switch(bearerId) 00153 { 00154 case 0: strcpy(bearer, "GSM"); break; 00155 case 1: strcpy(bearer, "GSM Compact"); break; 00156 case 2: strcpy(bearer, "UTRAN"); break; 00157 case 3: strcpy(bearer, "GSM w/EGPRS"); break; 00158 case 4: strcpy(bearer, "UTRAN w/HSDPA"); break; 00159 case 5: strcpy(bearer, "UTRAN w/HSUPA"); break; 00160 case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break; 00161 case 7: strcpy(bearer, "E-UTRAN"); break; 00162 00163 default: 00164 break; 00165 } 00166 return OK; 00167 } 00168 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) 00169 { 00170 return OK; 00171 } 00172 char network[24]; 00173 char bearer[24]; 00174 char apn[24]; 00175 volatile bool valid; 00176 }; 00177 #endif 00178 00179 int VodafoneUSBModem::connect(const char* apn, const char* user, const char* password) 00180 { 00181 if( !m_ipInit ) 00182 { 00183 m_ipInit = true; 00184 m_ppp.init(); 00185 } 00186 m_ppp.setup(user, password); 00187 00188 int ret = init(); 00189 if(ret) 00190 { 00191 return ret; 00192 } 00193 00194 #if USE_ONE_PORT 00195 m_smsInit = false; //SMS status reset 00196 m_ussdInit = false; //USSD status reset 00197 m_linkMonitorInit = false; //Link monitor status reset 00198 #endif 00199 00200 ATCommandsInterface::ATResult result; 00201 00202 #if 0 00203 //Get network info & select corresponding APN 00204 COPSProcessor copsProcessor; 00205 DBG("Get network info & select APN from DB"); 00206 ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id 00207 DBG("Result of command: Err code=%d", ret); 00208 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00209 00210 if(!copsProcessor.isValid()) 00211 { 00212 WARN("Connected to an unknown network, try to connect with default parameters"); 00213 DBG("Connected with %s", copsProcessor.getBearer()); 00214 } 00215 else 00216 { 00217 DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer()); 00218 char cmd[48]; 00219 int tries = 3; 00220 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN()); 00221 do //Try 3 times because for some reasons it can fail with the K3772-Z dongle 00222 { 00223 ret = m_at.executeSimple(cmd, &result); 00224 DBG("Result of command: Err code=%d", ret); 00225 } while(ret && --tries); 00226 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00227 DBG("APN set to %s", copsProcessor.getAPN()); 00228 } 00229 #else 00230 if(apn != NULL) 00231 { 00232 char cmd[48]; 00233 int tries = 30; 00234 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn); 00235 do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle 00236 { 00237 ret = m_at.executeSimple(cmd, &result); 00238 DBG("Result of command: Err code=%d", ret); 00239 if(ret) 00240 { 00241 Thread::wait(500); 00242 } 00243 } while(ret && --tries); 00244 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00245 DBG("APN set to %s", apn); 00246 } 00247 #endif 00248 00249 00250 //Connect 00251 DBG("Connecting"); 00252 #if 0 00253 ret = m_at.executeSimple("ATDT *99#", &result); 00254 DBG("Result of command: Err code=%d", ret); 00255 DBG("ATResult: AT return=%d (code %d)", result.result, result.code); 00256 #endif 00257 #if USE_ONE_PORT 00258 m_at.close(); // Closing AT parser 00259 m_atOpen = false; //Will need to be reinitialized afterwards 00260 #endif 00261 00262 #if 0 00263 DBG("AT Parser closed"); 00264 if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT)) 00265 { 00266 ERR("Could not connect"); 00267 return ret; //Could not connect 00268 } 00269 #endif 00270 DBG("Connecting PPP"); 00271 00272 ret = m_ppp.connect(); 00273 DBG("Result of connect: Err code=%d", ret); 00274 return ret; 00275 } 00276 00277 00278 int VodafoneUSBModem::disconnect() 00279 { 00280 DBG("Disconnecting from PPP"); 00281 int ret = m_ppp.disconnect(); 00282 if(ret) 00283 { 00284 ERR("Disconnect returned %d, still trying to disconnect", ret); 00285 } 00286 00287 //Ugly but leave dongle time to recover 00288 Thread::wait(500); 00289 00290 #if USE_ONE_PORT 00291 ATCommandsInterface::ATResult result; 00292 DBG("Starting AT thread"); 00293 ret = m_at.open(); 00294 if(ret) 00295 { 00296 return ret; 00297 } 00298 #endif 00299 00300 DBG("Trying to hangup"); 00301 00302 #if 0 //Does not appear to work 00303 int tries = 10; 00304 do 00305 { 00306 ret = m_at.executeSimple("+++", &result, 1000); 00307 DBG("Result of command: Err code=%d\n", ret); 00308 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00309 } while(tries-- && ret); 00310 if(!ret) 00311 { 00312 ret = m_at.executeSimple("ATH", &result); 00313 DBG("Result of command: Err code=%d\n", ret); 00314 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00315 } 00316 #endif 00317 00318 #if USE_ONE_PORT 00319 //Reinit AT parser 00320 ret = m_at.init(); 00321 DBG("Result of command: Err code=%d\n", ret); 00322 if(ret) 00323 { 00324 m_at.close(); // Closing AT parser 00325 DBG("AT Parser closed, could not complete disconnection"); 00326 return NET_TIMEOUT; 00327 } 00328 00329 #if 0 00330 m_at.close(); // Closing AT parser 00331 DBG("AT Parser closed"); 00332 #endif 00333 #endif 00334 return OK; 00335 } 00336 00337 int VodafoneUSBModem::sendSM(const char* number, const char* message) 00338 { 00339 int ret = init(); 00340 if(ret) 00341 { 00342 return ret; 00343 } 00344 00345 if(!m_smsInit) 00346 { 00347 ret = m_sms.init(); 00348 if(ret) 00349 { 00350 return ret; 00351 } 00352 m_smsInit = true; 00353 } 00354 00355 ret = m_sms.send(number, message); 00356 if(ret) 00357 { 00358 return ret; 00359 } 00360 00361 return OK; 00362 } 00363 00364 int VodafoneUSBModem::getSM(char* number, char* message, size_t maxLength) 00365 { 00366 int ret = init(); 00367 if(ret) 00368 { 00369 return ret; 00370 } 00371 00372 if(!m_smsInit) 00373 { 00374 ret = m_sms.init(); 00375 if(ret) 00376 { 00377 return ret; 00378 } 00379 m_smsInit = true; 00380 } 00381 00382 ret = m_sms.get(number, message, maxLength); 00383 if(ret) 00384 { 00385 return ret; 00386 } 00387 00388 return OK; 00389 } 00390 00391 int VodafoneUSBModem::getSMCount(size_t* pCount) 00392 { 00393 int ret = init(); 00394 if(ret) 00395 { 00396 return ret; 00397 } 00398 00399 if(!m_smsInit) 00400 { 00401 ret = m_sms.init(); 00402 if(ret) 00403 { 00404 return ret; 00405 } 00406 m_smsInit = true; 00407 } 00408 00409 ret = m_sms.getCount(pCount); 00410 if(ret) 00411 { 00412 return ret; 00413 } 00414 00415 return OK; 00416 } 00417 00418 int VodafoneUSBModem::sendUSSD(const char* command, char* result, size_t maxLength) 00419 { 00420 int ret = init(); 00421 if(ret) 00422 { 00423 return ret; 00424 } 00425 00426 if(!m_ussdInit) 00427 { 00428 ret = m_ussd.init(); 00429 if(ret) 00430 { 00431 return ret; 00432 } 00433 m_ussdInit = true; 00434 } 00435 00436 ret = m_ussd.send(command, result, maxLength); 00437 if(ret) 00438 { 00439 return ret; 00440 } 00441 00442 return OK; 00443 } 00444 00445 int VodafoneUSBModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer) 00446 { 00447 DBG("Entering getLinkState."); 00448 int ret = init(); 00449 if(ret) 00450 { 00451 return ret; 00452 } 00453 00454 if(!m_linkMonitorInit) 00455 { 00456 ret = m_linkMonitor.init(); 00457 if(ret) 00458 { 00459 return ret; 00460 } 00461 m_linkMonitorInit = true; 00462 } 00463 00464 ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer); 00465 if(ret) 00466 { 00467 return ret; 00468 } 00469 00470 return OK; 00471 } 00472 00473 00474 ATCommandsInterface* VodafoneUSBModem::getATCommandsInterface() 00475 { 00476 return &m_at; 00477 } 00478 00479 int VodafoneUSBModem::power(bool enable) 00480 { 00481 if( m_powerGatingPin == NC ) 00482 { 00483 return NET_INVALID; //A pin name has not been provided in the constructor 00484 } 00485 00486 if(!enable) //Will force components to re-init 00487 { 00488 cleanup(); 00489 } 00490 00491 DigitalOut powerGatingOut(m_powerGatingPin); 00492 powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable; 00493 00494 return OK; 00495 } 00496 00497 bool VodafoneUSBModem::power() 00498 { 00499 if( m_powerGatingPin == NC ) 00500 { 00501 return true; //Assume power is always on 00502 } 00503 00504 DigitalOut powerGatingOut(m_powerGatingPin); 00505 return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut; 00506 } 00507 00508 int VodafoneUSBModem::init() 00509 { 00510 DBG("Entering init method for the VodafoneUSBModem"); 00511 if( !m_dongleConnected ) 00512 { 00513 DBG("Dongle is not connected"); 00514 if(!power()) 00515 { 00516 //Obviously cannot initialize the dongle if it is disconnected... 00517 ERR("Power is off"); 00518 return NET_INVALID; 00519 } 00520 m_dongleConnected = true; 00521 bool detectConnectedModem = false; // local variable to use to create a while loop that we can break out of - this is used to detect if we can see a modem or not 00522 00523 while(!detectConnectedModem) 00524 { 00525 for (int x=0; x<100;x++) 00526 { 00527 DBG("Trying to connect the dongle"); 00528 m_dongle.tryConnect(); 00529 if (m_dongle.connected()) 00530 { 00531 DBG("Great the dongle is connected - I've tried %d times to connect", x); 00532 detectConnectedModem = true; // OK we can break out this while loop now - the dongle has been connected 00533 break; // Break out of the for loop once the dongle is connected - otherwise try for a while more 00534 } 00535 Thread::wait(1000); 00536 } 00537 if (!detectConnectedModem) 00538 { 00539 // OK we got this far - so give up trying and let someone know you can't see the modem 00540 m_dongleConnected = false; // set the member variable of this object to false - so if we get called again we know we have to try to detect again 00541 ERR("There is no dongle pluged into the board, or the module does not respond. Is the module/modem switched on?"); 00542 Thread:wait(1000); 00543 //DBG("Last ditch attempt to re-initialise the USB Subsystem"); 00544 //m_dongle.init(); 00545 return HARDWARE_NO_RESPONSE; 00546 } 00547 } 00548 00549 00550 //while( !m_dongle.connected() ) 00551 //{ 00552 // DBG("Trying to connect the dongle"); 00553 // m_dongle.tryConnect(); 00554 // Thread::wait(10); 00555 //} 00556 00557 00558 } 00559 00560 if(m_atOpen) 00561 { 00562 return OK; 00563 } 00564 00565 DBG("Starting AT thread if needed"); 00566 int ret = m_at.open(); 00567 if(ret) 00568 { 00569 return ret; 00570 } 00571 00572 DBG("Sending initialisation commands"); 00573 ret = m_at.init(); 00574 if(ret) 00575 { 00576 return ret; 00577 } 00578 00579 if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_VODAFONEK3770) 00580 { 00581 INFO("Using a Vodafone K3770 Dongle"); 00582 #if USE_ONE_PORT 00583 DBG("Configuring unsolicited result codes support properly"); 00584 //Configuring port to enable 3GPP-compliant unsollicited response codes but disable Huawei-specific unsollicited response codes 00585 ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant 00586 if(ret != OK) 00587 { 00588 return NET_PROTOCOL; 00589 } 00590 #else 00591 //Configuring port to disable Huawei-specific unsollicited response codes 00592 ret = m_at.executeSimple("AT^CURC=0", NULL); //Huawei-specific, not 3GPP-compliant 00593 if(ret != OK) 00594 { 00595 return NET_PROTOCOL; 00596 } 00597 #endif 00598 } 00599 else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_VODAFONEK3772Z) 00600 { 00601 INFO("Using a Vodafone K3772-Z Dongle"); 00602 //FIXME this returns %USBMODEM: [0] MODEM DRIVER<CR><LF><CR><LF><CR><LF>OK<CR><LF> which is not a compliant response 00603 /* 00604 //Configuring modem to directly boot into modem mode 00605 ret = m_at.executeSimple("AT%USBMODEM=0", NULL); //Icera-specific, not 3GPP-compliant 00606 if(ret != OK) 00607 { 00608 return NET_PROTOCOL; 00609 } 00610 */ 00611 } 00612 else if(m_dongle.getDongleType()== WAN_DONGLE_TYPE_VODAFONEK3773) 00613 { 00614 INFO("Using a Vodafone K3773 M2M dongle."); 00615 INFO("Disabling sim toolkit notifications"); 00616 ret = m_at.executeSimple("at^stsf=0",NULL); 00617 if(ret!=0) { 00618 return NET_PROTOCOL; 00619 } 00620 INFO("Disabling other unsolicited notifications"); 00621 ret = m_at.executeSimple("at^curc=0",NULL); 00622 if(ret!=0) { 00623 return NET_PROTOCOL; 00624 } 00625 } 00626 else if(m_dongle.getDongleType()== WAN_DONGLE_TYPE_VODAFONEMU509) 00627 { 00628 INFO("Using a Huawei MU509 module."); 00629 m_ppp.setHangupViaATPort(true); 00630 00631 // this modem defaults to sending a delivery receipt to the SM storage area 00632 // need to disable this for the current library to work in a sensible manner 00633 INFO("Disabling SMS delivery receipts"); 00634 ret = m_at.executeSimple("at+csmp=1,,0,0",NULL); 00635 if(ret!=0) { 00636 return NET_PROTOCOL; 00637 } 00638 INFO("Disabling unsolicitied notifications"); 00639 ret = m_at.executeSimple("AT^CURC=0", NULL); //Huawei-specific, not 3GPP-compliant 00640 if(ret != OK) 00641 { 00642 return NET_PROTOCOL; 00643 } 00644 } 00645 else 00646 { 00647 WARN("Using an Unknown Dongle"); 00648 } 00649 00650 ATCommandsInterface::ATResult result; 00651 00652 //Wait for network registration 00653 CREGProcessor cregProcessor; 00654 do 00655 { 00656 DBG("Waiting for network registration"); 00657 ret = m_at.execute("AT+CREG?", &cregProcessor, &result); 00658 DBG("Result of command: Err code=%d\n", ret); 00659 DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code); 00660 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) 00661 { 00662 Thread::wait(3000); 00663 } 00664 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING); 00665 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) 00666 { 00667 ERR("Registration denied"); 00668 return NET_AUTH; 00669 } 00670 00671 m_atOpen = true; 00672 00673 return OK; 00674 } 00675 00676 int VodafoneUSBModem::cleanup() 00677 { 00678 if(m_ppp.isConnected()) 00679 { 00680 WARN("Data connection is still open"); //Try to encourage good behaviour from the user 00681 m_ppp.disconnect(); 00682 } 00683 00684 m_smsInit = false; 00685 m_ussdInit = false; 00686 m_linkMonitorInit = false; 00687 //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once 00688 00689 if(m_atOpen) 00690 { 00691 m_at.close(); 00692 m_atOpen = false; 00693 } 00694 00695 m_dongle.disconnect(); 00696 m_dongleConnected = false; 00697 00698 return OK; 00699 } 00700
Generated on Tue Jul 12 2022 21:41:40 by 1.7.2