Desarrolle una aplicación de IA con la luz de relleno de la unidad HDF de Hongmeng (5)

Prefacio

En el artículo anterior, ejecutamos el primer programa en Hongmeng. En este artículo, escribiremos una luz de relleno infrarroja que impulsa la cámara. Por cierto, nos familiarizaremos con el desarrollo del controlador HDF en Hongmeng.

 

# 2020 征文 - 发展 板 # Desarrolle aplicaciones de IA con la luz de relleno de la unidad HDF de Hongmeng (5)

 

Para la preparación del hardware,
primero consulte el diagrama esquemático (consulte la información del hardware en el primer artículo para obtener más detalles) y busque el número de puerto IO de la luz infrarroja, GPIO5_1.

# 2020 征文 - 发展 板 # Desarrolle aplicaciones de IA con la luz de relleno de la unidad HDF de Hongmeng (5)

Desarrollo de controladores HDF
1. Introducción El
marco de controladores HDF (OpenHarmony Driver Foundation) proporciona capacidades de marco de controladores para los desarrolladores de controladores, incluida la carga de controladores, la gestión de servicios de controladores y los mecanismos de mensajes del controlador. Su objetivo es construir una plataforma de arquitectura de unidades unificada para proporcionar a los desarrolladores de unidades un entorno de desarrollo más preciso y eficiente, y esforzarse por lograr un desarrollo único y una implementación de múltiples sistemas.

El marco HDF toma el modelo de unidad basado en componentes como la idea de diseño central para proporcionar a los desarrolladores una gestión de unidades más refinada y hacer que el desarrollo y la implementación de unidades sean más estandarizados. El marco HDF coloca una clase de controladores de dispositivo en el mismo host. Los desarrolladores que impulsan la implementación interna también pueden desarrollar e implementar las funciones del controlador de forma independiente en capas y admitir un controlador para varios nodos. El modelo de controlador de administración del marco HDF se muestra en la siguiente figura:

# 2020 征文 - 发展 板 # Desarrolle aplicaciones de IA con la luz de relleno de la unidad HDF de Hongmeng (5)

 

2. Driver Framework
2.1 El driver framework se da cuenta
de crear una nueva carpeta bajo el directorio huawei / hdf, y luego crea un archivo fuente led.c en ella.

#include "hdf_device_desc.h" // El marco HDF abre el archivo de encabezado de la interfaz de capacidad relevante al controlador 
#include "hdf_log.h" // El archivo de encabezado de la interfaz de registro proporcionado por el marco HDF 

#define HDF_LOG_TAG led_driver // Imprime las etiquetas contenidas en el registro, Si no está definida, use la etiqueta HDF_TAG definida por defecto 

// impulse las capacidades de servicio proporcionadas al mundo exterior y vincule la interfaz de servicio relevante al marco HDF 
int32_t HdfLedDriverBind (struct HdfDeviceObject * deviceObject) 
{ 
    HDF_LOGD ("Led driver bind success"); 
    return 0 ; 
} 

// Interfaz inicial propia del controlador 
int32_t HdfLedDriverInit (struct HdfDeviceObject * deviceObject) 
{ 
    if (deviceObject == NULL) { 
        HDF_LOGE ("Led driver Init fall!"); 
        Return HDF_ERR_INVALID_OBJECT; 
    } 
    HDF_LOGD ("Led driver Init éxito" ); 
    return HDF_SUCCESS;
}

// Interfaz de liberación de recursos del controlador 
void HdfLedDriverRelease (struct HdfDeviceObject * deviceObject) 
{ 
    if (deviceObject == NULL) { 
        HDF_LOGE ("Error en la liberación del controlador LED"); 
        return; 
    } 

    HDF_LOGD ("Lanzamiento exitoso del controlador LED"); 
    return; 
}

2.2 Registre la entrada del controlador en el marco HDF

// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
struct HdfDriverEntry g_ledDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "led_driver",
    .Bind = HdfLedDriverBind,
    .Init = HdfLedDriverInit,
    .Release = HdfLedDriverRelease,
};

// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_ledDriverEntry);

3. 驱动编译

在 huawei/hdf/led 目录下新建编译文件 Makefile

include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk  #导入hdf预定义内容,必需

