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));
}
u-blox