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.
Step 2. Add related file in Keil project
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