MODULE_NAME := hdf_led_driver  #生成的结果文件
LOCAL_SRCS += led.c  #本驱动的源代码文件
LOCAL_INCLUDE := ./include  #本驱动的头文件目录
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror  #自定义的编译选项
include $(HDF_DRIVER)  #导入模板makefile完成编译

这里的hdf_led_driver为驱动文件名,注意对应关系。

 

4. 编译结果链接到内核镜像

修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码

LITEOS_BASELIB += -lhdf_led_driver  #链接生成的静态库
LIB_SUBDIRS    += $(VENDOR_HDF_DRIVERS_ROOT)/led  #驱动代码Makefile的目录

填入驱动文件名和源码路径。

 

5. 驱动配置

驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息。

5.1 驱动设备描述(必选)
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述。

修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。

platform :: host {
    hostName = "platform_host";  // host名称,host节点是用来存放某一类驱动的容器
    priority = 50;  // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序

    device_led :: device {                  // led设备节点
        device0 :: deviceNode {             // led驱动的DeviceNode节点
            policy = 2;                     // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍
            priority = 100;                 // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
            preload = 0;                    // 驱动按需加载字段
            permission = 0666;              // 驱动创建设备节点权限
            moduleName = "led_driver";      // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
            serviceName = "led_service";    // 驱动对外发布服务的名称,必须唯一
            deviceMatchAttr = "led_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
        }
    }

其中,moduleName、serviceName和deviceMatchAttr 都比较重要,分布链接到源码的不同位置,我这里都分开命名,便于理解。

 

5.2 驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考驱动开发)传递给驱动。

在 vendor/hisi/hi35xx/hi3516dv300/config/ 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led_config.hcs, 填入以下代码。

root {
    LedDriverConfig {
        led_version = 1;
        match_attr = "led_config";   //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致
    }
}

配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs。

 

5.3 板级配置(可选)
修改 vendor/hisi/hi35xx/hi3516dv300/config/hdf.hcs文件,添加代码

#include "device_info/device_info.hcs"
#include "led/led_config.hcs"

 

6. 驱动消息机制管理

当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。用消息管理可以在用户态和内核态之间架起桥梁,这为我们之后的APP提供了操控底层设备功能的能力。

这里我们在用户态实现一个简单的消息机制,内核态接受到消息后,翻转摄像头两侧的红外补光灯。

 

6.1 配置服务策略
HDF框架定了驱动对外发布服务的策略,是由配置文件中的policy字段来控制。

typedef enum {
    /* 驱动不提供服务 */
    SERVICE_POLICY_NONE = 0,
    /* 驱动对内核态发布服务 */
    SERVICE_POLICY_PUBLIC = 1,
    /* 驱动对内核态和用户态都发布服务 */
    SERVICE_POLICY_CAPACITY = 2,
    /* 驱动服务不对外发布服务,但可以被订阅 */
    SERVICE_POLICY_FRIENDLY = 3,
    /* 驱动私有服务不对外发布服务,也不能被订阅 */
    SERVICE_POLICY_PRIVATE = 4,
    /* 错误的服务策略 */
    SERVICE_POLICY_INVALID
} ServicePolicy;

我们将驱动配置信息中服务策略policy字段设置为2,在之前的设备描述文件device_info.hcs里已经配置好了。

 

6.2 实现服务
在第2章,我们实现了一个空的驱动框架,现在继续实现内核态的消息服务接口。

编辑 huawei/hdf/led/led.c, 实现服务基类成员IDeviceIoService中的Dispatch方法。收到用户态发来的命令后,操作LED设备,然后将返回值通过reply传回,最后再将收到的命令回传给用户态程序。

// Dispatch是用来处理用户态发下来的消息
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    int32_t result = HDF_FAILURE;
    HDF_LOGE("Led driver dispatch");
    if (client == NULL || client->device == NULL)
    {
        HDF_LOGE("Led driver device is NULL");
        return HDF_ERR_INVALID_OBJECT;
    }

    switch (cmdCode)
    {
    case LED_WRITE_READ:
        const char *recv = HdfSbufReadString(data);
        if (recv != NULL)
        {
            HDF_LOGI("recv: %s", recv);
            result = CtlLED(-1);  # 操作设备
            // CtlLED(GPIO_VAL_HIGH);
            if (!HdfSbufWriteInt32(reply, result))
            {
                HDF_LOGE("replay is fail");
            }
            return HdfDeviceSendEvent(client->device, cmdCode, data);
        }
        break;

    default:
        break;
    }
    return result;
}

