BluetoothLE

BLE Manager

BLE manager provide the auto-advertise option and handling the BLE status that make user eaiser to control BLE statment.

Initialize

Before using the BLE manager, please follow below steps to initiate.

Step 1. Enable BLE manager

#define BM_ENABLED                               (1)

The definition been defined in qd_module.h in sys_config folder.

ble_mngr_keil_file

Step 3. Register callback and init

Add below program in app_main.c

void APP_BleUnsolicitedCallback(uint16_t u16EvtType, T_OplErr tEvtRst, uint8_t *pu8Data, uint32_t u32DataLen)
{
    switch(u16EvtType)
    {
        case USLCTED_CB_EVT_BLE_INIT:
        {       
            // ble inited event

            // initialize ble advertise data
            APP_BleAdvDataInit();

            // initialize ble scan response data
            APP_BleScanRspDataInit();

            break;
        }
        case USLCTED_CB_EVT_BLE_ENT_ADVERTISE:
        {
            // enter advertising event

            break;
        }
        case USLCTED_CB_EVT_BLE_EXI_ADVERTISE:
        {
            // exit advertising event

            break;
        }
        case USLCTED_CB_EVT_BLE_CONNECTED:
        {
            // ble connected event

            break;
        }
        case USLCTED_CB_EVT_BLE_DISCONNECT:
        {
            // ble disconnect event

            break;
        }
        default:
        {
            // should not be here

            break;
        }
    }
}
void APP_BleInit(void)
{
    // assign unsolicited callback function
    Opl_Ble_Uslctd_CB_Reg(&APP_BleUnsolicitedCallback);

    // register service
    GAP_Svc_Init();
    GATT_Svc_Init();

    // ...register your service here

    // initialize the ble manager (auto-adv)
    Opl_Ble_Init_Req(true);

    // user implement
}

The parameter of Opl_Ble_Init_Req() is to enable/disable auto-advertise function.

  • If set as true - the auto-advertise will be enabled, and will directly start advertise after ble manager init done. While disconnect from connected state, ble manager will also start advertising, till user calling Opl_Ble_Stop_Req().
  • If set as false - the auto-advertise will be disabled, and will not advertise after ble manager init done.

Info

The APP_BleInit() function create by default in app_main.c, it's for developer to fill the ble related init function in it.

Step 4. Setup advertise data

void APP_BleAdvDataInit(void)
{
    // ble advertise data inititate

    // user modify
    // *

    uint8_t au8BleAdvertData[];

    // configure your own advertise data

    Opl_Ble_Advertise_Data_Set(au8BleAdvertData, lens);

    // *
}

Step 5. Setup scan response data

Create scan response data init function, and modify your wishes data.

void APP_BleScanRspDataInit(void)
{
    // ble scan response data inititate

    // user modify
    // *

    uint8_t au8BleScanRspData[BLE_ADV_SCAN_BUF_SIZE];

    // configure your own scan response data

    if(OPL_OK != Opl_Ble_ScanRsp_Data_Set(au8BleScanRspData, lens))
    {
        OPL_LOG_ERRO(APP, "Scan Rsp Data Set Fail");
    }

    // *
}

Step 6. Call set adv data & scan rsp data after init

Call APP_BleAdvDataInit (created in step 4) and APP_BleScanRspDataInit (created in step 5) after recevied USLCTED_CB_EVT_BLE_INIT event in ble unsolicited callback.

