| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /* UbloxUSBGSMModem.cpp */
- /* Copyright (C) 2012 mbed.org, MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or
- * substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
- * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #define __DEBUG__ 3
- #ifndef __MODULE__
- #define __MODULE__ "UbloxUSBGSMModem.cpp"
- #endif
- #include "core/fwk.h"
- #include "UbloxUSBGSMModem.h"
- #include "UbloxGSMModemInitializer.h"
- #include "USBHost.h"
- UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) :
- m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
- m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
- m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
- m_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel
- m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
- m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
- m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
- m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
- m_dongleConnected(false), // Dongle is initially not ready for anything
- m_ipInit(false), // PPIPInterface connection is initially down
- m_smsInit(false), // SMSInterface starts un-initialised
- m_ussdInit(false), // USSDInterface starts un-initialised
- m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
- m_atOpen(false), // ATCommandsInterface starts in a closed state
- m_powerGatingPin(powerGatingPin), // set power gating pin
- m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) // set state semantics for power gating pin
- {
- USBHost* host = USBHost::getHostInst();
- m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
- if( m_powerGatingPin != NC )
- {
- power(false); //Dongle will have to be powered on manually
- }
- }
- class CREGProcessor : public IATCommandsProcessor
- {
- public:
- CREGProcessor() : status(STATUS_REGISTERING)
- {
- }
- enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
- REGISTERING_STATUS getStatus()
- {
- return status;
- }
- private:
- virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
- {
- int r;
- if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
- {
- switch(r)
- {
- case 1:
- case 5:
- status = STATUS_OK;
- break;
- case 0:
- case 2:
- status = STATUS_REGISTERING;
- break;
- case 3:
- default:
- status = STATUS_FAILED;
- break;
- }
- }
- return OK;
- }
- virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
- {
- return OK;
- }
- volatile REGISTERING_STATUS status;
- };
- #if 0
- class COPSProcessor : public IATCommandsProcessor
- {
- public:
- COPSProcessor() : valid(false)
- {
- network[0] = '\0';
- apn[0] = '\0';
- bearer[0] = '\0';
- }
- char* getNetwork()
- {
- return network;
- }
- char* getAPN()
- {
- return apn;
- }
- char* getBearer()
- {
- return bearer;
- }
- bool isValid()
- {
- return valid;
- }
- private:
- virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
- {
- int networkId;
- int bearerId;
- int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
- if( s == 2 )
- {
- switch(networkId)
- {
- case 23415:
- strcpy(network, "Vodafone UK");
- strcpy(apn, "pp.vodafone.co.uk");
- valid = true;
- break;
- case 20810:
- strcpy(network, "SFR FR");
- strcpy(apn, "websfr");
- valid = true;
- break;
- default:
- break;
- }
- }
- else
- {
- return OK;
- }
- switch(bearerId)
- {
- case 0: strcpy(bearer, "GSM"); break;
- case 1: strcpy(bearer, "GSM Compact"); break;
- case 2: strcpy(bearer, "UTRAN"); break;
- case 3: strcpy(bearer, "GSM w/EGPRS"); break;
- case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
- case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
- case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
- case 7: strcpy(bearer, "E-UTRAN"); break;
- default:
- break;
- }
- return OK;
- }
- virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
- {
- return OK;
- }
- char network[24];
- char bearer[24];
- char apn[24];
- volatile bool valid;
- };
- #endif
- int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* password)
- {
- if( !m_ipInit )
- {
- m_ipInit = true;
- m_ppp.init();
- }
- m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
- int ret = init();
- if(ret)
- {
- return ret;
- }
- #if USE_ONE_PORT
- m_smsInit = false; //SMS status reset
- m_ussdInit = false; //USSD status reset
- m_linkMonitorInit = false; //Link monitor status reset
- #endif
- ATCommandsInterface::ATResult result;
- #if 0
- //Get network info & select corresponding APN
- COPSProcessor copsProcessor;
- DBG("Get network info & select APN from DB");
- ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id
- DBG("Result of command: Err code=%d", ret);
- DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
- if(!copsProcessor.isValid())
- {
- WARN("Connected to an unknown network, try to connect with default parameters");
- DBG("Connected with %s", copsProcessor.getBearer());
- }
- else
- {
- DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer());
- char cmd[48];
- int tries = 3;
- sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN());
- do //Try 3 times because for some reasons it can fail with the K3772-Z dongle
- {
- ret = m_at.executeSimple(cmd, &result);
- DBG("Result of command: Err code=%d", ret);
- } while(ret && --tries);
- DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
- DBG("APN set to %s", copsProcessor.getAPN());
- }
- #else
- if(apn != NULL)
- {
- char cmd[48];
- int tries = 30;
- sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
- do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
- {
- ret = m_at.executeSimple(cmd, &result);
- DBG("Result of command: Err code=%d", ret);
- if(ret)
- {
- Thread::wait(500);
- }
- } while(ret && --tries);
- DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
- DBG("APN set to %s", apn);
- }
- #endif
- //Connect
- DBG("Connecting");
- #if 0
- ret = m_at.executeSimple("ATDT *99#", &result);
- DBG("Result of command: Err code=%d", ret);
- DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
- #endif
- #if USE_ONE_PORT
- m_at.close(); // Closing AT parser
- m_atOpen = false; //Will need to be reinitialized afterwards
- #endif
- #if 0
- DBG("AT Parser closed");
- if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT))
- {
- ERR("Could not connect");
- return ret; //Could not connect
- }
- #endif
- DBG("Connecting PPP");
- ret = m_ppp.connect();
- DBG("Result of connect: Err code=%d", ret);
- return ret;
- }
- int UbloxUSBGSMModem::disconnect()
- {
- DBG("Disconnecting from PPP");
- int ret = m_ppp.disconnect();
- if(ret)
- {
- ERR("Disconnect returned %d, still trying to disconnect", ret);
- }
- //Ugly but leave dongle time to recover
- Thread::wait(500);
- #if USE_ONE_PORT
- ATCommandsInterface::ATResult result;
- DBG("Starting AT thread");
- ret = m_at.open();
- if(ret)
- {
- return ret;
- }
- #endif
- DBG("Trying to hangup");
- #if 0 //Does not appear to work
- int tries = 10;
- do
- {
- ret = m_at.executeSimple("+++", &result, 1000);
- DBG("Result of command: Err code=%d\n", ret);
- DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
- } while(tries-- && ret);
- if(!ret)
- {
- ret = m_at.executeSimple("ATH", &result);
- DBG("Result of command: Err code=%d\n", ret);
- DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
- }
- #endif
- #if USE_ONE_PORT
- //Reinit AT parser
- ret = m_at.init();
- DBG("Result of command: Err code=%d\n", ret);
- if(ret)
- {
- m_at.close(); // Closing AT parser
- DBG("AT Parser closed, could not complete disconnection");
- return NET_TIMEOUT;
- }
- #if 0
- m_at.close(); // Closing AT parser
- DBG("AT Parser closed");
- #endif
- #endif
- return OK;
- }
- int UbloxUSBGSMModem::sendSM(const char* number, const char* message)
- {
- int ret = init();
- if(ret)
- {
- return ret;
- }
- if(!m_smsInit)
- {
- ret = m_sms.init();
- if(ret)
- {
- return ret;
- }
- m_smsInit = true;
- }
- ret = m_sms.send(number, message);
- if(ret)
- {
- return ret;
- }
- return OK;
- }
- int UbloxUSBGSMModem::getSM(char* number, char* message, size_t maxLength)
- {
- int ret = init();
- if(ret)
- {
- return ret;
- }
- if(!m_smsInit)
- {
- ret = m_sms.init();
- if(ret)
- {
- return ret;
- }
- m_smsInit = true;
- }
- ret = m_sms.get(number, message, maxLength);
- if(ret)
- {
- return ret;
- }
- return OK;
- }
- int UbloxUSBGSMModem::getSMCount(size_t* pCount)
- {
- int ret = init();
- if(ret)
- {
- return ret;
- }
- if(!m_smsInit)
- {
- ret = m_sms.init();
- if(ret)
- {
- return ret;
- }
- m_smsInit = true;
- }
- ret = m_sms.getCount(pCount);
- if(ret)
- {
- return ret;
- }
- return OK;
- }
- int UbloxUSBGSMModem::sendUSSD(const char* command, char* result, size_t maxLength)
- {
- int ret = init();
- if(ret)
- {
- return ret;
- }
- if(!m_ussdInit)
- {
- ret = m_ussd.init();
- if(ret)
- {
- return ret;
- }
- m_ussdInit = true;
- }
- ret = m_ussd.send(command, result, maxLength);
- if(ret)
- {
- return ret;
- }
- return OK;
- }
- int UbloxUSBGSMModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
- {
- int ret = init();
- if(ret)
- {
- return ret;
- }
-
- if(!m_linkMonitorInit)
- {
- ret = m_linkMonitor.init();
- if(ret)
- {
- return ret;
- }
- m_linkMonitorInit = true;
- }
- ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
- if(ret)
- {
- return ret;
- }
- return OK;
- }
- ATCommandsInterface* UbloxUSBGSMModem::getATCommandsInterface()
- {
- return &m_at;
- }
- int UbloxUSBGSMModem::power(bool enable)
- {
- if( m_powerGatingPin == NC )
- {
- return NET_INVALID; //A pin name has not been provided in the constructor
- }
- if(!enable) //Will force components to re-init
- {
- cleanup();
- }
-
- DigitalOut powerGatingOut(m_powerGatingPin);
- powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
- return OK;
- }
- bool UbloxUSBGSMModem::power()
- {
- if( m_powerGatingPin == NC )
- {
- return true; //Assume power is always on
- }
-
- DigitalOut powerGatingOut(m_powerGatingPin);
- return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
- }
- int UbloxUSBGSMModem::init()
- {
- if( !m_dongleConnected )
- {
- if(!power())
- {
- //Obviously cannot initialize the dongle if it is disconnected...
- ERR("Power is off");
- return NET_INVALID;
- }
- m_dongleConnected = true;
- while( !m_dongle.connected() )
- {
- m_dongle.tryConnect();
- Thread::wait(10);
- }
- }
- if(m_atOpen)
- {
- return OK;
- }
-
- DBG("Starting AT thread if needed");
- int ret = m_at.open();
- if(ret)
- {
- return ret;
- }
-
- DBG("Sending initialisation commands");
- ret = m_at.init();
- if(ret)
- {
- return ret;
- }
- if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
- {
- INFO("Using a u-blox LISA-U");
- }
- else
- {
- WARN("Using an Unknown Dongle");
- }
- ATCommandsInterface::ATResult result;
- //Wait for network registration
- CREGProcessor cregProcessor;
- do
- {
- DBG("Waiting for network registration");
- ret = m_at.execute("AT+CREG?", &cregProcessor, &result);
- DBG("Result of command: Err code=%d\n", ret);
- DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
- if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
- {
- Thread::wait(3000);
- }
- } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
- if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
- {
- ERR("Registration denied");
- return NET_AUTH;
- }
- m_atOpen = true;
- return OK;
- }
- int UbloxUSBGSMModem::cleanup()
- {
- if(m_ppp.isConnected())
- {
- WARN("Data connection is still open"); //Try to encourage good behaviour from the user
- m_ppp.disconnect();
- }
-
- m_smsInit = false;
- m_ussdInit = false;
- m_linkMonitorInit = false;
- //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
-
- if(m_atOpen)
- {
- m_at.close();
- m_atOpen = false;
- }
-
- m_dongle.disconnect();
- m_dongleConnected = false;
-
- return OK;
- }
|