Connection Manager library for u-blox cellular modules. It manages the modem for keeping data connection always active.
Diff: CNManager.cpp
- Revision:
- 0:86284a262735
- Child:
- 1:29ad1d1ac1f9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CNManager.cpp Tue Jan 12 09:08:15 2016 +0000 @@ -0,0 +1,283 @@ +#include "CNManager.h" + +#include "CNData.h" +#include "CNUtil.h" +#include "CNLib.h" +#include "CNReg.h" + +//! internal state +typedef enum { + MNG_NOT_INIT = 0, //!< not initiated + MNG_RADIO_OFF, //!< radio is off + MNG_RADIO_ON, //!< radio is on + MNG_IDLE, //!< idle + MNG_DATA_UP, //!< data connection is active + MNG_ERROR_RESET, //!< reset + MNG_ERROR_STUCK //!< unrecoverable error +} MngState; + + +static MngState state = MNG_NOT_INIT; //!< Manager state +static bool moduleOn; //!< Module power requested power status +static bool dataOn; +static CNLib* cnLib; //!< Pointer to CN library +static char simPin[10]; //!< Sim Pin +static int errorCounter; //!< Error counter +static evDataHandler clientHandler; //!< function point handler + +static CNResp radioSwitchOn(CNLib*& lib); +static CNResp radioSwitchOff(CNLib*& lib); +static CNResp simInit(CNLib* lib, char* simPin); + +static void dump(); + +bool cnInit(evDataHandler handler /*=NULL*/, bool powerOn /*=true*/, bool dataEnabled /*=true*/, bool roomingEnabled /*=true*/){ + clientHandler = handler; + state = MNG_RADIO_OFF; + moduleOn = powerOn; + errorCounter = 0; + cnRegInit(); + cnDataInit(); + dataOn = dataEnabled; + cnRegSetRoaming(roomingEnabled); + return true; +} + +CNLib* cnGetMDM(){ + return cnLib; +} + +void cnSetPower(bool on){ + moduleOn = on; +} + +void cnSetDataEnabled(bool hasDataConnToBeEnabled){ + dataOn = hasDataConnToBeEnabled; + cnDataEnable(dataOn); +} + +void cnSetRoamingOn(bool isRoomingEnabled){ + cnRegSetRoaming(isRoomingEnabled); +} + +void cnSetApn(const char *apn,const char* username/*= NULL*/,const char* password/*= NULL*/){ + cnDataSetupApn(apn, username, password); +} + +void cnSetSimPin(const char* pin){ + if (pin!=NULL) + strncpy(simPin,pin, sizeof(simPin)); +} + +DataStatus cnGetDataConnStatus(){ + return (state == MNG_DATA_UP)? DATA_CONNECTED : DATA_DISCONNECTED; +} + +bool cnSetDebug(int level){ + if (!setUtilDebugLevel(level)) + return false; + return true; +} + +int cnLoop(){ + int ret; + MngState oldState = state; + + TRACE("%s enter \r\n", __FUNCTION__); + //check if init has been called + if (state == MNG_NOT_INIT){ + ERROR("%s Module has not been initiated\r\n", __FUNCTION__); + return false; + } + //switch on + if (state == MNG_RADIO_OFF && moduleOn ){ + INFO("%s: Switching ON radio \r\n", __FUNCTION__); + cnDataEnable(dataOn); + ret = radioSwitchOn(cnLib); + state = (ret == RES_OK) ? MNG_RADIO_ON : MNG_ERROR_RESET; + } + //switch off + if (state != MNG_RADIO_OFF && !moduleOn){ + INFO("%s: Switching OFF radio \r\n", __FUNCTION__); + if (state == MNG_DATA_UP) + //disable data + cnDataEnable(false); + else if (state == MNG_IDLE){ + //switching off + cnDataReset(); + cnRegReset(); + radioSwitchOff(cnLib); + state = MNG_RADIO_OFF; + } + } + //sim initialization + if (state == MNG_RADIO_ON ){ + ret = simInit(cnLib, simPin); + state = (ret == RES_OK) ? MNG_IDLE : MNG_ERROR_RESET; + } + //cycle the registration and data service + if (state == MNG_IDLE || state == MNG_DATA_UP){ + RegStatus regStatus; + DataConnStatus dataStatus; + //Tick the registration service + cnRegLoop(cnLib, ®Status); + //Tick Data service + cnDataLoop(cnLib, regStatus, &dataStatus); + //manage data status + if (dataStatus == DATA_IS_CONNECTED){ + state = MNG_DATA_UP; + if (clientHandler!=NULL) clientHandler(DATA_CONNECTED); + } else if (dataStatus == DATA_IS_DISCONNECTED){ + state = MNG_IDLE; + if (clientHandler!=NULL) clientHandler(DATA_DISCONNECTED); + } + } + //error management + if (state == MNG_ERROR_RESET){ + //block state machine when errors reach a max value counter + if (++errorCounter > MAX_ERROR_RETRIES) + state = MNG_ERROR_STUCK; + else{ + //otherwise start reset procedure + ERROR("State machine is in Error state, doing Reset.\r\n"); + cnDataReset(); + cnRegReset(); + radioSwitchOff(cnLib); + state = MNG_RADIO_OFF; + } + } + //when the state is stuck stay here forever + if (state == MNG_ERROR_STUCK){ + ERROR("State machine is in Blocked state, please change setting.\r\n"); + return false; + } + //dump info + if (getUtilDebugLevel() > 1 && oldState != state) + dump(); + return true; +} + +void dump(){ + INFO("cnanager Dump\r\n"); + const char* txtState[] = { "Not Initiated", "Radio is Off", "Radio is On", \ + "Idle", "Connected", "Reset Error", "Blocked Error"}; + if (state < sizeof(txtState)/sizeof(*txtState)) + INFO(" Internal State: %s\r\n", txtState[state]); +} + +/** Switch On Radio + \param lib pointer to library + */ +CNResp radioSwitchOn(CNLib*& lib) +{ + TRACE("%s enter \r\n", __FUNCTION__); + lib = new CNLib(); + if (lib == NULL){ + ERROR("Error on allocating lib\r\n"); + goto error; + } + lib->setDebug(getUtilDebugLevel()); + //power on the module and detect if alive + if (!RESPOK(lib->powerOnModem())){ + ERROR("Error on detecting the modem\r\n"); + goto error; + } + //init generic modem + if (!RESPOK(lib->initModem())){ + ERROR("Error on init device\r\n"); + goto error; + } + //handle unknown device + if (lib->getDev()->dev == MDMParser::DEV_UNKNOWN){ + ERROR("Device is unknown\r\n"); + goto error; + } + return RES_OK; + +error: + return RES_ERROR; + +} + +/** Switch off the radio + \param lib pointer to CN library + */ +CNResp radioSwitchOff(CNLib*& lib){ + TRACE("%s enter \r\n", __FUNCTION__); + if (lib != NULL){ + lib->powerOff(); + delete lib; + } + return RES_OK; +} + +/** Sim Pin initialization + \param lib pointer to CN library + \param simPin sim pin + */ +CNResp simEnterPin(CNLib* lib, char* simPin){ + int res; + + if (simPin == NULL){ + ERROR("Sim Pin is required but not provided\r\n"); + return RES_ERROR_STUCK; + } + res = lib->simInit(simPin); + if (RESPOK(res) ) + return RES_OK; + if (lib->getDev()->sim == MDMParser::WRONG_PIN){ + ERROR("Sim pin, %s ,provided is wrong\r\n", simPin); + return RES_ERROR_STUCK; + } + return RES_ERROR; +} + +/** Sim initialization + \param lib pointer to CN library + \param simPin sim pin + */ +CNResp simInit(CNLib* lib, char* simPin) +{ + CNResp res = RES_ERROR; + int _simWaitCounter=0; + TRACE("CNLib::%s enter\r\n", __FUNCTION__); + + do{ + if (RESPOK(lib->simInit(NULL))) + break; + wait_ms(10); + } while(_simWaitCounter++ < SIM_WAIT_MAX_CYCLE); + INFO("Sim status is %d \r\n", lib->getDev()->sim); + //handle sim status + switch (lib->getDev()->sim){ + case MDMParser::SIM_READY: + INFO("Sim has been initiated correctly\r\n"); + res = RES_OK; + break; + case MDMParser::SIM_PIN: + INFO("Sim Pin is requested\r\n"); + res = simEnterPin(lib, simPin); + break; + case MDMParser::SIM_MISSING: + ERROR("Sim has not been inserted, HALT\r\n"); + res = RES_ERROR; + break; + case MDMParser::SIM_PUK: + ERROR("Sim Puk is required, HALT\r\n"); + res = RES_ERROR_STUCK; + break; + case MDMParser::SIM_UNKNOWN: + ERROR("Sim Unknown state\r\n"); + res = RES_ERROR_STUCK; + break; + case MDMParser::WRONG_PIN: + ERROR("Wrong sim pin provided, HALT\r\n"); + res = RES_ERROR_STUCK; + break; + } + //sim has been successfully initialized + if (res == RES_OK){ + lib->getSimInfo(); + } + return res; +} \ No newline at end of file