修改 HdfLedDriverBind函数,将服务绑定到框架。

//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL)
    {
        HDF_LOGE("Led driver bind failed!");
        return HDF_ERR_INVALID_OBJECT;
    }
    static struct IDeviceIoService ledDriver = {
        .Dispatch = LedDriverDispatch,
    };
    deviceObject->service = (struct IDeviceIoService *)(&ledDriver);
    HDF_LOGD("Led driver bind success");
    return HDF_SUCCESS;
}

 

7. 业务代码
内核态核心功能,就简单实现一个每调用一次,就翻转一下LED状态的CtrlLED函数。这里mode为 -1 时为翻转,也可以直接指定高电平或低电平来开关,方便后续扩展。

其中Hi3516DV300的控制器管理12组GPIO管脚,每组8个。

GPIO号 = GPIO组索引(0~11)* 每组GPIO管脚数(8) + 组内偏移。

那么GPIO5_1的GPIO号 = 5 * 8 +1 = 41。

 

static int32_t CtlLED(int mode)
{
    int32_t ret;
    uint16_t valRead;
    /* LED的GPIO管脚号 */
    uint16_t gpio = 5 * 8 + 1;  // 红外补光灯
    // uint16_t gpio = 2 * 8 + 3;  // 绿色指示灯
    // uint16_t gpio = 3 * 8 + 4;  // 红色指示灯

    /* 将GPIO管脚配置为输出 */
    ret = GpioSetDir(gpio, GPIO_DIR_OUT);
    if (ret != 0)
    {
        HDF_LOGE("GpioSerDir: failed, ret %d\n", ret);
        return ret;
    }

    if (mode == -1)
    {
        // 翻转输出口
        (void)GpioRead(gpio, &valRead);
        ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
    }
    else
    {
        ret = GpioWrite(gpio, mode);
    }

    if (ret != 0)
    {
        HDF_LOGE("GpioWrite: failed, ret %d\n", ret);
        return ret;
    }
    return ret;
}

同理,GPIO2_3、GPIO3_4和蜂鸣器组件等等通用IO设备也能相应控制,可以尽情发挥想象力了。

 

8. 配置Kconfig

在`vendor/huawei/hdf/led/`下,新建一个目录`driver`,再在其下新建`Kconfig`文件。

config LOSCFG_DRIVERS_HDF_PLATFORM_LED
    bool "Enable HDF LED driver"
    default n
    depends on LOSCFG_DRIVERS_HDF_PLATFORM
    help
      Answer Y to enable HDF LED driver.

将其链接到板级Kconfig中,在vendor/huawei/hdf/Kconfig增加

source "../../vendor/huawei/hdf/led/driver/Kconfig"

好了,内核态的程序基本都搞定了。

 

9. Programa en modo usuario
Empezamos a escribir un programa principal para interactuar con el modo kernel a través de un mecanismo de mensajes.

Cree una nueva aplicación / muestra / cámara / myApp / my_led_app.c archivo fuente:

9.1 Defina el parámetro
led_service como el nombre del servicio, que debe coincidir con el definido previamente; LED_WRITE_READ es el identificador del comando, y el modo de usuario y el modo de kernel lo usan para identificar el tipo de mensaje.

#define LED_WRITE_READ 1 
#define HDF_LOG_TAG LED_APP 
#define LED_SERVICE "led_service"

 

9.2 Envío de un mensaje
Primero implemente una función SendEvent para enviar un mensaje Después de enviar un comando de cadena, el valor de retorno después de operar el dispositivo en el estado del kernel response se recupera y se imprime en replyData. Esta operación devuelve 0 con éxito.

Para el contenido de seguimiento y los archivos adjuntos relacionados del artículo, puede hacer clic en el enlace original a continuación para ir al enlace original para aprender
: https://harmonyos.51cto.com/posts/2820#bkwz


Para obtener más información sobre Hongmeng, visite:

Comunidad tecnológica de Hongmeng creada por la cooperación estratégica oficial 51CTO y Huawei

https://harmonyos.51cto.com/#bkwz


Supongo que te gusta

Origin blog.51cto.com/14901125/2595628
Recomendado
Clasificación