Motion and Environmental sensor reader application connected via BLE to ST BlueMS iOS/Android application.

Dependencies:   HTS221 LIS3MDL LPS22HB LSM303AGR LSM6DSL

Fork of MOTENV_Mbed by ST Expansion SW Team

This application supports three different sets of ST hardware boards:

  • STEVAL-STLKT01V1 (aka SensorTile)
  • X-NUCLEO-IDB05A1 and X-NUCLEO-IKS01A2 expansion boards
  • B-L475E-IOT01A IoT Discovery board

    and runs over four different target configurations:

  • Nucleo F401RE + X-NUCLEO-IDB05A1 + X-NUCLEO-IKS01A2 (set target NUCLEO_F401RE)
  • DISCO_L475VG_IOT01A (set target DISCO_L475VG_IOT01A)
  • Nucleo L476RG + CRADLE + SENSORTILE (set compile target NUCLEO_L476RG)
  • Nucleo L476RG + CRADLE_EXPANSION_BOARD + SENSORTILE (set compile target NUCLEO_L476RG, remove macro MINI_CRADLE from mbed_app.json)

The first 2 configurations do not require any HW modifications (just use the above indicated targets).

Third configuration (CRADLE ) only requires to remove the two ST-LINK jumpers and JP6 from the Nucleo L476RG board in order to allow flashing the SensorTile through the Nucleo Jtag controller. Once flashed, if the battery is properly plugged and charged, the SensorTile could be mounted in the plastic enclosure being able to run as a small stand alone wearable device. Please note that this configuration do not provide a serial console for printf.

To enable last configuration (CRADLE_EXPANSION_BOARD), follow the steps below:

  • On Nucleo L476RG
    • open the two "ST-LINK" jumpers
    • open the MCU power supply jumper JP6
    • close the solder bridges SB63 and SB62 (to enable the serial console)
  • On SensorTile Arduino Cradle close the solder bridges SB21 and SB10 (to enable the serial console) and move the jumper J2 to the 5V position
  • Plug the Sensor Tile on the Arduino Cradle
  • Plug the Cradle on the Nucleo Arduino connector and connect the debug flat cable between Cradle and Nucleo Jtag connector (the cradle pin1 -identified by a dot- must be connected to the Nucleo pin1 (dot) of SWD CN4 jtag connector)
  • Plug the Nucleo USB cable on PC (a new COM port should appear); no need to plug the micro USB cable on the cradle.
  • Open a PC terminal to see the messages
  • Compile from mbed CLI or on-line compiler removing macro MINI_CRADLE from mbed_app.json file and selecting NUCLEO_ L476RG target
  • Flash the board with the binary

For all configurations on an Android or iOS device download and open the ST BlueMS application and connect to "MotEnvMbedOS" BLE device to see the sensor data.

For all configurations is also possible to add a 9 axis MotionFX sensor fusion library, which is part of the X-CUBE-MEMS package at this link.
The library comes in three flavours, choose your preferred according to the toolchain used (IAR, Keil or GC, Keil version should be used for the online compiler) and copy it in the Middlewares\ST\STM32_MotionFX_Library\Lib directory changing the file extension according to the toolchain used (.a for GCC, .ar for Keil).
In the file mbed_app.json add the macro definition "USE_SENSOR_FUSION_LIB" to the chosen target.
If compiling from CLI and using GCC_ARM toolchain option, in the file \mbed-os\tools\toolchains\gcc.py change the compiling option from

        if target.core == "Cortex-M4F":
            self.cpu.append("-mfpu=fpv4-sp-d16")
            self.cpu.append("-mfloat-abi=softfp")

to

        if target.core == "Cortex-M4F":
            self.cpu.append("-mfpu=fpv4-sp-d16")
            self.cpu.append("-mfloat-abi=hard")

and compile.

main.cpp

Committer:
mapellil
Date:
2015-12-21
Revision:
8:b042fe719f51
Parent:
7:34014895dda8
Child:
9:2693f9ef8ff7

File content as of revision 8:b042fe719f51:

#include "mbed.h"

/*L0_BlueNRG_xx version main*/

#include <cmath>
#include <math.h>
#include "mbed.h"
#include "Gap.h"
#include "debug.h"
#include "btle.h"
#include "blecommon.h"
#include "BLE.h"
#include "UUID.h"
#include "Utils.h"
#include "MotionFX_Manager.h"
#include "InterruptManager.h"
#include "DevI2C.h"
#include "BlueNRGGattServer.h"
#include "GattCharacteristic.h"
#include "main.h"   // contains the condt compiling configuration

typedef struct {
    int32_t AXIS_X;
    int32_t AXIS_Y;
    int32_t AXIS_Z;
} AxesRaw_TypeDef;

#ifdef CUST_CONS_SERV
#include "CustomConsoleService.h"
#endif

#ifdef CUST_BATT_SERV
#include "CustomBatteryService.h"
#endif

#ifdef CUST_SENS_SERV
#include "x_nucleo_iks01a1.h"
#include "CustomSensorsService.h"
#endif

#ifdef CUST_CONFIG_SERV
#include "CustomConfigService.h"
#endif

#ifdef CUST_SW_SERV
#include "CustomSoftwareService.h"
#endif

static bool             isBlueButtonSequence = false;
static                  Ticker BlueButtonTimer;
static DigitalOut       greenled(LED1);
//static int8_t           txPower=-3;
static unsigned char    isCal = 0;
static uint16_t         TimeStamp=0;
static int              BLEConnectionStatus =0;
static bool             ForceReCalibration =0;
static int              HowManyButtonPress =0;
static uint32_t         timeoutEnv =0;
static uint32_t         timeoutCalib  =0;
static uint32_t         timeoutMems  =0;
static BLE              * p_BLEdev = NULL;
static int32_t          CounterAGM  =0;
static uint32_t         bleTxErrCnt =0;    
    
#ifdef CUST_CONS_SERV
static CustomConsoleService    * p_customconsoleservice = NULL;
#endif

#ifdef CUST_SENS_SERV
static CustomSensorService     * p_customsensorservice   = NULL;
static X_NUCLEO_IKS01A1        * p_mems_expansion_board = NULL;
#endif

