WI-FI provision via BLE
The advantage of dual-core chip (OPL series), QuickDev-Framework provide a process to provision Wi-Fi credentials of the Home AP via the Bluetooth low energy (BLE). This setion can help the developer to quickly understand and implement the protocol into the application.
This block diagram introduces the architecture of the provision Wi-Fi credentials via BLE. The phone (BLE central) will transmitting the required message to the device. When the device received the message, it will process the Wi-Fi connection base on the given information.
Opulinks also provide a reference code-base for Phone APP, the front-end developer can use the needed code-base to enhance on their project/product.
- Android APP :
- IOS APP :
- WeChat mini APP :
Provision Process
QuickDev-Framework had provided the Wi-Fi provision via BLE protocol, for a quick look to the example which can demonstrate the Wi-Fi provision via BLE protocol, please check on QD_APP section.
In below diagram, it present a simplify steps that how's the provision done.
When the phone (BLE central) wants to provision the Wi-Fi credential and connect to AP, the phone (BLE central) will send the command and required message to the device, e.g. Wi-Fi scan request or Wi-Fi connect request.
And the device is responsible to receive and parsing the required message, then progress the Network manager to processing according to different events.
While Network manager had done with indicate or unsolicited callback returns, then the device will transit the corresponding response or result to the phone (BLE central) for notify the status.
The focusing of provision process is to create a BLE data command list to letting the phone (BLE central) and the device can recognize the data and handling in such.
OPL Service
OPL service is one of the profile service collection in BLE which designed by Opulinks that including the Wi-Fi provision command & handler needed.
Info
To understand the BLE manager and BLE service can refer to BluetoothLE
The OPL service UUID defined in quick_dev/app_ref/ble_data_prot/opl_data/opl_svc.h
Service/Characteristic | UUID |
---|---|
OPL service | 0xAAAA |
DATA IN character | 0xBBB0 |
DATA OUT character | 0xBBB1 |
Initialize
To using this service on your application, please follow in below items.
Initialize the OPL service in your application
Add OPL_Svc_Init()
in app_main.c
void APP_BleInit(void)
{
// assign unsolicited callback function
Opl_Ble_Uslctd_CB_Reg(&APP_BleUnsolicitedCallback);
// register service
GAP_Svc_Init();
GATT_Svc_Init();
// register opl service
OPL_Svc_Init(); // <- initialize OPL service
// initialize the ble manager (auto-adv)
Opl_Ble_Init_Req(true);
// user implement
}
Generate a data passthrough
When the data received, the OPL_SVC_DATA_IN
characteristic contents in OPL service will execute a context switch to passing the received data from BLE manager to host application, so we need to create a catcher on application side, and let it process the data parsing and progress.
Add the APP_EVT_BLE_DATA_IND
event and handler in app_main.c
.
static T_AppEvtHandlerTbl g_tAppEvtHandlerTbl[] =
{
...
{APP_EVT_BLE_DATA_IND, APP_EvtHandler_BleDataInd},
...
{0xFFFFFFFF, NULL},
};
Then add OPL_DataRecvHandler()
to let the handler do parsing and progress.
static void APP_EvtHandler_BleDataInd(uint32_t u32EventId, void *pData, uint32_t u32DataLen)
{
OPL_DataRecvHandler(pData, (uint16_t)u32DataLen);
}
At final step, we must enable the protocol which defined in `qd_module.h"
//==========================================================
// <h> OPL Data protocol
//==========================================================
// <e> OPL_DATA_ENABLED - Opulinks BLE WI-FI data protocol
//==========================================================
#ifndef OPL_DATA_ENABLED
#define OPL_DATA_ENABLED (1)
#endif
And that's the wrap, the Wi-Fi provision via BLE function has been activated in your application. It's recommend to using our standard phone APP by searching "Opulinks Wireless Utilities" at APP store to try with.
How to...
How to create an user defined service (e.g. quick_dev\app_ref\ble_data_prot\opl_svc.c
) in BLE Manager
Please refer to BluetoothLE
How to receive BLE data in and then export to BLE Application in application
- Create a gatt dispatch handler (e.g.
OPL_Svc_GattDispatchHandler()
) in user defined service
static T_OplErr OPL_Svc_GattDispatchHandler(MESSAGEID tId, MESSAGE tMsg)
{
switch(tId)
{
case LE_GATT_MSG_ACCESS_READ_IND:
{
OPL_Svc_GattDispatchReadHandler((LE_GATT_MSG_ACCESS_READ_IND_T *)tMsg);
break;
}
case LE_GATT_MSG_ACCESS_WRITE_IND:
{
OPL_Svc_GattDispatchWriteHandler((LE_GATT_MSG_ACCESS_WRITE_IND_T *)tMsg);
break;
}
case LE_GATT_MSG_NOTIFY_CFM:
{
Opl_Ble_Send_Message(OPL_SVC_EVT_SEND_TO_PEER_CFM, NULL, 0, 0);
break;
}
default:
{
return OPL_ERR_CASE_INVALID;
}
}
return OPL_OK;
}
This example is receiving LE_GATT_MSG_ACCESS_WRITE_IND
event to handle BLE data via OPL_Svc_GattDispatchWriteHandler()
tatic void OPL_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_tOplSvcHandle.ptSvcDef->startHdl;
switch(u16AttrId)
{
case OPL_SVC_IDX_DATA_IN_VAL:
{
APP_SendMessage(APP_EVT_BLE_DATA_IND, ind->pVal, ind->len);
break;
}
case OPL_SVC_IDX_DATA_OUT_CFG:
{
uint16_t u16Enable = *((uint16_t *)ind->pVal);
if ((ind->len == 2) && (u16Enable <= 1))
{
LeGattChangeAttrVal(g_tOplSvcHandle.ptSvcDef, OPL_SVC_IDX_DATA_OUT_CFG, sizeof(u16Enable), &u16Enable);
}
else
{
u8AttErr = LE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
break;
}
default:
{
u8AttErr = LE_ATT_ERR_WRITE_NOT_PERMITTED;
break;
}
}
If receiving OPL_SVC_IDX_DATA_IN_VAL
, OPL_Svc_GattDispatchWriteHandler()
could send BLE data to application via APP_SendMessage()
In application, developer could create a function (e.g. APP_EvtHandler_BleDataInd()
) to send BLE data to BLE Application.
static void APP_EvtHandler_BleDataInd(uint32_t u32EventId, void *pData, uint32_t u32DataLen)
{
OPL_DataRecvHandler(pData, (uint16_t)u32DataLen);
}
How to handle Wi-Fi provision message via BLE in BLE Application
BLE Application is responsible for parsing the messages from BLE, and then processing these events by category. Wi-Fi provision messages include Wi-Fi scan, Wi-Fi connect, Wi-Fi disconnect, Wi-Fi reconnect, read device Wi-Fi information, write Wi-Fi device information, get device Wi-Fi status and reset Wi-Fi. It is a BLE Application event handler table g_tOplDataEventHandlerTbl
to handle these events.
static T_OplDataEventTable g_tOplDataEventHandlerTbl[] =
{
{OPL_DATA_REQ_SCAN, OPL_DataProtocol_Scan},
{OPL_DATA_REQ_CONNECT, OPL_DataProtocol_Connect},
{OPL_DATA_REQ_DISCONNECT, OPL_DataProtocol_Disconnect},
{OPL_DATA_REQ_RECONNECT, OPL_DataProtocol_Reconnect},
{OPL_DATA_REQ_READ_DEVICE_INFO, OPL_DataProtocol_ReadDeviceInfo},
{OPL_DATA_REQ_WRITE_DEVICE_INFO, OPL_DataProtocol_WriteDeviceInfo},
{OPL_DATA_REQ_WIFI_STATUS, OPL_DataProtocol_WifiStatus},
{OPL_DATA_REQ_RESET, OPL_DataProtocol_Reset},
For example, if receiving OPL_DATA_REQ_SCAN
, OPL_DataProtocol_Scan
handler will send Wi-Fi scan message to Network Manager to execute Wi-Fi scan.
static void OPL_DataProtocol_Scan(uint16_t type, uint8_t *data, int len)
{
OPL_LOG_DEBG(OPL, "OPL_DATA_REQ_SCAN");
// reset connection config table
memset(&g_tOplDataConnCfg, 0, sizeof(T_OplDataConnCfg));
g_tOplDataConnCfg.u8ConnectType = OPL_DATA_CONN_TYPE_BSSID;
// trigger scan request
APP_NmWifiScanReq(OPL_DataHandler_WifiScanDoneIndCb);
}
How to respnose Wi-Fi process result to phone
BLE Application send Wi-Fi provision message to Network Manager, and then Network Manager will create a callback function to handle indicate callback.
For example, if Wi-Fi scan done, the Wi-FI scan done callback OPL_DataHandler_WifiScanDoneIndCb
will follow up on scan done.
void OPL_DataHandler_WifiScanDoneIndCb(T_OplErr tEvtRst)
{
OPL_LOG_DEBG(OPL, "Wifi scan done ind %d", tEvtRst);
if(OPL_DATA_CONN_TYPE_BSSID == g_tOplDataConnCfg.u8ConnectType)
{
// CK_DATA_REQ_SCAN cmd, just do report scan list
_OPL_DataHandler_SendScanReport();
OPL_DataSendResponse(OPL_DATA_RSP_SCAN_END, 0);
}
}
_OPL_DataHandler_SendScanReport
will obtain the information of APs via Wi-Fi Manager in the environment, and sort out the AP list.
static int _OPL_DataHandler_SendScanReport(void)
{
wifi_scan_info_t *pstAPList = NULL;
wifi_auto_connect_info_t *info = NULL;
T_WmScanInfo *pstWifiAPList = NULL;
uint8_t u8APPAutoConnectGetApNum = 0;
// uint8_t u8IsUpdate = false;
uint16_t u16apCount = 0;
int32_t i = 0, j = 0;
// TODO: get ap number
Opl_Wifi_ApNum_Get(&u16apCount);
OPL_LOG_INFO(OPL, "AP num = %d", u16apCount);
pstAPList = (wifi_scan_info_t *)malloc(sizeof(wifi_scan_info_t) * u16apCount);
// TODO: get ap record
Opl_Wifi_ApRecord_Get(&u16apCount, pstAPList);
pstWifiAPList = (T_WmScanInfo *)malloc(sizeof(T_WmScanInfo) * u16apCount);
memset(pstWifiAPList , 0 , sizeof(T_WmScanInfo) * u16apCount);
// TODO: get auto connect ap number
Opl_Wifi_AutoConnectApNum_Get(&u8APPAutoConnectGetApNum);
if (u8APPAutoConnectGetApNum)
{
info = (wifi_auto_connect_info_t *)malloc(sizeof(wifi_auto_connect_info_t) * u8APPAutoConnectGetApNum);
memset(info, 0, sizeof(wifi_auto_connect_info_t) * u8APPAutoConnectGetApNum);
for (i = 0; i < u8APPAutoConnectGetApNum; i++)
{
// TODO: get auto connected ap info
Opl_Wifi_AutoConnectApInfo_Get(i, info + i);
}
/* build blewifi ap list */
for (i = 0; i < u16apCount; ++i)
{
memcpy(pstWifiAPList[i].ssid, pstAPList[i].ssid, sizeof(pstAPList[i].ssid));
memcpy(pstWifiAPList[i].bssid, pstAPList[i].bssid, WIFI_MAC_ADDRESS_LENGTH);
pstWifiAPList[i].rssi = pstAPList[i].rssi;
pstWifiAPList[i].auth_mode = pstAPList[i].auth_mode;
pstWifiAPList[i].ssid_length = strlen((const char *)pstAPList[i].ssid);
pstWifiAPList[i].connected = 0;
#if (1 == FLITER_STRONG_AP_EN)
pstWifiAPList[i].u8IgnoreReport = false;
#endif
for (j = 0; j < u8APPAutoConnectGetApNum; j++)
{
if ((info+j)->ap_channel)
{
if(!memcmp(pstWifiAPList[i].ssid, (info+j)->ssid, sizeof((info+j)->ssid)) && !memcmp(pstWifiAPList[i].bssid, (info+j)->bssid, sizeof((info+j)->bssid)))
{
pstWifiAPList[i].connected = 1;
break;
}
}
}
}
/* Send Data to BLE */
/* Send AP inforamtion individually */
for (i = 0; i < u16apCount; ++i)
{
#if (1 == FLITER_STRONG_AP_EN)
if(true == pstWifiAPList[i].u8IgnoreReport)
{
continue;
}
#endif
if(pstWifiAPList[i].ssid_length != 0)
{
_OPL_DataHandler_SendSignalScanReport(1, &pstWifiAPList[i]);
osDelay(100);
}
}
if (pstAPList)
free(pstAPList);
if (pstWifiAPList)
free(pstWifiAPList);
if (info)
free(info);
return ubAppErr;
}
_OPL_DataHandler_SendSignalScanReport
will organize the AP list
static void _OPL_DataHandler_SendSignalScanReport(uint16_t apCount, T_WmScanInfo *ap_list)
{
uint8_t *data;
int data_len;
uint8_t *pos;
int malloc_size = sizeof(T_WmScanInfo) * apCount;
pos = data = malloc(malloc_size);
if (data == NULL)
{
OPL_LOG_ERRO(OPL, "malloc fail");
return;
}
for (int i = 0; i < apCount; ++i)
{
uint8_t len = ap_list[i].ssid_length;
data_len = (pos - data);
*pos++ = len;
memcpy(pos, ap_list[i].ssid, len);
pos += len;
memcpy(pos, ap_list[i].bssid,6);
pos += 6;
*pos++ = ap_list[i].auth_mode;
*pos++ = ap_list[i].rssi;
#ifdef CK_DATA_USE_CONNECTED
*pos++ = ap_list[i].connected;
#else
*pos++ = 0;
#endif
}
data_len = (pos - data);
/* create scan report data packet */
OPL_DataSendEncap(OPL_DATA_RSP_SCAN_REPORT, data, data_len);
free(data);
}
OPL_DataSendEncap
is responsible for packing data in accordance with BLE packet format.
void OPL_DataSendEncap(uint16_t u16Type, uint8_t *pu8Data, uint32_t u32TotalDataLen)
{
T_OplDataHdrTag *tHdrTag = NULL;
int remain_len = u32TotalDataLen;
/* 1.fragment data packet to fit MTU size */
/* 2.Pack blewifi header */
tHdrTag = malloc(sizeof(T_OplDataHdrTag) + remain_len);
if (tHdrTag == NULL)
{
OPL_LOG_ERRO(OPL, "malloc fail");
return;
}
tHdrTag->u16EventId = u16Type;
tHdrTag->u16DataLen = remain_len;
if (tHdrTag->u16DataLen)
memcpy(tHdrTag->au8Data, pu8Data, tHdrTag->u16DataLen);
/* 3.send app data to BLE stack */
Opl_Ble_Send_Message(OPL_SVC_EVT_SEND_DATA, (uint8_t *)tHdrTag, (tHdrTag->u16DataLen + sizeof(T_OplDataHdrTag)), 0);
free(tHdrTag);
}
Opl_Ble_Send_Message
is responsible for sending scan done result (e.g. AP list) to phone via BLE Manager.