Использование Hongmeng для разработки приложений ИИ (5) Заполняющий свет на основе HDF

Android HarmonyOS
Использование Hongmeng для разработки приложений ИИ (5) Заполняющий свет на основе HDF

предисловие

В предыдущей статье мы запускали первую программу на Hongmeng.В этой статье напишем заполняющий инфракрасный свет, приводящий в действие камеру на включение.Кстати, ознакомимся с разработкой драйвера HDF на Hongmeng.

аппаратная подготовка

Сначала проверьте принципиальную схему (подробности см. в информации об оборудовании в первой статье) и найдите номер порта ввода-вывода инфракрасного источника света, GPIO5_1.

Разработка драйвера HDF

1. Введение

Платформа драйверов HDF (OpenHarmony Driver Foundation) предоставляет разработчикам драйверов возможности платформы драйверов, включая загрузку драйверов, управление службами драйверов и механизмы сообщений драйверов. Он направлен на создание унифицированной платформы архитектуры драйверов, предоставление разработчикам драйверов более точной и эффективной среды разработки, а также на достижение однократной разработки и развертывания нескольких систем.

Инфраструктура HDF использует компонентную модель драйвера в качестве основной идеи дизайна, предоставляет разработчикам более усовершенствованное управление драйверами и делает разработку и развертывание драйверов более стандартизированной. Платформа HDF помещает тип драйвера устройства на один и тот же хост, и разработчики также могут разрабатывать и развертывать функции драйвера независимо на уровнях и поддерживать несколько узлов для одного драйвера.Среда HDF управляет моделью драйвера, как показано на следующем рисунке:

2. Каркас драйверов

2.1 Реализация каркаса драйверов

существуетhuawei/hdfСоздайте новую папку в каталогеled, а затем создайте в нем новый исходный файлled.c.

#include "hdf_device_desc.h"  // HDF框架对驱动开放相关能力接口的头文件
#include "hdf_log.h"          // HDF 框架提供的日志接口头文件

#define HDF_LOG_TAG led_driver   // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签

//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Led driver bind success");
    return 0;
}

// 驱动自身业务初始的接口
int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("Led driver Init failed!");
        return HDF_ERR_INVALID_OBJECT;
    }
    HDF_LOGD("Led driver Init success");
    return HDF_SUCCESS;
}

// 驱动资源释放的接口
void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("Led driver release failed!");
        return;
    }

    HDF_LOGD("Led driver release success");
    return;
}

2.2 Зарегистрируйте запись драйвера в структуре 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 = 0664;              // 驱动创建设备节点权限
            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. Использование управления сообщениями может создать мост между режимом пользователя и режимом ядра, что дает нашему последующему ПРИЛОЖЕНИЮ возможность управлять функциями базового устройства.

Здесь мы реализуем простой механизм сообщений в пользовательском режиме.После того, как режим ядра получит сообщение, он перевернет инфракрасные заполняющие огни с обеих сторон камеры.

6.1 Настройка политики обслуживания

Платформа HDF определяет политику управления внешне опубликованными службами, которая управляется полем политики в файле конфигурации.

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;

Мы устанавливаем поле политики политики обслуживания в информации о конфигурации драйвера на 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. Бизнес-код

Основная функция режима ядра состоит в том, чтобы просто реализовать функцию, которая меняет состояние светодиода при каждом вызове.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. Программа пользовательского режима

Мы начали писать основную программу для взаимодействия с режимом ядра через механизм сообщений.

новыйapplications/sample/camera/myApp/my_led_app.cИсходный файл:

9.1 Определение параметров

led_serviceимя службы, которое должно совпадать с ранее определенным;LED_WRITE_READЭто идентификатор команды, который используется пользовательским режимом и режимом ядра для идентификации типа сообщения.

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

9.2 Отправка сообщения

Сначала реализуйте функцию для отправки сообщенияSendEvent, после отправки строковой команды восстановить режим ядраreplyВозвращаемое значение после работы устройства вreplyDataраспечатанный. Эта операция успешно возвращается0.

static int SendEvent(struct HdfIoService *serv, char *eventData)
{
    int ret = 0;
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL)
    {
        HDF_LOGE("fail to obtain sbuf data");
        return 1;
    }

    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL)
    {
        HDF_LOGE("fail to obtain sbuf reply");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }

    if (!HdfSbufWriteString(data, eventData))
    {
        HDF_LOGE("fail to write sbuf");
        ret = HDF_FAILURE;
        goto out;
    }

    ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS)
    {
        HDF_LOGE("fail to send service call");
        goto out;
    }

    int replyData = 0;
    if (!HdfSbufReadInt32(reply, &replyData))
    {
        HDF_LOGE("fail to get service call reply");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    HDF_LOGE("Get reply is: %d", replyData);
out:
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}

9.3 Настройка обратного вызова

Получив строку, отправленную состоянием ядра, просто напечатайте ее.

static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data)
{
    const char *string = HdfSbufReadString(data);
    if (string == NULL)
    {
        HDF_LOGE("fail to read string in event data");
        return HDF_FAILURE;
    }
    HDF_LOGE("%s: dev event received: %u %s", (char *)priv, id, string);

    return HDF_SUCCESS;
}