#ifdef CUST_SW_SERV
static CustomSoftwareService   * p_customsoftwareservice = NULL;
static osxMFX_output           * p_MotionFX_Engine_Out     = NULL;
#endif
static osxMFX_calibFactor        magOffset;

#ifdef CUST_CONFIG_SERV
static CustomConfigService     * p_customconfigservice     = NULL;
#endif


/***************************    Calibration functions    **************************/

/**
 * @brief  Check if there are a valid Calibration Values in Memory and read them
 * @param None
 * @retval unsigned char Success/Not Success
 */
static unsigned char ReCallCalibrationFromMemory(void)
#ifdef BLUEMSYS_STORE_CALIB_FLASH
{
    /* ReLoad the Calibration Values from FLASH */
    unsigned char Success=1;
    uint32_t Address = BLUEMSYS_FLASH_ADD;
    __IO uint32_t data32 = *(__IO uint32_t*) Address;
    if(data32== BLUEMSYS_CHECK_CALIBRATION) {
        int32_t ReadIndex;
        uint32_t ReadmagOffset[7];

        for(ReadIndex=0; ReadIndex<7; ReadIndex++) {
            Address +=4;
            data32 = *(__IO uint32_t*) Address;
            ReadmagOffset[ReadIndex]=data32;
        }

        magOffset.magOffX    = (signed short) ReadmagOffset[0];
        magOffset.magOffY    = (signed short) ReadmagOffset[1];
        magOffset.magOffZ    = (signed short) ReadmagOffset[2];
        magOffset.magGainX   = *((float *) &(ReadmagOffset[3]));
        magOffset.magGainY   = *((float *) &(ReadmagOffset[4]));
        magOffset.magGainZ   = *((float *) &(ReadmagOffset[5]));
        magOffset.expMagVect = *((float *) &(ReadmagOffset[6]));

#ifdef BLUEMSYS_DEBUG_CALIB
        /* Debug */
        printf("magOffX   ->%d\r\n",magOffset.magOffX);
        printf("magOffY   ->%d\r\n",magOffset.magOffY);
        printf("magOffZ   ->%d\r\n",magOffset.magOffZ);
        printf("magGainX  ->%X\r\n",magOffset.magGainX);
        printf("magGainY  ->%X\r\n",magOffset.magGainY);
        printf("magGainZ  ->%X\r\n",magOffset.magGainZ);
        printf("expMagVect->%X\r\n",magOffset.expMagVect);
#endif /* BLUEMSYS_DEBUG_CALIB */

        /* Set the Calibration Structure */
#ifdef USE_SENSOR_FUSION_LIB
        osx_MotionFX_setCalibrationData(&magOffset);

        printf("Calibration Read from Flash\r\n");
        /* Control the calibration status */
        isCal = osx_MotionFX_compass_isCalibrated();
        printf("Check the Calibration =%d\r\n",isCal);
#endif
    } else {
        printf("Calibration Not present in FLASH\r\n");
        isCal=0;
    }

    return Success;
}
#else /* BLUEMSYS_STORE_CALIB_FLASH */
{
    /* ReLoad the Calibration Values from RAM */
    unsigned char Success=1;

    if(CalibrationStructureRAM[0]== BLUEMSYS_CHECK_CALIBRATION) {
        magOffset.magOffX    = (signed short) CalibrationStructureRAM[1];
        magOffset.magOffY    = (signed short) CalibrationStructureRAM[2];
        magOffset.magOffZ    = (signed short) CalibrationStructureRAM[3];
        magOffset.magGainX   = *((float *) &(CalibrationStructureRAM[4]));
        magOffset.magGainY   = *((float *) &(CalibrationStructureRAM[5]));
        magOffset.magGainZ   = *((float *) &(CalibrationStructureRAM[6]));
        magOffset.expMagVect = *((float *) &(CalibrationStructureRAM[7]));

#ifdef BLUEMSYS_DEBUG_CALIB
        /* Debug */
        printf("magOffX   ->%d\r\n",magOffset.magOffX);
        printf("magOffY   ->%d\r\n",magOffset.magOffY);
        printf("magOffZ   ->%d\r\n",magOffset.magOffZ);
        printf("magGainX  ->%X\r\n",magOffset.magGainX);
        printf("magGainY  ->%X\r\n",magOffset.magGainY);
        printf("magGainZ  ->%X\r\n",magOffset.magGainZ);
        printf("expMagVect->%X\r\n",magOffset.expMagVect);
#endif /* BLUEMSYS_DEBUG_CALIB */

#ifdef USE_SENSOR_FUSION_LIB
        /* Set the Calibration Structure */
        osx_MotionFX_setCalibrationData(&magOffset);
        printf("Calibration Read from RAM\r\n");

        /* Control the calibration status */
        isCal = osx_MotionFX_compass_isCalibrated();
        printf("Check the Calibration =%d\r\n",isCal);
#endif
    } else {
        printf("Calibration Not present in RAM\r\n");
        isCal=0;
    }

    return Success;
}
#endif /* BLUEMSYS_STORE_CALIB_FLASH */

static unsigned char ResetCalibrationInMemory(void)
#ifdef BLUEMSYS_STORE_CALIB_FLASH
{
    /* Reset Calibration Values in FLASH */
    unsigned char Success=1;

    /* Erase First Flash sector */
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t SectorError = 0;
    EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3;
    EraseInitStruct.Sector = BLUEMSYS_FLASH_SECTOR;
    EraseInitStruct.NbSectors = 1;

    /* Unlock the Flash to enable the flash control register access *************/
    HAL_FLASH_Unlock();

    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
        /*
          Error occurred while sector erase.
          User can add here some code to deal with this error.
          SectorError will contain the faulty sector and then to know the code error on this sector,
          user can call function 'HAL_FLASH_GetError()'
        */
        /*
          FLASH_ErrorTypeDef errorcode = HAL_FLASH_GetError();
        */

//   Error_Handler();
        Success=0;
    } else {
        printf("Erase calibration in FLASH Memory\r\n");
    }

    /* Lock the Flash to disable the flash control register access (recommended
    to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();

    return Success;
}
#else /* BLUEMSYS_STORE_CALIB_FLASH */
{
    /* Reset Calibration Values in RAM */
    unsigned char Success=1;
    int32_t Counter;

    for(Counter=0; Counter<8; Counter++)
        CalibrationStructureRAM[Counter]=0xFFFFFFFF;

    printf("Erase Calibration in RAM Memory\r\n");
    return Success;
}
#endif /* BLUEMSYS_STORE_CALIB_FLASH */

