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

Dependents:   C027_demo_ConnMan

Revision:
0:86284a262735
Child:
1:29ad1d1ac1f9
diff -r 000000000000 -r 86284a262735 CNManager.cpp
--- /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, &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;
+}
\ No newline at end of file