9.4 Основная программа

Сначала создайте службу и привяжите ее к соответствующему драйверу через имя службы. Затем настройте прослушивание, ожидание сообщений от ядра. Наконец каждый1отправить флипLEDинструкция.

int main(void)
{
    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE, 0);
    if (serv == NULL)
    {
        HDF_LOGE("fail to get service %s", LED_SERVICE);
        return HDF_FAILURE;
    }
    static struct HdfDevEventlistener listener = {
        .callBack = OnDevEventReceived,
        .priv = "Service0"};

    if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS)
    {
        HDF_LOGE("fail to register event listener");
        return HDF_FAILURE;
    }

    char *send_cmd = "toggle LED";
    while (1)
    {
        if (SendEvent(serv, send_cmd))
        {
            HDF_LOGE("fail to send event");
            return HDF_FAILURE;
        }
        sleep(1);
    }

    if (HdfDeviceUnregisterEventListener(serv, &listener))
    {
        HDF_LOGE("fail to  unregister listener");
        return HDF_FAILURE;
    }

    HdfIoServiceRecycle(serv);
    HDF_LOGI("exit");

    return HDF_SUCCESS;
}

9.5 Настройка BUILD.gn

существуетdrivers/hdf/lite/manager/BUILD.gnДобавьте следующий код для генерацииled_appприменение.

lite_component("hdf_manager") {
    features = [
        ":hdf_core",
        ":led_app",
    ]
}

executable("led_app") {
    sources = [
        "//applications/sample/camera/myApp/my_led_app.c"
        
    ]

    include_dirs = [
        "../adapter/syscall/include",
        "../adapter/vnode/include",
        "$HDF_FRAMEWORKS/ability/sbuf/include",        
        "$HDF_FRAMEWORKS/core/shared/include",
        "$HDF_FRAMEWORKS/core/host/include",
        "$HDF_FRAMEWORKS/core/master/include",
        "$HDF_FRAMEWORKS/include/core",
        "$HDF_FRAMEWORKS/include/utils",
        "$HDF_FRAMEWORKS/utils/include",
        "$HDF_FRAMEWORKS/include/osal",
        "//third_party/bounds_checking_function/include",
    ]
        
    deps = [
        "//drivers/hdf/lite/manager:hdf_core",
        "//drivers/hdf/lite/adapter/osal/posix:hdf_posix_osal",
    ]

    public_deps = [
        "//third_party/bounds_checking_function:libsec_shared",
        ]

    defines = [
        "__USER__",
    ]

    cflags = [
        "-Wall",
        "-Wextra",
        "-Werror",
    ]
}

10. Скомпилируйте и запишите

С этого момента мы будем использоватьHDFFramework, нужно использовать больше компонентов, просто скопируйте одинbuild\lite\product\ipcamera_hi3516dv300.jsonпереименовать вmy_hi3516dv300Вот и все.

python build.py my_hi3516dv300 -b debug

Процесс компиляции и записи упоминается в предыдущей статье и здесь повторяться не будет. Если все пойдет хорошо, запустите программу, и вы увидитеLEDСчастливое мерцание.

./bin/led_app

Инфракрасный свет не очень заметен невооруженным глазом, но под объективом он ярче, и диапазон освещения большой.Я проверю действие дополнительного света ночного видения позже.

Суммировать

Разработка драйверов включает в себя множество файлов и конфигураций, а отношения более сложны и разбросаны по разным каталогам.

Основные файлы перечислены здесь, а затем отсортированы:

Он примерно разделен на три части: режим ядра, пользовательский режим и конфигурация драйвера.

1. Состояние ядра

сначала поled.cсгенерировать названныйled_serviceуслугиg_ledDriverEntryструктура, зарегистрированная наHCSРамка. скомпилировано вhdf_led_driverобусловленhuawei/hdf/hdf_vendor.mkСсылка на образ ядра.

пройти черезHdfLedDriverBindфункция будетled_driverмодули привязаны к фреймворку,IDeviceIoServiceсерединаDispatchметод для обработки сообщений из пользовательского режима.

2. Пользовательский режим

пользовательский режим сHdfIoServiceBindпо названию службыled_serviceЧтобы найти соответствующий драйвер, используйтеHdfSbufWriteStringОтправить сообщение,serv->dispatcher->Dispatchдля получения возвращаемого значения черезHdfDeviceRegisterEventListenerНастройте прослушиватель, чтобы получать сообщения, активно отправляемые режимом ядра.

3. Конфигурация драйвера

с названием модуляled_driverнайти зарегистрированный наHCSдрайвер фреймворка (псевдоним на стороне ядра);

по названию службыled_service, подвергаемый вызову программы пользовательского режима или программы режима ядра (псевдоним на стороне пользователя);

отled_configЧастные файлы конфигурации, управляемые ссылкой. Два псевдонима не связаны в обоих направлениях и, наконец, связаны через файл конфигурации для обеспечения гибкости. Эта конструкция будет более удобной в распределенных случаях.

Скачать

Следующее уведомление

Этот выпуск в основном знакомит с разработкой драйверов HDF,

Интерфейсная часть оставлена ​​в следующем введении из-за места.

Быть в курсе...

Категории