/**
 * @brief  Save the Magnetometer Calibration Values to Memory
 * @param None
 * @retval unsigned char Success/Not Success
 */
static unsigned char SaveCalibrationToMemory(void)
{
    unsigned char Success=1;

    /* Reset Before The data in Memory */
    Success = ResetCalibrationInMemory();

    if(Success)
#ifdef BLUEMSYS_STORE_CALIB_FLASH
    {
        /* Store in Flash Memory */
        uint32_t Address = BLUEMSYS_FLASH_ADD;
        uint32_t WritemagOffset[8];
        int32_t WriteIndex;
        WritemagOffset[0] = BLUEMSYS_CHECK_CALIBRATION;
        WritemagOffset[1] = (uint32_t) magOffset.magOffX;
        WritemagOffset[2] = (uint32_t) magOffset.magOffY;
        WritemagOffset[3] = (uint32_t) magOffset.magOffZ;
        WritemagOffset[4] = *((uint32_t *) &(magOffset.magGainX));
        WritemagOffset[5] = *((uint32_t *) &(magOffset.magGainY));
        WritemagOffset[6] = *((uint32_t *) &(magOffset.magGainZ));
        WritemagOffset[7] = *((uint32_t *) &(magOffset.expMagVect));

        /* Unlock the Flash to enable the flash control register access *************/
        HAL_FLASH_Unlock();

        for(WriteIndex=0; WriteIndex<8; WriteIndex++) {
            if (HAL_FLASH_Program(TYPEPROGRAM_WORD, Address,WritemagOffset[WriteIndex]) == HAL_OK) {
                Address = Address + 4;
            } else {
                /* Error occurred while writing data in Flash memory.
                   User can add here some code to deal with this error */
                /*
                  FLASH_ErrorTypeDef errorcode = HAL_FLASH_GetError();
                */
//       Error_Handler();
            }
        }
#ifdef BLUEMSYS_DEBUG_CALIB
        /* Debug */
        printf("magOffX   ->%d\r\n",magOffset.magOffX);
        printf("magOffY   ->%d\r\n",magOffset.magOffY);
        printf("magOffZ   ->%d\r\n",magOffset.magOffZ);
        printf("magGainX  ->%X\r\n",magOffset.magGainX);
        printf("magGainY  ->%X\r\n",magOffset.magGainY);
        printf("magGainZ  ->%X\r\n",magOffset.magGainZ);
        printf("expMagVect->%X\r\n",magOffset.expMagVect);
#endif /* BLUEMSYS_DEBUG_CALIB */

        printf("New Calibration Values Saved in FLASH\r\n");

        /* Lock the Flash to disable the flash control register access (recommended
         to protect the FLASH memory against possible unwanted operation) *********/
        HAL_FLASH_Lock();
    }
#else /* BLUEMSYS_STORE_CALIB_FLASH */
    {
        /* Store in RAM */
        CalibrationStructureRAM[0] = BLUEMSYS_CHECK_CALIBRATION;
        CalibrationStructureRAM[1] = (uint32_t) magOffset.magOffX;
        CalibrationStructureRAM[2] = (uint32_t) magOffset.magOffY;
        CalibrationStructureRAM[3] = (uint32_t) magOffset.magOffZ;
        CalibrationStructureRAM[4] = *((uint32_t *) &(magOffset.magGainX));
        CalibrationStructureRAM[5] = *((uint32_t *) &(magOffset.magGainY));
        CalibrationStructureRAM[6] = *((uint32_t *) &(magOffset.magGainZ));
        CalibrationStructureRAM[7] = *((uint32_t *) &(magOffset.expMagVect));

#ifdef BLUEMSYS_DEBUG_CALIB
        /* Debug */
        printf("magOffX   ->%d\r\n",magOffset.magOffX);
        printf("magOffY   ->%d\r\n",magOffset.magOffY);
        printf("magOffZ   ->%d\r\n",magOffset.magOffZ);
        printf("magGainX  ->%X\r\n",magOffset.magGainX);
        printf("magGainY  ->%X\r\n",magOffset.magGainY);
        printf("magGainZ  ->%X\r\n",magOffset.magGainZ);
        printf("expMagVect->%X\r\n",magOffset.expMagVect);
#endif /* BLUEMSYS_DEBUG_CALIB */

        printf("New Calibration Values Saved in RAM\r\n");
    }
#endif /* BLUEMSYS_STORE_CALIB_FLASH */

    return Success;
}

/***************************    End Calibration functions    **************************/

static void floatToInt(float in, int32_t *out_int, int32_t *out_dec, int32_t dec_prec)
{
    *out_int = (int32_t)in;
    in = in - (float)(*out_int);
//    *out_dec = (int32_t)trunc(in*pow((float)10,(int)dec_prec));
    *out_dec = (int32_t)(float)(int)(in*pow((float)10,(int)dec_prec));

}