void APP_BleUnsolicitedCallback(uint16_t u16EvtType, T_OplErr tEvtRst, uint8_t *pu8Data, uint32_t u32DataLen)
{
    switch(u16EvtType)
    {
        case USLCTED_CB_EVT_BLE_INIT:
        {       
            // ble inited event

            // initialize ble advertise data
            APP_BleAdvDataInit();               // <---

            // initialize ble scan response data
            APP_BleScanRspDataInit();           // <---

            break;
        }

Unsolicited callback

The unsolicited callback will content with ble status and carried the result in each state.

Info

Unsolicited callback prototype located in ble_mngr_api.h


How To...

BLE Manager

The BLE manager should provide a mechanism for user BLE data processing application to register the user (vendor defined) service table. The user data processing application process the data receive from and transmit to the phone App via BLE. Developer could set a file for specific service in quick_dev\ble_services

How to create BLE service

  • BLE service initiate (e.g. Battery Service)
void BAS_Svc_Init(void)
{
    g_tBasSvcHandle.patSvcDb = g_BasSvcDb;
    g_tBasSvcHandle.u8SvcDbSize = BAS_SVC_IDX_TOTAL;
    g_tBasSvcHandle.ptSvcGattDispatchHandler = BAS_Svc_GattDispatchHandler;

    if(OPL_OK != Opl_Ble_Service_Assign(&g_tBasSvcHandle))
    {
        OPL_LOG_ERRO(BAS, "BAS Service assign fail\r\n");
    }
}

g_tBasSvcHandle is the BLE service handle structure

static T_BmSvcHandle g_tBasSvcHandle = {0};

typedef struct S_BmSvcHandle
{
    LE_GATT_SERVICE_T             *ptSvcDef;
    LE_GATT_ATTR_T                *patSvcDb;
    uint8_t                       u8SvcDbSize;
    uint8_t                       u8Reserved;
    uint16_t                      u16SvcDataEvtBase;
    uint16_t                      u16SvcDataEvtTop;
    T_BmSvcDataProcessHandlerFp   ptSvcDataProcessHandler;
    T_BmSvcGattDispatchHandlerFp  ptSvcGattDispatchHandler;
} T_BmSvcHandle;

Developer at least should set three parameters *patSvcDb, u8SvcDbSize and ptSvcGattDispatchHandler. *patSvcDb is the service attribute information. u8SvcDbSize is the service size and ptSvcGattDispatchHandler is GATT dispatch handler.

LE_GATT_ATTR_T                *patSvcDb;

typedef struct
{
    UINT16                  handle;                    /**< handle */
    UINT8                   format;                    /**< UUID type */
    UINT16 * const          pUuid;                     /**< UUID */
    UINT16                  permit;                    /**< permit */
    UINT16                  maxLen;                    /**< maxinum value length */
    UINT16                  len;                       /**< value length */
    UINT8 * const           pVal;                      /**< value */
} LE_GATT_ATTR_T;

After configurating the BLE handle structure, developer could register BLE service via BLE Manager.

  • Register BLE service via BLE Manager
T_OplErr Opl_Ble_Service_Assign(T_BmSvcHandle *ptBmSvcHandle)

How to receive/notify data via BLE

Developer could create user defined service to implement input/output via BLE.

  • Receive data via BLE

In user defined servcie, developer can use user defined GATT dispatch handler to handle data from LE task. The developer can create different handlers for processing according to the type of data received in user defined GATT dispatch handler.

static T_OplErr UD_Svc_GattDispatchHandler(MESSAGEID tId, MESSAGE tMsg)
{
    switch(tId)
    {
        case LE_GATT_MSG_ACCESS_READ_IND:
        {
            UD_Svc_GattDispatchReadHandler((LE_GATT_MSG_ACCESS_READ_IND_T *)tMsg);
            break;
        }

        case LE_GATT_MSG_ACCESS_WRITE_IND:
        {
            UD_Svc_GattDispatchWriteHandler((LE_GATT_MSG_ACCESS_WRITE_IND_T *)tMsg);
            break;
        }

        case LE_GATT_MSG_NOTIFY_CFM:
        {
            OPL_LOG_INFO(UDS, "Notify Confirm");
            break;
        }

        default:
        {
            return OPL_ERR_CASE_INVALID;
        }
    }

    return OPL_OK;
}

There are three types of events in user defined handler that incude LE_GATT_MSG_ACCESS_READ_IND, LE_GATT_MSG_ACCESS_WRITE_IND and LE_GATT_MSG_NOTIFY_CFM. Developer could create different handler to handle these events.

If receiving LE_GATT_MSG_ACCESS_WRITE_IND, developer could create write handler (e.g. UD_Svc_GattDispatchWriteHandler). In this handler, develop must response read access to bottom layer via LE LeGattAccessWriteRsp.

static void UD_Svc_GattDispatchWriteHandler(LE_GATT_MSG_ACCESS_WRITE_IND_T *ind)
{
    // process the write access activity in each characteristic
    uint8_t u8AttErr = 0;
    uint16_t u16AttrId = ind->handle - g_tUdSvcHandle.ptSvcDef->startHdl;

    // printf("UD Svc attId = %d op = %x offset = %d\r\n", u16AttrId, ind->flag, ind->offset);

    switch(u16AttrId)
    {
        case UD_SVC_IDX_TX_VAL:
        {
            // send message to app
            APP_SendMessage(APP_EVT_BLE_DATA_IND, ind->pVal, ind->len);

            break;
        }

        case UD_SVC_IDX_RX_CFG:
        {
            uint16_t u16Enable = *((uint16_t *)ind->pVal);

            if ((ind->len == 2) && (u16Enable <= 1))
            {
                LeGattChangeAttrVal(g_tUdSvcHandle.ptSvcDef, UD_SVC_IDX_RX_CFG, sizeof(u16Enable), &u16Enable);
            }
            else
            {
                u8AttErr = LE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
            }

            break;
        }

        default:
        {
            u8AttErr = LE_ATT_ERR_WRITE_NOT_PERMITTED;
            break;
        }
    }

    LeGattAccessWriteRsp(ind->conn_hdl, ind->flag, ind->handle, u8AttErr);
}

If receiving LE_GATT_MSG_ACCESS_READ_IND, developer could create read handler (e.g. UD_Svc_GattDispatchReadHandler). In this handler, develop must response read access to bottom layer via LE LeGattAccessReadRsp.

static void UD_Svc_GattDispatchReadHandler(LE_GATT_MSG_ACCESS_READ_IND_T *ind)
{
    // process the read access activity in each characteristic
    uint8_t u8AttErr = 0;
    uint16_t u16AttrId = ind->handle - g_tUdSvcHandle.ptSvcDef->startHdl;

    // printf("UD Svc attId = %d op = %x offset = %d\r\n", u16AttrId, ind->flag, ind->offset);

    switch(u16AttrId)
    {
        case UD_SVC_IDX_RX_VAL:
        case UD_SVC_IDX_RX_CFG:
        {
            break;
        }

        default:
        {
            u8AttErr = LE_ATT_ERR_READ_NOT_PERMITTED;
            break;
        }
    }

    LeGattAccessReadRsp(ind->conn_hdl, ind->handle, u8AttErr);
}
  • Notify data via BLE

If wanting to actively send messages from application to the host via BLE, developer can create a notify function (e.g. UD_Svc_RxDataOutNotify) in the user defined service. LeGattCharValNotify can send data via LE.

T_OplErr UD_Svc_RxDataOutNotify(uint8_t *pu8Data, uint32_t u32DataLen)
{
    LE_ERR_STATE status;

    uint16_t u16NotiAttrId = g_tUdSvcHandle.ptSvcDef->startHdl + UD_SVC_IDX_RX_VAL;

    // update rx data to attribute value
    LeGattChangeAttrVal(g_tUdSvcHandle.ptSvcDef, (uint16_t)UD_SVC_IDX_RX_VAL, u32DataLen, pu8Data);

    // notify rx data to host
    status = LeGattCharValNotify(Opl_Ble_EntityGet()->conn_hdl, u16NotiAttrId, u32DataLen, pu8Data);

    if (status != SYS_ERR_SUCCESS)
    {
        OPL_LOG_ERRO(BAS, "Ble sending data fail");
        return OPL_ERR;
    }

    return OPL_OK;
}

How to perform BLE process

  • Start BLE advertising
T_OplErr Opl_Ble_Start_Req(uint8_t u8AutoAdvEn)

To start BLE advertising, *u8AutoAdvEn is true that enable auto-advertise while disconnect.

  • Stop BLE advertisng
T_OplErr Opl_Ble_Stop_Req(void)
  • Set BLE advertise data
T_OplErr Opl_Ble_Advertise_Data_Set(uint8_t *pau8AdvData, uint8_t u8AdvDataLen)

If wanting to set BLE advertisement data via BLE Manager, developer could config BLE data *pau8AdvData in Opl_Ble_Advertise_Data_Set

  • Set BLE scan respnse data
T_OplErr Opl_Ble_ScanRsp_Data_Set(uint8_t *pau8ScanRspData, uint8_t u8ScanRspDataLen)

If BLE central scan, developer could set scan response data in BLE perpherial