本帖最后由 symic 于 2022-8-27 07:47 编辑
学习了一段时间后,准备试用将E53接口的模块与 小熊派BearPi-HM Micro进行联试。手头正好由一款ES53-SC1智能灯模块,可实现光线感应及智能灯光的功能。
E53接口是适用于小熊派系列的外界模块接口,
由于需要与驱动打交道,这里还是参考南向的开发方法。
1、首先是驱动的开发,在device\st\driver下创建一个名叫e53_driver\E53_SC1文件夹,新建2个文件:驱动文件E53_SC1_hdf.c和编译构建文件BUILD.gn 。
E53_SC1_hdf.c负责驱动源码的编制,按照linux的标准模板,添加相应的内容。如:
static int32_t Hdf_E53_SC1_DriverInit(struct HdfDeviceObject *device) //实现初始化
static int32_t Hdf_E53_SC1_DriverBind(struct HdfDeviceObject *deviceObject) //实现将相关的服务接口绑定到HDF框架
void HdfE53sc1DriverRelease(struct HdfDeviceObject *deviceObject)// 驱动资源释放的接口
int32_t E53sc1DriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)// 处理用户态发下来的消息
其中最主要的是E53sc1DriverDispatch,该函数通过cmdCode命令来判断不同的用户命令参数。包括 E53_SC1_Start,E53_SC1_Stop, E53_SC1_Read, E53_SC1_SetLight。
nt32_t E53sc1DriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int ret = -1;
char *replay_buf;
HDF_LOGE("E53sc1 driver dispatch");
if (client == NULL || NULL == client->device)
{
HDF_LOGE("E53sc1 driver device is NULL");
return HDF_ERR_INVALID_OBJECT;
}
switch (cmdCode)
{
case E53_SC1_Start:
ret = E53_SC1Init();
if (ret != 0)
{
HDF_LOGE("E53sc1 Init err");
return HDF_FAILURE;
}
ret = HdfSbufWriteString(reply, "ES3_SC1 Init sucessful");
if (ret == 0)
{
HDF_LOGE("Reply failed\r\n");
return HDF_FAILURE;
}
break;
case E53_SC1_Stop:
ret = E53_SC1Init();
if (ret != 0)
{
HDF_LOGE("E53sc1 Init err");
return HDF_FAILURE;
}
ret = HdfSbufWriteString(reply, "ES3_SC1 Init sucessful");
if (ret == 0)
{
HDF_LOGE("Reply failed\r\n");
return HDF_FAILURE;
}
break;
case E53_SC1_Read:
ret = E53_SC1ReadData(&lux_data);
if (ret != 0)
{
HDF_LOGE("E53sc1 Read data err");
return HDF_FAILURE;
}
replay_buf = OsalMemAlloc(100);
(void)memset(replay_buf, 100, 0, 100);
sprintf(replay_buf, {\"Lux\":%.2f,\"LED\":\"%s\"}", lux_data, LightStatus ? "ON" : "OFF")
//把传感器数据写入reply, 可被带至用户程序
if(!HdfSbufWriteString(reply, rreply_buf))
{
HDF_LOGE("Reply failed\r\n");
return HDF_FAILURE;
}
osalMemFree(replay_buf);
break;
case E53_SC1_SetLight:
const char *readdata = HdfSbufReadString(data);
if (strcmp(readdata, "ON") == 0)
{
E53_SC1LightStatusSet(ON);
LightStaus = 1;
}
else if (strcmp(readdata, "OFF"))
{
E53_SC1LightStatusSet(OFF);
LightStaus = 0;
}
else
{
HDF_LOGE("Command wrong\r\n");
return HDF_FAILURE;
}
replay_buf = OsalMemAlloc(100);
(void) memset_s(replay_buf, 100, 0, 100);
sprintf(replay_buf, "{\"Lux\":%.2f,\"LED\":\"%s\"}", lux_data, LightStatus ? "ON" : "OFF");
/* 把传感器数据写入reply, 可被带至用户程序 */
if(!HdfSbufWriteString(reply, replay_buf))
{
HDF_LOGE("replay is fail");
return HDF_FAILURE;
}
osalMemFree(replay_buf);
brek;
default:
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
最后再调用驱动注册函数
struct HdfDriverEntry g_ledDriverEntry = {
.moduleVersion = 1,
.moduleName = "HDF_ES53_SC1",
.Bind = HdfE53sc1DriverBind,
.Init = HdfE53sc1DriverInit,
.Release = HdfE53sc1DriverRelease,
};
// 调用HDF_INIT将驱动入口注册到HDF框架中
HDF_INIT(g_E53sc1DriverEntry);
2、接下来需要再HDF框架中添加新建的设备驱动描述,具体是在device\st\bearpi_hm_micro\liteos_a\hdf_config\device_info\device_info.hcs,新增一项
device_e53 :: device {
priority = 30;
device_sc1 :: deviceNode {
policy = 2;
priority = 130;
preload = 1;
permission = 0777;
moduleName = "HDF_E53_SC1";
serviceName = "hdf_e53_sc1";
}
}
3、以上操作后底层的驱动工作基本完成,接上来需要开展JS接口层的开发,主要涉及需要修改的文件为app_module.h和app_module.c,文件路径在foundation\ace\ace_engine_lite\frameworks\src\core\modules\,内容是添加一个JS APIE53SC1Service
在app_module.h中添加声明
static JSIValue E53SC1Service(const JSIValue thisVal, const JSIValue* args, uint8_t argsNum);
并在void InitAppModule(JSIValue exports)中添加
JSI::SetModuleAPI(exports, "e53sc1service", AppModule::E53SC1Service);
在app_module.c中添加定义
static int E53SC1Control(struct HdfIoService *serv, int32_t cmd, const char* buf, char **val)
{
int ret = HDF_FAILURE;
struct HdfSBuf *data = HdfSBufObtainDefaultSize();
struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
if (data == NULL || reply == NULL) {
HILOG_ERROR(HILOG_MODULE_ACE,"fail to obtain sbuf data\n");
return ret;
}
if (!HdfSbufWriteString(data, buf))
{
HILOG_ERROR(HILOG_MODULE_ACE,"fail to write sbuf\n");
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
ret = serv->dispatcher->Dispatch(&serv->object, cmd, data, reply);
if (ret != HDF_SUCCESS)
{
HILOG_ERROR(HILOG_MODULE_ACE,"fail to send service call\n");
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
*val = (char *)(HdfSbufReadString(reply));
if(val ==NULL){
HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service call reply\n");
ret = HDF_ERR_INVALID_OBJECT;
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
HILOG_ERROR(HILOG_MODULE_ACE,"Get reply is: %s\n", *val);
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
JSIValue AppModule::E53SC1Service(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
{
struct HdfIoService *serv = HdfIoServiceBind(E53_SC1_SERVICE);
if (serv == NULL)
{
HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service %s\n", E53_SC1_SERVICE);
return JSI::CreateUndefined();
}
if ((args == nullptr) || (argsNum == 0) || (JSI::ValueIsUndefined(args[0]))) {
return JSI::CreateUndefined();
}
JSIValue success = JSI::GetNamedProperty(args[0], CB_SUCCESS);
JSIValue fail = JSI::GetNamedProperty(args[0], CB_FAIL);
JSIValue complete = JSI::GetNamedProperty(args[0], CB_COMPLETE);
int32_t cmd = (int32_t)JSI::GetNumberProperty(args[0], "cmd");
char *data = (char *)JSI::GetStringProperty(args[0], "data");
HILOG_ERROR(HILOG_MODULE_ACE, "cmd is: %d\n", cmd);
HILOG_ERROR(HILOG_MODULE_ACE,"data is: %s\n", data);
char *replyData;
if (E53SC1Control(serv, cmd, data, &replyData))
{
HILOG_ERROR(HILOG_MODULE_ACE,"fail to send event\n");
JSI::CallFunction(fail, thisVal, nullptr, 0);
JSI::CallFunction(complete, thisVal, nullptr, 0);
JSI::ReleaseValueList(success, fail, complete);
return JSI::CreateUndefined();
}
JSIValue result = JSI::CreateObject();
JSI::SetStringProperty(result, "e53_sc1", replyData);
JSIValue argv[ARGC_ONE] = {result};
JSI::CallFunction(success, thisVal, argv, ARGC_ONE);
JSI::CallFunction(complete, thisVal, nullptr, 0);
JSI::ReleaseValueList(success, fail, complete, result);
HdfIoServiceRecycle(serv);
return JSI::CreateUndefined();
}
4、最后配置编译依赖
在foundation\ace\ace_engine_lite\ace_lite.gni
中添加HDF头文件路径。
ace_lite_include_dirs += [
"//drivers/framework/ability/sbuf/include",
"//drivers/framework/include/core",
"//drivers/framework/include/utils",
"//drivers/adapter/uhdf/posix/include",
]
修改foundation\ace\ace_engine_lite\frameworks\BUILD.gn
,在public_deps
中添加以下代码
"//drivers/adapter/uhdf/manager:hdf_core",
修改foundation\ace\ace_engine_lite\test\ace_test_config.gni
,在extra_deps
中添加以下代码
"//drivers/adapter/uhdf/manager:hdf_core",
到此为止,驱动代码编写工作完成,通过编译完成后,使用STM32CubeProgrammer下载完成,具体参考之前的试用帖子
接下来是北向的JS应用的编写,这里可以先使用教程中原有的HAP文件:MicroE53.HAP,通过SD卡拷贝安装,
但是遇到的问题
在想试试使用SD卡安装HAP程序时,发现通过mount 加载时出现以下问题
目前还没解决。