static void onUpdatesEnabledCallback(GattAttribute::Handle_t handle)
{
    PRINTF("onUpdatesEnabledCallback! handle: %x\n\r", handle);
#ifdef CUST_SENS_SERV
    if (p_customsensorservice)
        p_customsensorservice->enNotify (handle);
#endif

#ifdef CUST_SW_SERV
    if (p_customsoftwareservice)
        p_customsoftwareservice->enNotify (handle);
#endif

#ifdef CUST_CONFIG_SERV
    if (p_customconfigservice) {
        p_customconfigservice->enNotify (handle);
                p_customconfigservice->updateConfigState(MASK_CALIB_SENSORFUSION_SHORT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
                p_customconfigservice->updateConfigState(MASK_CALIB_SENSORFUSION_FLOAT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
        }
#endif
#ifdef CUST_CONS_SERV
    if (p_customconsoleservice)
        p_customconsoleservice->enNotify (handle);
#endif
    /* TODO inform other obj implementing BLE services */
}

static void onUpdatesDisabledCallback(Gap::Handle_t handle)
{
    PRINTF("onUpdatesDisabledCallback! handle: %x\n\r", handle);
#ifdef CUST_SENS_SERV
    if (p_customsensorservice)
        p_customsensorservice->disNotify (handle);
#endif

#ifdef CUST_SW_SERV
    if (p_customsoftwareservice)
        p_customsoftwareservice->disNotify (handle);
#endif

#ifdef CUST_CONFIG_SERV
    if (p_customconfigservice)
        p_customconfigservice->disNotify (handle);
#endif
#ifdef CUST_CONS_SERV
    if (p_customconsoleservice)
        p_customconsoleservice->disNotify (handle);
#endif
    /* TODO inform other obj implementing BLE services */
}

//static void onDisconnectionCallback(const Gap::Handle_t handle, const Gap::DisconnectionReason_t disConnectionReason)
static void onDisconnectionCallback(const Gap::DisconnectionCallbackParams_t * disConnectionReason)
{
    printf("Disconnected\n\r");
    printf("Restarting the advertising process\n\r");
    TimeStamp =0;
    BLEConnectionStatus =0;
#ifdef CUST_SENS_SERV
    if (p_customsensorservice)
        p_customsensorservice->updateConnectionStatus(DISCONNECTED);
#endif
#ifdef CUST_SW_SERV
    if (p_customsoftwareservice)
        p_customsoftwareservice->updateConnectionStatus(DISCONNECTED);
#endif
#ifdef CUST_CONFIG_SERV
    if (p_customconfigservice)
        p_customconfigservice->updateConnectionStatus(DISCONNECTED);
#endif
#ifdef CUST_CONS_SERV
    if (p_customconsoleservice)
        p_customconsoleservice->updateConnectionStatus(DISCONNECTED);
#endif
    if (p_BLEdev)
        p_BLEdev->startAdvertising();
    bleTxErrCnt =0;    
}

static void onConnectionCallback(const Gap::ConnectionCallbackParams_t * connectionParams)
{
    printf("\rConnected: %x", connectionParams->peerAddr[Gap::ADDR_LEN-1]);
    for(int i=Gap::ADDR_LEN-2; i>=0; i--) printf(":%x", connectionParams->peerAddr[i]);
    printf("\n\r");
            
    TimeStamp =0;
    BLEConnectionStatus =1;
#ifdef CUST_SENS_SERV
    if (p_customsensorservice)
        p_customsensorservice->updateConnectionStatus(CONNECTED);
#endif
#ifdef CUST_SW_SERV
    if (p_customsoftwareservice)
        p_customsoftwareservice->updateConnectionStatus(CONNECTED);
#endif
#ifdef CUST_CONFIG_SERV
    if (p_customconfigservice)
        p_customconfigservice->updateConnectionStatus(CONNECTED);
#endif
#ifdef CUST_CONS_SERV
    if (p_customconsoleservice)
        p_customconsoleservice->updateConnectionStatus(CONNECTED);
#endif
    bleTxErrCnt =0;
}

static void onDataReadCallback(const GattReadCallbackParams *eventDataP)
{
    float temp, hum, pres;
    int16_t TempToSend, HumToSend;
    uint32_t    PresToSend;
    int32_t decPart, intPart;
    AxesRaw_TypeDef Magn, Acc, Gyro;

    printf ("onDataReadCallback\n\r");
#ifdef CUST_SENS_SERV
    if (p_customsensorservice->isTempHandle(eventDataP->handle)) {
        p_mems_expansion_board->ht_sensor->GetTemperature(&temp);
        floatToInt(temp, &intPart, &decPart, 1);
        TempToSend = intPart*10+decPart;
        p_customsensorservice->sendEnvTemperature(TempToSend, TimeStamp);

    } else if (p_customsensorservice->isHumHandle(eventDataP->handle)) {
        p_mems_expansion_board->ht_sensor->GetHumidity(&hum);
        floatToInt(hum, &intPart, &decPart, 1);
        HumToSend = intPart*10+decPart;
        p_customsensorservice->sendEnvHumidity(HumToSend, TimeStamp);

    } else if (p_customsensorservice->isPresHandle(eventDataP->handle)) {
        p_mems_expansion_board->pt_sensor->GetPressure(&pres);
        floatToInt(pres, &intPart, &decPart, 1);
        PresToSend = intPart*100+decPart;
        p_customsensorservice->sendEnvPressure(PresToSend, TimeStamp);

    } else if (p_customsensorservice->isGyroHandle(eventDataP->handle)) {
        p_mems_expansion_board->GetGyroscope()->Get_G_Axes((int32_t *)&Gyro);
        p_customsensorservice->sendEnvGyroscope (&Gyro, TimeStamp);

    } else if (p_customsensorservice->isAccHandle(eventDataP->handle)) {
        p_mems_expansion_board->GetAccelerometer()->Get_X_Axes((int32_t *)&Acc);
        p_customsensorservice->sendEnvAccelerometer (&Acc, TimeStamp);

    } else if (p_customsensorservice->isMagHandle(eventDataP->handle)) {
        p_mems_expansion_board->magnetometer->Get_M_Axes((int32_t *)&Magn);
        p_customsensorservice->sendEnvMagnetometer(&Magn, TimeStamp, magOffset);

    } else if (p_customsensorservice->isAccGyroMagHandle(eventDataP->handle)) {
        p_customsensorservice->sendEnvAccGyroMag (&Acc, &Gyro, &Magn, TimeStamp, magOffset);
    }
#endif

#ifdef CUST_SW_SERV
    if (p_customsoftwareservice->isQuatHandle(eventDataP->handle)) {
//          p_customsoftwareservice->updateQuaternions(quat_axes, TimeStamp);   // dont need to update because already calculated/update into main loop

    } else if (p_customsoftwareservice->isFloatQuatHandle(eventDataP->handle)) {
//          p_customsoftwareservice->updateFloatQuaternions(QuatFloat, TimeStamp);  // dont need to update because already calculated/update into main loop
    }
#endif

#ifdef CUST_CONFIG_SERV
    if (p_customconfigservice->isConfHandle(eventDataP->handle)) {
        p_customconfigservice->sendConfigState(MASK_CALIB_SENSORFUSION_SHORT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
        p_customconfigservice->sendConfigState(MASK_CALIB_SENSORFUSION_FLOAT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
    }
#endif
}

static void myonDataWriteCallback(const GattWriteCallbackParams *eventDataP)
{
    PRINTF("onEventCallback!!\n\r");
    printf (" myonDataWriteCallback attr_handle: %x  att_data[0]: %d  data_length: %d\n\r", eventDataP->handle, eventDataP->data[0], eventDataP->len );


#ifdef CUST_CONFIG_SERV
            if (p_customconfigservice->isConfHandle(eventDataP->handle)) {
                /* Received one write command from Client on calibration characteristc */
                uint32_t FeatureMask = (eventDataP->data[3]) | (eventDataP->data[2]<<8) | (eventDataP->data[1]<<16) | (eventDataP->data[0]<<24);
                uint8_t Command = eventDataP->data[4];
                switch (Command) {
                    case W2ST_COMMAND_CAL_STATUS:

                        /* Replay with the calibration status for the feature */
                        //  Config_Notify(FeatureMask,Command,isCal);
                        p_customconfigservice->sendConfigState(FeatureMask, Command, isCal, TimeStamp);
                        break;
                    case W2ST_COMMAND_CAL_RESET:

                        /* Reset the calibration */
                        ForceReCalibration=1;
                        break;
                    case W2ST_COMMAND_CAL_STOP:

                        /* Do nothing in this case */
                        break;
                    default:
//        if(StdErrNotification){
//          BytesToWrite = sprintf((char *)BufferToWrite, "Calibration UNKNOW Signal For Features=%x\n\r",FeatureMask);
//          Stderr_Update(BufferToWrite,BytesToWrite);
//        } else {
//          printf("Calibration UNKNOW Signal For Features=%x\n\r",FeatureMask);
//        }
                        break;
                }

            }
#endif
#ifdef CUST_CONS_SERV
//  printf ("-------------->>> attr_handle: %x\n\r", attr_handle);
//  if (p_customconsoleservice->isTermHandle(attr_handle -1)) {
//      p_customconsoleservice->updateTerm(att_data,data_length);
//    }
#endif


}

static void onDataSentCallback(unsigned count)
{
    PRINTF("onDataSentCallback!!\n\r");
}


static void onTimeoutCallback(Gap::TimeoutSource_t source)
{
    PRINTF("onTimeoutCallback!!\n\r");
}

static void onConfirmationReceivedCallback(uint16_t attributeHandle)
{
    PRINTF("onConfirmationReceivedCallback!!\n\r");
}


static void Ticker_BlueButton(void)
{
#ifdef CUST_CONS_SERV   
static uint8_t          BufferToWrite[W2ST_CONSOLE_MAX_CHAR_LEN];
static uint8_t          BytesToWrite;   
#endif
    
        BlueButtonTimer.detach();   
        printf (" butt time expired \n\r"); 
#ifdef CUST_CONS_SERV
    BytesToWrite = sprintf((char *)BufferToWrite, "nr%d push in %1.1fs\r\n",HowManyButtonPress, BUTTON_TIME);
    p_customconsoleservice->updateTerm(BufferToWrite,BytesToWrite);
#endif      
        isBlueButtonSequence = false;       
        HowManyButtonPress =0;  

}

/**
 * CB Triggered by the user blue button press;
 */
static void BlueButtonPressed ()
{
        //printf (" CB  BlueButtonPressed  PRESSED!!!!!!!!! %d\n\r", HowManyButtonPress);
    if (HowManyButtonPress == 0) { // first push
        BlueButtonTimer.attach(&Ticker_BlueButton, BUTTON_TIME);            
                HowManyButtonPress++;           
                isBlueButtonSequence = false;           
    } else {
                HowManyButtonPress++;           
                if (HowManyButtonPress == BLUEMSYS_N_BUTTON_PRESS ) {
                        BlueButtonTimer.detach();                   
                        printf (" CB  BlueButtoon SEQUENCE!!!!!!!!! \n\r");
                        HowManyButtonPress =0;
                        if (BLEConnectionStatus) isBlueButtonSequence = true;                               
                }       
        }
}

/**
 * CB Triggered periodically by the 'ticker' interrupt;
 */
static void Ticker_Env(void)
{
    timeoutEnv = 1;
}

static void Ticker_Calib(void)
{
    timeoutCalib = 1;
}

static void Ticker_Mems(void)
{
    TimeStamp++;
    CounterAGM++;
    timeoutMems = 1;
}


int main()
{
    Ticker EnvTimer;
    Ticker CalibTimer;
    Ticker MemsTimer;
    int32_t decPart, intPart;
    int16_t TempToSend,HumToSend;
    uint32_t PresToSend;
    float temp,hum,pres;
    AxesRaw_TypeDef Magn;
    AxesRaw_TypeDef Acc;
    AxesRaw_TypeDef Gyro;
    bool isgyro_lsm6ds0Present=false;
    bool isgyro_lsm6ds3Present=false;    
#ifdef CUST_CONS_SERV   
//    static uint8_t          BufferToWrite[256];
//    static uint8_t          BytesToWrite;           
#endif    
    static bool SensorFusionOK = false;

    DevI2C *i2c = new DevI2C(I2C_SDA, I2C_SCL);
    i2c->frequency(NUCLEO_I2C_SHIELDS_SPEED);

#ifdef CUST_SENS_SERV
    p_mems_expansion_board = X_NUCLEO_IKS01A1::Instance(i2c);
    if (p_mems_expansion_board->gyro_lsm6ds0) isgyro_lsm6ds0Present=true;
    if (p_mems_expansion_board->gyro_lsm6ds3) isgyro_lsm6ds3Present=true;    
#endif
//#ifdef CUST_CONFIG_SERV    
    InterruptIn BlueButton(USER_BUTTON);    
    BlueButton.fall(&BlueButtonPressed);
//#endif
    printf("\r\nSTMicroelectronics BlueMicrosystem1 W2ST:\r\n"
#ifdef CUST_SENS_SERV
           "\tGyro lsmds0 present: %d, lsmds3 present: %d\n\r"
           "\tSend Every %dmS Temperature/Humidity/Pressure\r\n"
           "\tSend Every %dmS Acc/Gyro/Magneto\r\n\n"   
#endif  
#ifdef CUST_SW_SERV
           ,"\tSend Every %dmS %d Quaternions\r\n"
           "\tSend Every %dmS Float precision Quaternion\r\n"
#endif
#ifdef CUST_SENS_SERV
           ,isgyro_lsm6ds0Present,
           isgyro_lsm6ds3Present,
           ENV_TIMER/1000,
           MEMS_TIMER/1000*ACC_GYRO_MAG_UPDATE_MUL_10MS
#endif
#ifdef CUST_SW_SERV
           ,MEMS_TIMER/1000*SEND_N_QUATERNIONS,SEND_N_QUATERNIONS,
           MEMS_TIMER/1000*QUAT_FLOAT_UPDATE_MUL_10MS
#endif
          );
                    
                    
    if (NUCLEO_I2C_SHIELDS_SPEED < MAX_I2C_SPEED) 
        printf ("Warning I2C speed set to: %d (max: %d)\n\r", NUCLEO_I2C_SHIELDS_SPEED, MAX_I2C_SPEED);
 
    p_BLEdev = new BLE;
    if (!p_BLEdev) {
        printf("\r\nBLE Device creation failed\r\n");
        return 0;
    }
        const Gap::Address_t BLE_address_BE = {BLE_DEV_MAC};        
        p_BLEdev->gap().setAddress(Gap::ADDR_TYPE_PUBLIC, BLE_address_BE);
        
      p_BLEdev->init();         
    
    greenled = 0;//Switch OFF LED1
    
    /* set the BLE CB functions */
    p_BLEdev->gattServer().onUpdatesEnabled(onUpdatesEnabledCallback);
    p_BLEdev->gattServer().onUpdatesDisabled(onUpdatesDisabledCallback);
    p_BLEdev->gattServer().onConfirmationReceived(onConfirmationReceivedCallback);    
    p_BLEdev->gattServer().onDataSent(onDataSentCallback);
    p_BLEdev->gattServer().onDataRead(onDataReadCallback);
        p_BLEdev->gattServer().onDataWritten(myonDataWriteCallback);
    p_BLEdev->gap().onConnection(onConnectionCallback);
    p_BLEdev->gap().onDisconnection(onDisconnectionCallback);
    p_BLEdev->gap().onTimeout(onTimeoutCallback);

    
    /* Initialize MotionFX library */
    bool DS3_OnBoard = DS3_ONBOARD;
    if (MotionFX_manager_init(DS3_OnBoard, magOffset)) {
        MotionFX_manager_start_9X();
        SensorFusionOK = true;
        printf("SW      Service sensor fusion library added successfully\r\n");
    } else {    /* sensor fusion lib init failed: likely because of wrong license */
            printf("sensor fusion lib init failed: likely because of wrong license \n\r");
        SensorFusionOK = false;     
    }   
        
#ifdef CUST_CONFIG_SERV
    p_customconfigservice = new CustomConfigService(*p_BLEdev);
    if (!p_customconfigservice) {
        printf("SW      Service W2ST calibration add FAILED!\n\r");
        return 0;  
    }
    printf("SW      Service W2ST calibration added successfully\r\n");
#endif
#ifdef CUST_CONS_SERV
    p_customconsoleservice = new CustomConsoleService(*p_BLEdev);
    if (!p_customconsoleservice) {
        printf("\n\rHW      Service W2ST console add FAILED!\n\r");
        return 0;
    }
    printf("\rHW      Service W2ST console added successfully\r\n");
#endif
#ifdef CUST_SENS_SERV
    p_customsensorservice = new CustomSensorService(*p_BLEdev);
    if (!p_customsensorservice) {
        printf("\n\rHW      Service W2ST sensors add FAILED!\n\r");
        return 0;
    }
    printf("\rHW      Service W2ST sensors added successfully\r\n");
#endif       
#ifdef CUST_SW_SERV
        AxesRaw_TypeDef quat_axes[SEND_N_QUATERNIONS];
        float QuatFloat[SEND_N_QUATERNIONS];        
        if (SensorFusionOK) {
            p_customsoftwareservice = new CustomSoftwareService(*p_BLEdev);
            if (!p_customsoftwareservice) {
                    printf("SW      Service W2ST quaternions add FAILED!\n\r");
                    return 0;
            }
            printf("SW      Service W2ST quaternions added successfully\r\n");
        }
#endif      
        
        const static char     DEVICE_NAME[]        = BLE_DEV_NAME;
    /* Setup advertising. */
    p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
//    p_BLEdev->gap().accumulateAdvertisingPayloadTxPower(txPower); 
#ifdef USE_SENSOR_FUSION_LIB        
    uint8_t dat[]= {0x01,0x80,0x00,0xFC,0x01,0x80};
#else
    uint8_t dat[]= {0x01,0x80,0x00,0xFC,0x00,0x00};
#endif      
    p_BLEdev->gap().accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA,dat,6);    
    p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::UNKNOWN);
    p_BLEdev->gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    p_BLEdev->gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    p_BLEdev->gap().setAdvertisingInterval(BLE_ADVERTISING_INTERVAL);
    
    printf("SERVER: BLE Stack Initialized\r\n");
    printf("Starting Advertising...\n\r");
    p_BLEdev->gap().startAdvertising();
    
    TimeStamp =0;
    EnvTimer.attach_us(&Ticker_Env, ENV_TIMER);
    CalibTimer.attach_us(&Ticker_Calib, CALIB_TIMER );
    MemsTimer.attach_us(&Ticker_Mems, MEMS_TIMER);

    /* Control if the calibration is already available in memory */
        if (SensorFusionOK) {
            ReCallCalibrationFromMemory();

            /* Switch on/off the LED according to calibration */
            if(isCal) {
                    greenled =1;
            } else {
                    greenled =0;
            }
        }
#ifdef CUST_SW_SERV        
    uint32_t QuaternionNumber =0;
    uint32_t CounterFloat =0;
#endif
        
    while(1) {

        if (BLEConnectionStatus) {
            if ((isBlueButtonSequence || ForceReCalibration) && SensorFusionOK ) {
                printf("ForceReCalibration\r\n");
                /* Reset the Compass Calibration */
                isCal=0;
                ForceReCalibration =0;
                                isBlueButtonSequence = false;                           
                /* Notifications of Compass Calibration */
#ifdef CUST_CONFIG_SERV
                p_customconfigservice->sendConfigState(MASK_CALIB_SENSORFUSION_SHORT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
                p_customconfigservice->sendConfigState(MASK_CALIB_SENSORFUSION_FLOAT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
#endif
#ifdef USE_SENSOR_FUSION_LIB
                /* Reset the Calibration */
                osx_MotionFX_compass_forceReCalibration();
#endif
                ResetCalibrationInMemory();

                /* Reset Calibration offset */
                magOffset.magOffX = magOffset.magOffY= magOffset.magOffZ=0;
                greenled =0;
            }
        }
        // Update MEMS @ 100Hz and calculate quaternions
        if (timeoutMems && BLEConnectionStatus) {
            timeoutMems =0;

#ifdef CUST_SENS_SERV
                        int32_t err;
                            err = p_mems_expansion_board->GetAccelerometer()->Get_X_Axes((int32_t *)&Acc);
                            if (err != IMU_6AXES_OK) {
                                printf ("= * ERROR %d GetAccelerometer\n\r", err);                          
                            }
                            err = p_mems_expansion_board->GetGyroscope()->Get_G_Axes((int32_t *)&Gyro);
                            if (err != IMU_6AXES_OK) {
                                printf ("= * ERROR %d GetGyroscope\n\r", err);                          
                            }
                            err = p_mems_expansion_board->magnetometer->Get_M_Axes((int32_t *)&Magn);
                            if (err != MAGNETO_OK) {
                                printf ("= * ERROR %d Get_M_Axes\n\r", err);                            
                            }    
            if(CounterAGM >= ACC_GYRO_MAG_UPDATE_MUL_10MS) {
                CounterAGM=0;
                uint32_t bleerr;
#ifdef BLE_TX_ERR_MNG 
                if (bleTxErrCnt == 0) {
#endif                                 
                    bleerr = p_customsensorservice->updateEnvAccelerometer (&Acc, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                    if (bleerr) {
                        bleTxErrCnt = BLE_TX_SKIP_NUM;   
                        printf ("===> BLE_TX_ERR %d\n\r", err);
                    }                            
                } else {
                    bleTxErrCnt--;
                }
#endif                     
#ifdef BLE_TX_ERR_MNG 
                if (bleTxErrCnt == 0) {
#endif                                 
                    bleerr = p_customsensorservice->updateEnvGyroscope(&Gyro, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                    if (bleerr) {
                        bleTxErrCnt = BLE_TX_SKIP_NUM;   
                        printf ("===> BLE_TX_ERR %d\n\r", err);
                    }                            
                } else {
                    bleTxErrCnt--;
                }
#endif                
#ifdef BLE_TX_ERR_MNG 
                if (bleTxErrCnt == 0) {
#endif                                                 
                    bleerr = p_customsensorservice->updateEnvMagnetometer(&Magn, TimeStamp, magOffset);
#ifdef BLE_TX_ERR_MNG 
                    if (bleerr) {
                        bleTxErrCnt = BLE_TX_SKIP_NUM;   
                        printf ("===> BLE_TX_ERR %d\n\r", err);
                    }                            
                } else {
                    bleTxErrCnt--;
                }
#endif                
#ifdef BLE_TX_ERR_MNG 
                if (bleTxErrCnt == 0) {
#endif                                                                     
                    bleerr = p_customsensorservice->updateEnvAccGyroMag (&Acc, &Gyro, &Magn, TimeStamp, magOffset);
#ifdef BLE_TX_ERR_MNG 
                    if (bleerr) {
                        bleTxErrCnt = BLE_TX_SKIP_NUM;   
                        printf ("===> BLE_TX_ERR %d\n\r", err);
                    }                            
                } else {
                    bleTxErrCnt--;
                }                    
            }
#endif
#endif

#ifdef USE_SENSOR_FUSION_LIB
            if (SensorFusionOK) {
                MotionFX_manager_run((AxesRaw_t*)&Acc, (AxesRaw_t*)&Gyro, (AxesRaw_t*)&Magn, magOffset);
                p_MotionFX_Engine_Out = MotionFX_manager_getDataOUT();
            }
#endif
#ifdef CUST_SW_SERV
            if (SensorFusionOK) {
                /* Update quaternions */
                if(p_MotionFX_Engine_Out->quaternion_9X[3] < 0) {
                    quat_axes[QuaternionNumber].AXIS_X = (int)(p_MotionFX_Engine_Out->quaternion_9X[0] * (-10000));
                    quat_axes[QuaternionNumber].AXIS_Y = (int)(p_MotionFX_Engine_Out->quaternion_9X[1] * (-10000));
                    quat_axes[QuaternionNumber].AXIS_Z = (int)(p_MotionFX_Engine_Out->quaternion_9X[2] * (-10000));
                } else {
                    quat_axes[QuaternionNumber].AXIS_X = (int)(p_MotionFX_Engine_Out->quaternion_9X[0] * 10000);
                    quat_axes[QuaternionNumber].AXIS_Y = (int)(p_MotionFX_Engine_Out->quaternion_9X[1] * 10000);
                    quat_axes[QuaternionNumber].AXIS_Z = (int)(p_MotionFX_Engine_Out->quaternion_9X[2] * 10000);
                }

                uint32_t bleerr;
                if (QuaternionNumber == SEND_N_QUATERNIONS-1) {
#ifdef BLE_TX_ERR_MNG 
                    if (bleTxErrCnt == 0) {
#endif                                       
                        bleerr = p_customsoftwareservice->updateQuaternions(quat_axes, TimeStamp);                    
#ifdef BLE_TX_ERR_MNG 
                        if (bleerr) {
                            bleTxErrCnt = BLE_TX_SKIP_NUM;   
                            printf ("===> BLE_TX_ERR %d\n\r", bleerr);
                        }                            
                    } else {
                        bleTxErrCnt--;
                    }
#endif              
                    QuaternionNumber =0;
                } else {
                    QuaternionNumber++;
                }

                /* Update Float Quaternions */
                /* Every QUAT_FLOAT_UPDATE_MUL_10MS*10 mSeconds Send Float Quaternion informations via bluetooth */
                if(CounterFloat==QUAT_FLOAT_UPDATE_MUL_10MS) {
                    if(p_MotionFX_Engine_Out->quaternion_9X[3] < 0) {
                        QuatFloat[0] = - p_MotionFX_Engine_Out->quaternion_9X[0];
                        QuatFloat[1] = - p_MotionFX_Engine_Out->quaternion_9X[1];
                        QuatFloat[2] = - p_MotionFX_Engine_Out->quaternion_9X[2];
                    } else {
                        QuatFloat[0] =   p_MotionFX_Engine_Out->quaternion_9X[0];
                        QuatFloat[1] =   p_MotionFX_Engine_Out->quaternion_9X[1];
                        QuatFloat[2] =   p_MotionFX_Engine_Out->quaternion_9X[2];
                    }
                    uint32_t bleerr;
#ifdef BLE_TX_ERR_MNG 
                    if (bleTxErrCnt == 0) {
#endif                         
                    bleerr = p_customsoftwareservice->updateFloatQuaternions(QuatFloat, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                        if (bleerr) {
                            bleTxErrCnt = BLE_TX_SKIP_NUM;   
                            printf ("===> BLE_TX_ERR %d\n\r", bleerr);
                        }                            
                    } else {
                        bleTxErrCnt--;
                    }
#endif                         
                    CounterFloat=0;
                } else  {
                    CounterFloat++;
                }
                }
#endif
        }

        /* Check if is calibrated  @ 25Hz */
        if(isCal!=0x01 && timeoutCalib && BLEConnectionStatus && SensorFusionOK ) {
            timeoutCalib =0;
            /* Run Compass Calibration @ 25Hz */
#ifdef USE_SENSOR_FUSION_LIB
            osx_MotionFX_compass_saveAcc(Acc.AXIS_X, Acc.AXIS_Y, Acc.AXIS_Z);  /* Accelerometer data ENU systems coordinate    */
            osx_MotionFX_compass_saveMag(Magn.AXIS_X, Magn.AXIS_Y, Magn.AXIS_Z);   /* Magnetometer  data ENU systems coordinate    */
            osx_MotionFX_compass_run();

            /* Control the calibration status */
            isCal = osx_MotionFX_compass_isCalibrated();
#endif
            if(isCal == 0x01) {

                printf("Compass Calibrated\n\r");
                /* Get new magnetometer offset */
#ifdef USE_SENSOR_FUSION_LIB
                osx_MotionFX_getCalibrationData(&magOffset);
#endif
                /* Save the calibration in Memory */
                SaveCalibrationToMemory();

                /* Switch on the Led */
                greenled = 1;

                /* Notifications of Compass Calibration */
#ifdef CUST_CONFIG_SERV
                p_customconfigservice->updateConfigState(MASK_CALIB_SENSORFUSION_SHORT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
                p_customconfigservice->updateConfigState(MASK_CALIB_SENSORFUSION_FLOAT, W2ST_COMMAND_CAL_STATUS, isCal, TimeStamp);
#endif
            }
        }

        // Update environmental sensors @ 2Hz
        if (timeoutEnv && BLEConnectionStatus) {
            timeoutEnv =0;
                        int32_t err;                                            
#ifdef CUST_SENS_SERV
                    if (p_customsensorservice->isTempNotificationEn()) {
                        err = p_mems_expansion_board->ht_sensor->GetTemperature(&temp);
                        if ( err != HUM_TEMP_OK) {
                            printf ("= * ERROR %d GetTemperature\n\r", err);
                        } else {
                            floatToInt(temp, &intPart, &decPart, 1);
                            TempToSend = intPart*10+decPart;
                            uint32_t bleerr;
#ifdef BLE_TX_ERR_MNG 
                            if (bleTxErrCnt == 0) {
#endif                               
                                bleerr = p_customsensorservice->updateEnvTemperature(TempToSend, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                                if (bleerr) {
                                    bleTxErrCnt = BLE_TX_SKIP_NUM;   
                                    printf ("===> BLE_TX_ERR %d\n\r", bleerr);
                                }                            
                            } else {
                                bleTxErrCnt--;
                            }
#endif                                 
                        }
                    }

                    if (p_customsensorservice->isHumNotificationEn()) {
                        err = p_mems_expansion_board->ht_sensor->GetHumidity(&hum);
                        if ( err != HUM_TEMP_OK) {
                            printf ("= * ERROR %d GetHumidity\n\r", err);                           
                        } else {
                            floatToInt(hum, &intPart, &decPart, 1);
                            HumToSend = intPart*10+decPart;
uint32_t bleerr;
#ifdef BLE_TX_ERR_MNG 
                            if (bleTxErrCnt == 0) {
#endif                             
                                bleerr = p_customsensorservice->updateEnvHumidity(HumToSend, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                                if (bleerr) {
                                    bleTxErrCnt = BLE_TX_SKIP_NUM;   
                                    printf ("===> BLE_TX_ERR %d\n\r", err);
                                }                            
                            } else {
                                bleTxErrCnt--;
                            }
#endif                                 
                        }
                    }

                    if (p_customsensorservice->isPresNotificationEn()) {
                        err = p_mems_expansion_board->pt_sensor->GetPressure(&pres);
                        if ( err != PRESSURE_OK) {
                            printf ("= * ERROR GetPressure\n\r");                           
                        } else {
                            floatToInt(pres, &intPart, &decPart, 1);
                            PresToSend = intPart*100+decPart;
uint32_t bleerr;
#ifdef BLE_TX_ERR_MNG 
                            if (bleTxErrCnt == 0) {
#endif                               
                                bleerr = p_customsensorservice->updateEnvPressure(PresToSend, TimeStamp);
#ifdef BLE_TX_ERR_MNG 
                               if (bleerr) {
                                    bleTxErrCnt = BLE_TX_SKIP_NUM;   
                                    printf ("===> BLE_TX_ERR %d\n\r", err);
                                }                            
                            } else {
                                bleTxErrCnt--;
                            }
#endif                                   
                        }
                    }
#endif
                }
        p_BLEdev->waitForEvent();
    }
}