[文章]

【HarmonyOS HiSpark AI Camera试用连载 】第七次眷恋-鸿蒙OS驱动服务的订阅机制

2021-1-14 23:08:21  336 鸿蒙os 驱动开发
分享

服务订阅

1
本帖最后由 瑟寒凌风 于 2021-1-14 23:10 编辑

谁?
我!
是你?
是我!
你终于来了!
我终于来了!
你终究是来了?
我终究是来了!
你来干什么!
我来写服务订阅!

鸿蒙lite-a的驱动开发,我们其实就是为了实现HdfDriverEntry结构体,驱动框架完成大部分驱动加载的动作,用户只需注册自己所需的接口和配置,然后驱动框架就会根据解析,完成驱动加载和初始化动作。
开发者基于HDF驱动框架开发的驱动主要包含三大部分:
1、驱动程序部分 - 完成驱动的功能逻辑
2、驱动配置信息 - 指示驱动的加载信息内容
3、驱动资源配置 - 配置驱动的硬件配置信息。
驱动程序主要是完成驱动功能的开发部分:
对于开发者首先看到的是驱动入口部分,驱动入口部分通过DriverEntry对齐进行描述。
其中主要包含bind, init 和release三个接口。
本文主要说的是驱动订阅服务。

要实现订阅,需要在device_info.hcs文件中修改policy字段,该字段policy是驱动服务发布的策略
  1. typedef enum {
  2. /* 驱动不提供服务 */
  3. SERVICE_POLICY_NONE = 0,
  4. /* 驱动对内核态发布服务 */
  5. SERVICE_POLICY_PUBLIC = 1,
  6. /* 驱动对内核态和用户态都发布服务 */
  7. SERVICE_POLICY_CAPACITY = 2,
  8. /* 驱动服务不对外发布服务,但可以被订阅 */
  9. SERVICE_POLICY_FRIENDLY = 3,
  10. /* 驱动私有服务不对外发布服务,也不能被订阅 */
  11. SERVICE_POLICY_PRIVATE = 4,
  12. /* 错误的服务策略 */
  13. SERVICE_POLICY_INVALID
  14. } ServicePolicy;
复制代码

