Connection Manager library for u-blox cellular modules. It manages the modem for keeping data connection always active.

Dependents:   C027_demo_ConnMan

CNManager.cpp

Committer:
msinig
Date:
2016-01-12
Revision:
0:86284a262735
Child:
1:29ad1d1ac1f9

File content as of revision 0:86284a262735:

#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, &regStatus);
        //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;
}