Connection Manager library for u-blox cellular modules. It manages the modem for keeping data connection always active.
CNManager.cpp
- Committer:
- msinig
- Date:
- 2016-01-21
- Revision:
- 1:29ad1d1ac1f9
- Parent:
- 0:86284a262735
File content as of revision 1:29ad1d1ac1f9:
#include "CNManager.h" #include "CNData.h" #include "CNUtil.h" #include "CNLib.h" #include "CNReg.h" //! Manager 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 evMngHandler mngHandler; //!< Function point handler static void* paramDataHandler; //!< Pointer to pass to the handler static int respError; static CNResp radioSwitchOn(CNLib*& lib); static CNResp radioSwitchOff(CNLib*& lib); static CNResp simInit(CNLib* lib, char* simPin); bool cnInit(bool powerOn /*=true*/, bool dataEnabled /*=true*/, bool roomingEnabled /*=true*/){ mngHandler = NULL; paramDataHandler = NULL; state = MNG_RADIO_OFF; moduleOn = powerOn; errorCounter = 0; respError = 0; cnRegInit(); cnDataInit(); dataOn = dataEnabled; cnRegSetRoaming(roomingEnabled); return true; } void cnRegHandler(evMngHandler handler, void* param/*=NULL*/) { mngHandler = handler; paramDataHandler = param; } MDMSerial* cnGetMDM(){ return (MDMSerial*) cnLib; } void cnSetPower(bool on){ moduleOn = on; } void cnSetDataEnabled(bool hasDataConnToBeEnabled){ TRACE("%s enter \r\n", __FUNCTION__); 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) strncpy(simPin,pin, sizeof(simPin)); } bool cnIsDataUp(){ return (state == MNG_DATA_UP)? true : false; } 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; if (state == MNG_IDLE && mngHandler) mngHandler(MNG_EV_IDLE, paramDataHandler); } //cycle the registration and data service if (state == MNG_IDLE || state == MNG_DATA_UP){ RegStatus regStatus; int res; DataConnStatus dataStatus; //Tick the registration service res = cnRegLoop(cnLib, ®Status); if (res != RES_OK && ++respError > MEX_RESP_ERROR) state = MNG_ERROR_RESET; //Tick Data service cnDataLoop(cnLib, regStatus, &dataStatus); //manage data status if (dataStatus == DATA_IS_CONNECTED){ state = MNG_DATA_UP; if (mngHandler) mngHandler(MNG_EV_DATA_UP, paramDataHandler); } else if (dataStatus == DATA_IS_DISCONNECTED){ state = MNG_IDLE; if (mngHandler) mngHandler(MNG_EV_DATA_DOWN, paramDataHandler); } } //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("%s: State machine is in Error state, doing Reset.\r\n", __FUNCTION__); respError=0; cnDataReset(); cnRegReset(); radioSwitchOff(cnLib); state = MNG_RADIO_OFF; } } //when the state is stuck stay here forever if (state == MNG_ERROR_STUCK){ ERROR("%s: State machine is in Blocked state, please change setting.\r\n", __FUNCTION__); return false; } //dump info if (getUtilDebugLevel() > 1 && oldState != state){ INFO("CNManager 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]); } return true; } /** 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("%s: Error on allocating lib\r\n", __FUNCTION__); goto error; } lib->setDebug(getUtilDebugLevel()); //power on the module and detect if alive if (!RESPOK(lib->powerOnModem())){ ERROR("%s: Error on detecting the modem\r\n", __FUNCTION__); goto error; } //init generic modem if (!RESPOK(lib->initModem())){ ERROR("%s: Error on init device\r\n", __FUNCTION__); goto error; } //handle unknown device if (lib->getDev()->dev == MDMParser::DEV_UNKNOWN){ ERROR("%s: Device is unknown\r\n", __FUNCTION__); 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("%s: Sim Pin is required but not provided\r\n", __FUNCTION__); return RES_ERROR_STUCK; } res = lib->simInit(simPin); if (RESPOK(res) ) return RES_OK; if (lib->getDev()->sim == MDMParser::WRONG_PIN){ ERROR("%s: 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("%s: Sim has been initiated correctly\r\n", __FUNCTION__); res = RES_OK; break; case MDMParser::SIM_PIN: INFO("%s: Sim Pin is requested\r\n"); res = simEnterPin(lib, simPin); break; case MDMParser::SIM_MISSING: ERROR("%s: Sim has not been inserted, HALT\r\n", __FUNCTION__); res = RES_ERROR; break; case MDMParser::SIM_PUK: ERROR("%s: Sim Puk is required, HALT\r\n", __FUNCTION__); res = RES_ERROR_STUCK; break; case MDMParser::SIM_UNKNOWN: ERROR("%s: Sim Unknown state\r\n", __FUNCTION__); res = RES_ERROR_STUCK; break; case MDMParser::WRONG_PIN: ERROR("%s: Wrong sim pin provided, HALT\r\n", __FUNCTION__); res = RES_ERROR_STUCK; break; } //sim has been successfully initialized if (res == RES_OK){ lib->getSimInfo(); } return res; } void getNetStatus(MDMParser::NetStatus* net){ if (net && cnLib) memcpy(net, cnLib->getNet(), sizeof(MDMParser::NetStatus)); } void getDevStatus(MDMParser::DevStatus* dev){ if (dev && cnLib) memcpy(dev, cnLib->getDev(), sizeof(MDMParser::DevStatus)); }