当对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,我们先实现一个自定义结构体
  1. struct ILEDService {
  2.     struct IDeviceIoService ioService;   // 服务结构的首个成员必须是IDeviceIoService类型的成员
  3.     int32_t (*LedServiceA)(void);               // 驱动的第一个服务接口
  4.     int32_t (*LedServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加
  5. };
复制代码

在驱动的绑定程序中,实现服务函数的初始化
  1. static struct ILedService leddriver = {
  2.         .ioService.object = {0},
  3.         .ioService.Dispatch = led_dispatch,
  4.         .LedServiceA = service_funA,
  5.         .LedServiceB = service_funB,
  6.     };
  7. object->service = &ledDriver.ioService;
复制代码

然后可以来实现service_funA和service_funB函数,我的函数如下
  1. int32_t service_funA()
  2. {
  3.     HDF_LOGE("%s: serviceA ok", __func__);
  4.     int i = 5;
  5.     while(i--)
  6.     {
  7.         GpioWrite(gpio, 1);
  8.         OsalSleep(1);
  9.         GpioWrite(gpio, 0);
  10.         OsalSleep(1);
  11.         
  12.     }
  13.     return 0;
  14. }

  15. int32_t service_funB(uint32_t inputCode)
  16. {
  17.     HDF_LOGE("%s: serviceB ok", __func__);
  18.     HDF_LOGE("inputCode: %d",inputCode);
  19.     return 0;
  20. }
复制代码

通过回调函数可以调用这两个服务函数,我的回调函数如下
  1. int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
  2. {
  3.     (void)*deviceObject;
  4.     const struct ILedService *sampleService =
  5.         (const struct ILedService *)service;
  6.     if (sampleService == NULL) {
  7.         return -1;
  8.     }
  9.     sampleService->LedServiceA();
  10.     sampleService->LedServiceB(5);
  11.     return 0;
  12. }
复制代码

这个函数就是简单的两个服务函数的调用。主要函数就是这样。
图1.jpg

Test.c如下


  1. /*
  2. * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
  3. * Description: ft6236 touch driver implement.
  4. * Author: zhaihaipeng
  5. * Create: 2020-07-25
  6. */

  7. #include <stdlib.h>
  8. #include <asm/io.h>
  9. #include <fs/fs.h>
  10. #include <fs_poll_pri.h>
  11. #include <los_queue.h>
  12. #include <poll.h>
  13. #include <user_copy.h>
  14. #include <securec.h>
  15. #include "gpio_if.h"
  16. #include "hdf_device_desc.h"
  17. #include "hdf_log.h"
  18. #include "osal_irq.h"
  19. #include "osal_mem.h"
  20. #include "osal_time.h"
  21. #include "led_dev.h"

  22. #define LED_WRITE_READ 123

  23. uint16_t gpio = 19; /*待测试的GPIO管脚号 */
  24. #define HDF_LOG_TAG led_driver   // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签
  25. struct ILedService {
  26.     struct IDeviceIoService ioService;   // 服务结构的首个成员必须是IDeviceIoService类型的成员
  27.     int32_t (*LedServiceA)(void);               // 驱动的第一个服务接口
  28.     int32_t (*LedServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加
  29. };


  30. int32_t led_dispatch(struct HdfDeviceIoClient *deviceObject, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
  31. {
  32.     HDF_LOGE("%s:Dispatch,cmd:%d", __func__,cmdId);
  33.     if(cmdId == LED_WRITE_READ)
  34.     {
  35.         const char *readData = HdfSbufReadString(data);
  36.         if (readData != NULL) {
  37.             HDF_LOGE("%s: read data is: %s", __func__, readData);
  38.         }
  39.         if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
  40.             HDF_LOGE("%s: reply int32 fail", __func__);
  41.         }
  42.         return HdfDeviceSendEvent(deviceObject->device, cmdId, data);
  43.     }
  44.        
  45.     return HDF_FAILURE;
  46. }

  47. int32_t service_funA()
  48. {
  49.     HDF_LOGE("%s: serviceA ok", __func__);
  50.     int i = 5;
  51.     while(i--)
  52.     {
  53.         GpioWrite(gpio, 1);
  54.         OsalSleep(1);
  55.         GpioWrite(gpio, 0);
  56.         OsalSleep(1);
  57.         
  58.     }
  59.     return 0;
  60. }

  61. int32_t service_funB(uint32_t inputCode)
  62. {
  63.     HDF_LOGE("%s: serviceB ok", __func__);
  64.     HDF_LOGE("inputCode: %d",inputCode);
  65.     return 0;
  66. }

  67. int32_t led_bind(struct HdfDeviceObject *object)
  68. {
  69.     HDF_LOGI("%s: led_bind", __func__);
  70.     if (object == NULL) {
  71.         HDF_LOGE("%s: param is null", __func__);
  72.         return HDF_ERR_INVALID_PARAM;
  73.     }
  74.     static struct ILedService ledDriver = {
  75.         .ioService.object = {0},
  76.         .ioService.Dispatch = led_dispatch,
  77.         .LedServiceA = service_funA,
  78.         .LedServiceB = service_funB,
  79.     };
  80.     object->service = &ledDriver.ioService;
  81.     return HDF_SUCCESS;
  82. }

  83. // 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用
  84. // object为订阅者的私有数据,service为被订阅的服务对象
  85. int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
  86. {
  87.     (void)*deviceObject;
  88.     const struct ILedService *sampleService =
  89.         (const struct ILedService *)service;
  90.     if (sampleService == NULL) {
  91.         return -1;
  92.     }
  93.     sampleService->LedServiceA();
  94.     sampleService->LedServiceB(5);
  95.     return 0;
  96. }

  97. int led_init(struct HdfDeviceObject *deviceObject)
  98. {
  99.     HDF_LOGI("%s: led_init", __func__);
  100.     GpioSetDir(gpio, GPIO_DIR_OUT);//设置GPIO管脚方向,输出
  101.     if (deviceObject == NULL) {
  102.         HDF_LOGE("Test driver init failed, deviceObject is null!");
  103.         return -1;
  104.     }
  105.     struct SubscriberCallback callBack;
  106.     callBack.deviceObject = deviceObject;
  107.     callBack.OnServiceConnected = TestDriverSubCallBack;
  108.     int32_t ret = HdfDeviceSubscribeService(deviceObject, "HDF_PLATFORM_LED", callBack);
  109.     if (ret != 0) {
  110.         HDF_LOGE("Test driver subscribe led driver failed!");
  111.     }
  112.     return ret;
  113. }

  114. void led_release(struct HdfDeviceObject *deviceObject)
  115. {
  116.     HDF_LOGD("led driver release success");
  117.     return;
  118. }

  119. struct HdfDriverEntry g_ledDevEntry = {
  120.     .moduleVersion = 1,
  121.     .moduleName = "HDF_PLATFORM_LED",
  122.     .Bind = led_bind,
  123.     .Init = led_init,
  124.     .Release = led_release,
  125. };

  126. HDF_INIT(g_ledDevEntry);

复制代码

main.c如下
  1. #include "hdf_log.h"
  2. #include "osal_mem.h"
  3. #include "hdf_io_service_if.h"
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include "osal_time.h"
  10. // #include "hdf_device_desc.h"
  11. //#include "hdf_device_section.h"

  12. #include <stdlib.h>
  13. // #include <asm/io.h>
  14. // #include <fs/fs.h>
  15. // #include <fs_poll_pri.h>
  16. // #include <los_queue.h>
  17. #include <poll.h>
  18. // #include <user_copy.h>
  19. // #include <securec.h>
  20. // #include "gpio_if.h"
  21. #include "hdf_device_desc.h"
  22. // #include "hdf_log.h"
  23. #include "osal_irq.h"
  24. // #include "osal_mem.h"
  25. // #include "osal_time.h"
  26. #include <sys/ioctl.h>
  27. #include "hdf_sbuf.h"
  28. #include "led_dev.h"



  29. #define SAMPLE_WRITE_READ 123    // 读写操作码1
  30. int g_replyFlag = 0;

  31. struct ILedService {
  32.     struct IDeviceIoService ioService;   // 服务结构的首个成员必须是IDeviceIoService类型的成员
  33.     int32_t (*LedServiceA)(void);               // 驱动的第一个服务接口
  34.     int32_t (*LedServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加
  35. };

  36. static int SendEvent(struct HdfIoService *serv, char *eventData)
  37. {
  38.     int ret = 0;
  39.     struct HdfSBuf *data = HdfSBufObtainDefaultSize();
  40.     if (data == NULL) {
  41.         HDF_LOGE("fail to obtain sbuf data");
  42.         return 1;
  43.     }

  44.     struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
  45.     if (reply == NULL) {
  46.         HDF_LOGE("fail to obtain sbuf reply");
  47.         ret = HDF_DEV_ERR_NO_MEMORY;
  48.         goto out;
  49.     }

  50.     if (!HdfSbufWriteString(data, eventData)) {
  51.         HDF_LOGE("fail to write sbuf");
  52.         ret = HDF_FAILURE;
  53.         goto out;
  54.     }

  55.     ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
  56.     if (ret != HDF_SUCCESS) {
  57.         HDF_LOGE("fail to send service call");
  58.         goto out;
  59.     }

  60.     int replyData = 0;
  61.     if (!HdfSbufReadInt32(reply, &replyData)) {
  62.         HDF_LOGE("fail to get service call reply");
  63.         ret = HDF_ERR_INVALID_OBJECT;
  64.         goto out;
  65.     }
  66.     HDF_LOGE("Get reply is: %d", replyData);
  67. out:
  68.     HdfSBufRecycle(data);
  69.     HdfSBufRecycle(reply);
  70.     return ret;
  71. }

  72. static int OnDevEventReceived(void *priv,  uint32_t id, struct HdfSBuf *data)
  73. {
  74.         HDF_LOGE("%s: OnDevEventReceived", __func__);
  75.     const char *string = HdfSbufReadString(data);
  76.     if (string == NULL) {
  77.         HDF_LOGE("fail to read string in event data");
  78.         g_replyFlag = 1;
  79.         return HDF_FAILURE;
  80.     }
  81.     HDF_LOGE("%s: dev event received: %u %s",  (char *)priv, id, string);
  82.     g_replyFlag = 1;
  83.     return HDF_SUCCESS;
  84. }

  85. int main()
  86. {
  87.         char *sendData = "default event info";
  88.     struct HdfIoService *serv = HdfIoServiceBind("HDF_PLATFORM_LED", 0);
  89.     if (serv == NULL) {
  90.         HDF_LOGE("fail to get service %s", "HDF_PLATFORM_LED");
  91.         return HDF_FAILURE;
  92.     }

  93.     static struct HdfDevEventlistener listener = {
  94.         .callBack = OnDevEventReceived,
  95.         .priv ="Service0"
  96.     };

  97.     if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
  98.         HDF_LOGE("fail to register event listener");
  99.         return HDF_FAILURE;
  100.     }
  101.     if (SendEvent(serv, sendData)) {
  102.         HDF_LOGE("fail to send event");
  103.         return HDF_FAILURE;
  104.     }

  105.     /* wait for event receive event finishing */
  106.     while (g_replyFlag == 0) {
  107.         sleep(1);
  108.     }
  109.     if (HdfDeviceUnregisterEventListener(serv, &listener)) {
  110.         HDF_LOGE("fail to  unregister listener");
  111.         return HDF_FAILURE;
  112.     }
  113.     HdfIoServiceRecycle(serv);
  114.     return HDF_SUCCESS;
  115. }

复制代码


service.zip

35.7 KB, 下载次数: 2, 下载积分: 积分 -1 分

黄少浪 2021-1-18 10:21:21
大佬,请问你的main.c是放在 app文件夹下,还是和HDF框架放一起的
1回复

举报

  • 陈书浪 2021-1-18 12:03

    main.c是放在app文件夹下,附件下载后,解压到源码根目录,替换源码中的对应文件,就行了

评论

您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发文章