Desenvolver aplicação de IA com luz de preenchimento de unidade HDF Hongmeng (5)

Prefácio

No artigo anterior, executamos o primeiro programa em Hongmeng. Neste artigo, escreveremos uma luz de preenchimento infravermelho que aciona a câmera. A propósito, vamos nos familiarizar com o desenvolvimento do driver HDF em Hongmeng.

 

# 2020 征文 - 发展 板 # Desenvolva aplicativos de IA com luz de preenchimento de unidade HDF Hongmeng (5)

 

Para a preparação do hardware,
primeiro verifique o diagrama esquemático (consulte as informações de hardware no primeiro artigo para obter detalhes) e encontre o número da porta IO da luz infravermelha, GPIO5_1.

# 2020 征文 - 发展 板 # Desenvolva aplicativos de IA com luz de preenchimento de unidade HDF Hongmeng (5)

Desenvolvimento de driver HDF
1. Introdução A
estrutura de driver HDF (OpenHarmony Driver Foundation) fornece recursos de estrutura de driver para desenvolvedores de driver, incluindo carregamento de driver, gerenciamento de serviço de driver e mecanismos de mensagem de driver. Seu objetivo é construir uma plataforma de arquitetura de drive unificada para fornecer aos desenvolvedores de drives um ambiente de desenvolvimento mais preciso e eficiente, e se esforça para alcançar um desenvolvimento único e implantação de vários sistemas.

A estrutura HDF considera o modelo de unidade com base em componentes como a ideia central de design para fornecer aos desenvolvedores um gerenciamento de unidade mais refinado e tornar o desenvolvimento e a implantação de unidades mais padronizados. A estrutura HDF coloca uma classe de drivers de dispositivo no mesmo host. Os desenvolvedores que conduzem a implementação interna também podem desenvolver e implantar as funções do driver independentemente em camadas e oferecer suporte a um driver para vários nós. O modelo de driver de gerenciamento da estrutura HDF é mostrado na figura a seguir:

# 2020 征文 - 发展 板 # Desenvolva aplicativos de IA com luz de preenchimento de unidade HDF Hongmeng (5)

 

2. Driver Framework
2.1 O driver framework realiza
a criação de uma nova pasta conduzida sob o diretório huawei / hdf, e então cria um arquivo fonte led.c dentro dela.

#include "hdf_device_desc.h" // A estrutura HDF abre o arquivo de cabeçalho da interface de capacidade relevante para o driver 
#include "hdf_log.h" // O arquivo de cabeçalho da interface de log fornecido pela estrutura HDF 

#define HDF_LOG_TAG led_driver // Imprime as marcas contidas no log, Se não estiver definida, use a tag HDF_TAG definida por padrão 

// direcionar os recursos de serviço fornecidos para o mundo externo e vincular a interface de serviço relevante à estrutura HDF 
int32_t HdfLedDriverBind (struct HdfDeviceObject * deviceObject) 
{ 
    HDF_LOGD ("Led driver bind success"); 
    retorno 0 ; 
} 

// Interface inicial de negócios do próprio driver 
int32_t HdfLedDriverInit (struct HdfDeviceObject * deviceObject) 
{ 
    if (deviceObject == NULL) { 
        HDF_LOGE ("Led driver Init falhou!"); 
        Return HDF_ERR_INVALID_OBJECT; 
    } 
    HDF_LOGD ("Led Init com sucesso"); ); 
    retornar HDF_SUCCESS;
}

// Interface de liberação de recursos do driver 
void HdfLedDriverRelease (struct HdfDeviceObject * deviceObject) 
{ 
    if (deviceObject == NULL) { 
        HDF_LOGE ("Falha na liberação do driver do led!"); 
        Return; 
    } 

    HDF_LOGD ("sucesso da liberação do driver do led") 
    ; 
}

2.2 Registrar a entrada do driver na estrutura 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 de modo de usuário
Começamos a escrever um programa principal para interagir com o modo de kernel por meio de um mecanismo de mensagem.

Crie um novo arquivo de origem application / sample / camera / myApp / my_led_app.c:

9.1 Defina o parâmetro
led_service como o nome do serviço, que deve corresponder ao definido anteriormente; LED_WRITE_READ é o identificador do comando, e o modo do usuário e o modo kernel usam este para identificar o tipo de mensagem.

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

 

9.2 Enviando uma mensagem
Implemente primeiro uma função SendEvent para enviar uma mensagem.Após enviar um comando string, o valor de retorno após operar o dispositivo no estado do kernel reply é recuperado e impresso em replyData. Esta operação retorna 0 com sucesso.

Para obter o conteúdo de acompanhamento e os anexos relacionados do artigo, você pode clicar no link original abaixo para ir para o link original de aprendizagem
: https://harmonyos.51cto.com/posts/2820#bkwz


Para saber mais sobre Hongmeng, visite:

Comunidade de tecnologia Hongmeng construída por 51CTO e cooperação estratégica oficial Huawei

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


Acho que você gosta

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