OpenHarmony HDF WIFI之WLAN_HDI(中) 原创 精华
下面就以createFeature()为例,学习feature的函数是如何发送命令到wifi驱动的。
//createFeature调用CreateFeatureInner
static int32_t CreateFeatureInner(int32_t type, struct IWiFiBaseFeature **ifeature)
{
//init feature
ret = InitFeatureByType(type, ifeature);
ret = FindValidNetwork(type, ifeature);
return HDF_SUCCESS;
}
//根据不同类型的feature,调用不同的接口
static int32_t InitFeatureByType(int32_t type, struct IWiFiBaseFeature **ifeature)
{
int32_t ret;
switch (type) {
case PROTOCOL_80211_IFTYPE_AP:
*ifeature = (struct IWiFiBaseFeature *)malloc(sizeof(struct IWiFiAp));
(void)memset_s(*ifeature, sizeof(struct IWiFiAp), 0, sizeof(struct IWiFiAp));
ret = InitApFeature((struct IWiFiAp **)ifeature);
break;
case PROTOCOL_80211_IFTYPE_STATION:
*ifeature = (struct IWiFiBaseFeature *)malloc(sizeof(struct IWiFiSta));
(void)memset_s(*ifeature, sizeof(struct IWiFiSta), 0, sizeof(struct IWiFiSta));
ret = InitStaFeature((struct IWiFiSta **)ifeature);
break;
default:
HDF_LOGE("%s: type not support, line: %d", __FUNCTION__, __LINE__);
return HDF_FAILURE;
}
return ret;
}
首先调用InitBaseFeature()来初始化basefeature,再添加IWiFiSta独有的函数。
int32_t InitStaFeature(struct IWiFiSta **fe)
{
if (InitBaseFeature((struct IWiFiBaseFeature **)fe) != HDF_SUCCESS) {
HDF_LOGE("%s: init base feature, line: %d", __FUNCTION__, __LINE__);
return HDF_FAILURE;
}
(*fe)->setScanningMacAddress = SetScanningMacAddress;
(*fe)->startScan = StartScan;
return HDF_SUCCESS;
}
创建完成IWiFiSta,就可以使用其接口来发送WIFI命令。
下面就以startScan命令为例子,加上互斥锁是因为wifi芯片同一时间只能响应一个命令。
static int32_t StartScan(const char *ifName, WifiScan *scan)
{
//加互斥锁,不能被其他命令打断执行
HalMutexLock();
//StartScanInner()最终调用sbuf_cmd_adapter.c中的WifiCmdScan()
int32_t ret = StartScanInner(ifName, scan);
HalMutexUnlock();
return ret;
}
StartScanInner()最终调用sbuf_cmd_adapter.c中的WifiCmdScan():
int32_t WifiCmdScan(const char *ifName, WifiScan *scan)
{
int32_t ret;
struct HdfSBuf *data = NULL;
data = HdfSBufObtainDefaultSize();
bool isSerializeFailed = false;
isSerializeFailed = isSerializeFailed || !HdfSbufWriteString(data, ifName);
if (scan->bssid == NULL) {
isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->bssid, 0);
} else {
isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->bssid, ETH_ADDR_LEN);
}
isSerializeFailed =
isSerializeFailed || !HdfSbufWriteBuffer(data, scan->ssids, sizeof(scan->ssids[0]) * scan->numSsids);
isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->extraIes, scan->extraIesLen);
isSerializeFailed =
isSerializeFailed || !HdfSbufWriteBuffer(data, scan->freqs, sizeof(scan->freqs[0]) * scan->numFreqs);
isSerializeFailed = isSerializeFailed || !HdfSbufWriteUint8(data, scan->prefixSsidScanFlag);
isSerializeFailed = isSerializeFailed || !HdfSbufWriteUint8(data, scan->fastConnectFlag);
if (isSerializeFailed) {
HILOG_ERROR(LOG_DOMAIN, "%s: Serialize failed!", __FUNCTION__);
ret = RET_CODE_FAILURE;
} else {
//发送命令给WLAN 驱动
ret = SendCmdSync(WIFI_WPA_CMD_SCAN, data, NULL);
}
HdfSBufRecycle(data);
return ret;
}
sbuf_cmd_adapter.c中的函数把所有的WIFI命令封装成sbuf类型,并调用 HDF 驱动的消息机制给 HDF_WIFI驱动发送命令。
static int32_t SendCmdSync(const uint32_t cmd, struct HdfSBuf *reqData, struct HdfSBuf *respData)
{
int32_t ret = g_wifiService->dispatcher->Dispatch(&g_wifiService->object, cmd, reqData, respData);
return ret;
}
1.3、Client
SendCmdSync()函数中使用了 g_wifiService 变量,该变量是 HdfIoService类型,在调用IWiFi的start方法时,会初始化该变量:
int32_t WifiDriverClientInit(void)
{
int32_t ret;
if (g_wifiService == NULL) {
//绑定 hdfwifi 服务
g_wifiService = HdfIoServiceBind(DRIVER_SERVICE_NAME);
}
//注册回调函数
g_wifiDevEventListener.onReceive = OnWiFiEvents;
return ret;
}
除了绑定服务,向服务发送消息外,还注册了回调函数OnWiFiEvents(),在该函数中,根据eventId调用不同的函数来处理驱动上报的消息,把消息从sbuf转换成普通的类型数据。(如何注册回调函数看最后)
int OnWiFiEvents(struct HdfDevEventlistener *listener,struct HdfIoService *service, uint32_t eventId, struct HdfSBuf *data)
{
const char *ifName = HdfSbufReadString(data);
//处理不同的wifi事件
switch (eventId) {
case WIFI_EVENT_NEW_STA:
WifiEventNewStaProcess(ifName, eventId, data);
break;
case WIFI_EVENT_DEL_STA:
WifiEventDelStaProcess(ifName, eventId, data);
break;
......
default:
break;
}
}
//以WifiEventNewStaProcess为例子
static void WifiEventNewStaProcess(const char *ifName, uint32_t event, struct HdfSBuf *reqData)
{
WifiNewStaInfo staInfo;
//提取reqData的数据到staInfo
if (!HdfSbufReadInt32(reqData, &staInfo.reassoc)) {
HILOG_ERROR(LOG_DOMAIN, "%s: fail to get reassoc", __FUNCTION__);
return;
}
if (!HdfSbufReadBuffer(reqData, (const void **)(&staInfo.ie), &staInfo.ieLen)) {
HILOG_ERROR(LOG_DOMAIN, "%s: fail to get ie", __FUNCTION__);
return;
}
if (!HdfSbufReadBuffer(reqData, (const void **)(&staInfo.macAddr), &len) || (len != ETH_ADDR_LEN)) {
HILOG_ERROR(LOG_DOMAIN, "%s: fail to get macAddr", __FUNCTION__);
return;
}
//上报到IWiFi
WifiEventReport(ifName, event, &staInfo);
}
WifiEventReport()调用HAL 层注册的回调函数:
void WifiEventReport(const char *ifName, uint32_t event, void *data)
{
uint32_t i;
//IWiFi 注册的回调函数保存在g_callbackEventMap
for (i = 0; i < MAX_CALL_BACK_COUNT; i++) {
if (g_callbackEventMap[i] != NULL && (strcmp(g_callbackEventMap[i]->ifName, ifName) == 0) &&
(((1 << event) & g_callbackEventMap[i]->eventType) != 0)) {
//调用回调函数 通知事件的发送
g_callbackEventMap[i]->onRecFunc(event, data, ifName);
}
}
}
二、HDI Service
HAL层的上一层是HDI Service,他将WLAN HAL层的IWiFiSta、IWiFiAp、IWiFiBaseFeature封装到一个对象 IWifiInterface 中,使其更方便用户使用。
HDI Service 分为两个部分:
- Services:作为HDF驱动模块,调用WLAN HAL 提供的对象,并提供服务给IWifiInterface。
- IWifiInterface:订阅 HDI Service驱动服务,提供统一接口给用户。
2.1、Service
作为一个HDF驱动模块,他必须有初始化函数,bind函数:
struct HdfDriverEntry g_wlanHdiDriverEntry = {
.moduleVersion = 1,
.moduleName = "wlan_device",
.Bind = HdfWlanHdiDriverBind,
.Init = HdfWlanHdiDriverInit,
.Release = HdfWlanHdiDriverRelease,
};
HDF_INIT(g_wlanHdiDriverEntry);
重点是dispatch()函数的实现:WlanHdiServiceDispatch()
在WlanHdiServiceOnRemoteRequest()中根据命令id调用不同的函数,这些函数最终都会调用WLAN HAL层提供的接口。
static int32_t WlanHdiServiceDispatch(struct HdfDeviceIoClient *client, int cmdId,
struct HdfSBuf *data, struct HdfSBuf *reply)
{
return WlanHdiServiceOnRemoteRequest(client, cmdId, data, reply);
}
int32_t WlanHdiServiceOnRemoteRequest(struct HdfDeviceIoClient *client, int cmdId,
struct HdfSBuf *data, struct HdfSBuf *reply)
{
switch (cmdId) {
case WLAN_SERVICE_CONSTRUCT:
return HdiWifiConstruct(client, data, reply);
case WLAN_SERVICE_DECONSTRUCT:
return HdiWifiDeConstruct(client, data, reply);
case WLAN_SERVICE_START:
return WlanServiceStubStart(client, data, reply);
......
default:
HDF_LOGW("SampleServiceDispatch: not support cmd %d", cmdId);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
例如:WlanServiceStubStart()
static int32_t WlanServiceStubStart(struct HdfDeviceIoClient *client, struct HdfSBuf *data, struct HdfSBuf *reply)
{
ret = g_wifi->start(g_wifi);
return ret;
}
2.2、IWifiInterface
IWifiInterface对象通过订阅HDI Service驱动服务,把所有的WIFI命令整合到一起,相比直接使用HAL 层接口更加简单方便。
调用HdIWifiInterfaceGet会帮我们创建IWifiInterface对象:
struct IWifiInterface *HdIWifiInterfaceGet(const char *serviceName)
{
struct HDIServiceManager *serviceMgr = HDIServiceManagerGet();
//绑定hdi service
struct HdfRemoteService *remote = serviceMgr->GetService(serviceMgr, serviceName);
//create IWifiInterface
struct IWifiInterface *wlanClient = (struct IWifiInterface *)OsalMemAlloc(sizeof(struct IWifiInterface));
wlanClient->remote = remote;
IwifiConstruct(wlanClient);
return wlanClient;
}
//构建IWifiInterface对象
static void IwifiConstruct(struct IWifiInterface *inst)
{
inst->construct = WlanConstruct;
inst->destruct = WlanDestruct;
......
inst->getNetDevInfo = WlanGetNetDevInfo;
inst->startScan = WlanStartScan;
}
IWifiInterface 使用HDF 驱动消息机制 来和service通信,以WlanStart命令为例子:
static int32_t WlanStart(struct IWifiInterface *self)
{
int32_t ec = HDF_FAILURE;
//创建sbuf
struct HdfSBuf *data = HdfSBufTypedObtain(SBUF_IPC);
struct HdfSBuf *reply = HdfSBufTypedObtain(SBUF_IPC);
//发送WLAN_SERVICE_START命令
ec = WlanProxyCall(self, WLAN_SERVICE_START命令, data, reply);
}
static int32_t WlanProxyCall(struct IWifiInterface *self, int32_t id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
//给 hdi service驱动服务发送消息
return self->remote->dispatcher->Dispatch(self->remote, id, data, reply);
}
三、注册WLAN回调函数
HAL 层提供了回调函数来监听wifi event。具体的实现是在wifi_driver_client.c
HalRegisterEventCallback()实现将onRecFunc函数赋值到全局变量g_callbackEventMap[];
static int32_t HalRegisterEventCallback(OnReceiveFunc onRecFunc, const char *ifName)
{
HalMutexLock();
int32_t ret = RegisterEventCallbackInner(onRecFunc, ifName);
HalMutexUnlock();
return ret;
}
static int32_t RegisterEventCallbackInner(OnReceiveFunc onRecFunc, const char *ifName)
{
if (WifiRegisterEventCallback(onRecFunc, WIFI_KERNEL_TO_HAL_CLIENT, ifName) != HDF_SUCCESS) {
HDF_LOGE("%s: callback function has been registered, line: %d", __FUNCTION__, __LINE__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t WifiRegisterEventCallback(OnReceiveFunc onRecFunc, uint32_t eventType, const char *ifName)
{
uint32_t i;
struct CallbackEvent *callbackEvent = NULL;
for (i = 0; i < MAX_CALL_BACK_COUNT; i++) {
//checkout event type and ifname
if (g_callbackEventMap[i] != NULL && g_callbackEventMap[i]->eventType == eventType &&
(strcmp(g_callbackEventMap[i]->ifName, ifName) == 0) && g_callbackEventMap[i]->onRecFunc == onRecFunc)
{
HILOG_INFO(LOG_DOMAIN, "%s the onRecFunc has been registered!", __FUNCTION__);
return RET_CODE_SUCCESS;
}
}
//create new callbackEvent
callbackEvent = (struct CallbackEvent *)malloc(sizeof(struct CallbackEvent));
//config callbackEvent
callbackEvent->eventType = eventType;
if (strcpy_s(callbackEvent->ifName, IFNAMSIZ, ifName) != RET_CODE_SUCCESS) {
free(callbackEvent);
return RET_CODE_FAILURE;
}
callbackEvent->onRecFunc = onRecFunc;
//add onRecFunc to the g_callbackEventMap[]
for (i = 0; i < MAX_CALL_BACK_COUNT; i++) {
if (g_callbackEventMap[i] == NULL) {
g_callbackEventMap[i] = callbackEvent;
return RET_CODE_SUCCESS;
}
}
free(callbackEvent);
HILOG_ERROR(LOG_DOMAIN, "%s fail: register onRecFunc num more than %d!", __FUNCTION__, MAX_CALL_BACK_COUNT);
return RET_CODE_FAILURE;
}
g_callbackEventMap[]是固定长度的数组,其中存放所有wifi事件的回调函数,wifi event的类型定义在wifi_common_cmd.h中。
struct CallbackEvent {
uint32_t eventType; //eventmap
char ifName[IFNAMSIZ + 1];
OnReceiveFunc onRecFunc;
};
static struct CallbackEvent *g_callbackEventMap[MAX_CALL_BACK_COUNT] = {NULL};