昇腾社区首页
中文
注册

开发示例

本章节指导开发者根据add_extend_driver_adapter工程示例适配OM SDK的接口。在实际操作本章节前,开发人员应已经仔细阅读模组开发章节,熟悉产品规格、模组规格、接口功能等信息。

操作步骤

  1. 进入工程源码{project_dir}/src/app/add_extend_driver_adapter”路径下。
    add_extend_driver_adapter的目录结构如下所示。
    ├── build_extend_driver_adapter.sh     // 驱动构建脚本
    ├── validate_module_def.py             // 配置文件校验脚本
    ├── CMakeLists.txt                     // CMake构建文件
    ├── demo_module.c                      // 模组适配源文件
    └── demo_module.h                      // 模组适配头文件
  2. 在规格配置文件中定义模组和设备。
    1. 从om-sdk.tar.gz中“software/ibma/config/devm_configs”下拷贝所有已有配置文件到{project_dir}/config/module_def”目录下。
    2. 在“{project_dir}/config/module_def”目录下新建模组规格配置文件module_demo.json,根据关键字段说明章节定义出关键字段。
    3. (可选)在“{project_dir}/config/module_def”路径下,打开product_specification.json文件,在文件的设备列表中添加属于拓展模组的设备定义。(如果模组的设备属于动态插拔类型则无需在配置文件中静态定义)。
    4. 使用配置文件检查脚本validate_module_def.py对拓展后的配置文件集进行检查,验证产品规格配置文件和模组规格配置文件的正确性。
      cd src/app/add_extend_driver_adapter
      python3 validate_module_def.py ../../../config/module_def
      validate_module_def.py脚本内容如下:
      import json
      import os
      import sys
      
      
      PRODUCT_NAME = 'product_specification.json'
      MAX_ATTRIBUTE_LEVEL = 2
      MAX_ATTRIBUTE_NUMBER = 50
      MODULE_CATEGORY = ('internal', 'extend', 'addition')
      ATTRIBUTE_VALUE_TYPE = ('bool', 'float', 'int', 'json', 'long long', 'string')
      ATTRIBUTE_ACCESS_MODE = ('Read', 'Write', 'ReadWrite','ReadHide', 'WriteHide', 'ReadWriteHide')
      
      
      def check(config_file_dir: str):
          """
          :param config_file_dir:
          :return: None
          Check the correctness of all the configuration files in the directory
          """
          for filename in os.listdir(config_file_dir):
              if not filename.endswith('json'):
                  continue
      
              with open(os.path.join(config_file_dir, filename)) as stream:
                  document = json.load(stream)
      
              if filename == PRODUCT_NAME:
                  check_product(document)
              elif filename.startswith('module'):
                  check_module(document)
              else:
                  raise AssertionError(f'Unknown file: "{filename}"')
      
          print(f'The collection of configurations in {config_file_dir} is correct. ')
      
      
      def check_product(doc: dict) -> int:
          """
          :param doc: product specification
          :return: total number of device
          """
          assert isinstance(doc, dict), 'product specification file structure error: outermost layer should be a map'
          modules = doc.get('modules')
          if modules:
              assert isinstance(modules, dict), 'modules should be a map'
              for module, module_spec in modules.items():
                  assert isinstance(module, str), 'key in modules should be a string'
                  assert isinstance(module_spec, dict), 'value in modules should be a dict'
      
                  devices = module_spec.get('devices')
                  if devices is None:
                      raise AssertionError(f'devices not exist in module {module}')
                  else:
                      assert isinstance(devices, list), 'devices in module spec should be a list'
                      for device in devices:
                          assert isinstance(device, str), 'device should be a string'
              return len(modules)
          else:
              raise AssertionError('no modules found in product specification')
      
      
      def check_module(doc: dict) -> str:
          """
          :param doc: module specification
          :return: module name
          """
          assert isinstance(doc, dict), 'module specification file structure error: outermost layer should be a map'
      
          module_name = doc.get('name')
          assert module_name is not None, f'no name in {doc}'
          assert isinstance(module_name, str), 'module name should be a string'
      
          _id = doc.get('id')
          assert _id is not None, f'no id in module {module_name}'
          assert isinstance(_id, int), 'module id should be an integer'
      
          category = doc.get('category')
          if category:
              assert isinstance(category, str), 'module category should be a string'
              assert category in MODULE_CATEGORY, f'invalid category: {category}'
          else:
              raise AssertionError(f'no category found in module {module_name}')
      
          driver = doc.get('driver')
          assert driver is not None, f'no driver found in module {module_name}'
          assert isinstance(driver, str), 'module driver should be a string'
      
          dynamic = doc.get('dynamic')
          assert dynamic is not None, f'no dynamic found in module {module_name}'
          assert isinstance(dynamic, bool), 'dynamic should be a boolean value'
      
          attributes = doc.get('attributes')
          if attributes:
              check_attributes(attributes)
          else:
              raise AssertionError(f'no attributes found in module {module_name}')
      
          return module_name
      
      
      def check_attributes(attributes: dict, level=1):
          """
          :param attributes: a map whose keys are attribute names and values are attribute specifications
          :param level: the level of recursive subAttribute
          :return: None
          """
          assert isinstance(attributes, dict), 'module specification file structure error: attributes should be a map'
          assert len(attributes) <= MAX_ATTRIBUTE_NUMBER, f'number of attributes exceeds limit ({MAX_ATTRIBUTE_NUMBER})'
          assert level <= MAX_ATTRIBUTE_LEVEL, 'recursive subAttributes level exceeds limit'
      
          for attr_name, doc in attributes.items():
              _id = doc.get('id')
              assert _id is not None, f'no id in attribute {attr_name}'
              assert isinstance(_id, int), 'attribute id should be an integer'
      
              value_type = doc.get('type')
              if value_type:
                  assert isinstance(value_type, str), 'attribute value type should be a string'
                  assert value_type in ATTRIBUTE_VALUE_TYPE, f'invalid value type {value_type}'
              else:
                  raise AssertionError(f'no type in attribute {attr_name}')
      
              access_mode = doc.get('accessMode')
              if access_mode:
                  assert isinstance(access_mode, str), 'attribute access mode should be a string'
                  assert access_mode in ATTRIBUTE_ACCESS_MODE, f'invalid access mode {access_mode}'
              else:
                  raise AssertionError(f'no accessMode in attribute {attr_name}')
      
              attributes = doc.get('subAttributes')
              if attributes:
                  check_attributes(attributes, level=level + 1)
      
      
      if __name__ == '__main__':
          if len(sys.argv) == 2:
              check(sys.argv[1])
          else:
              print('The input argument should be the directory of the configuration files')
      
      检查内容包括:
      • 配置文件结构是否正确。
      • 关键字段是否有缺失。
      • 枚举类型字段是否属于正确类型的一种。
      • 安全性检查。
  3. 在demo_module.h定义对外接口以及接口关键字段。
    #ifndef __DEMO_MODULE_H__
    #define __DEMO_MODULE_H__
    
    #define DEVICE_MAP_MAX_LEN 2  /* 保存模组设备的最大个数 */
    #define DEVICE_INFO_MAX_LEN 64 /* 保存模组信息的最大长度 */
    #define TLV_HEADER_LENGTH 8
    
    /* 定义属性ID类型 0:基础通用属性 1:模组特有属性 */
    #define BASE_CLASS_ID 0x00
    #define MODULE_CLASS_ID 0x01
    
    /* 定义模组管理的属性 */
    typedef enum demo_attribute_id {
        NAME = ((BASE_CLASS_ID) << 16) + 1,          /* 名称 string */
        CLASS = ((BASE_CLASS_ID) << 16) + 2,         /* 类型 string */
        PRESENT = ((MODULE_CLASS_ID) << 16) + 1,     /* 状态 int */
        TEMPERATURE = ((MODULE_CLASS_ID) << 16) + 2, /* 温度 float */
        VOLTAGE = ((MODULE_CLASS_ID) << 16) + 3,     /* 电压 float */
        SWITCH = ((MODULE_CLASS_ID) << 16) + 4,      /* 开关 bool */
        MEMORY = ((MODULE_CLASS_ID) << 16) + 5,      /* 内存 long long */
        VERSION = ((MODULE_CLASS_ID) << 16) + 6,     /* 版本 string */
        SIGNAL_INFO = ((MODULE_CLASS_ID) << 16) + 7 /* 信号信息 json */
    } DEMO_ATTRIBUTE_ID;
    
    /* 定义json属性中的子属性ID */
    typedef enum sub_attribute_id {
        SUB_ATTRIBUTE1 = 1,
        SUB_ATTRIBUTE2 = 2
    } SUB_ATTRIBUTE_ID;
    
    /* 定义模拟json属性的结构体 */
    typedef struct demo_signal_info {
        char signal_type[DEVICE_INFO_MAX_LEN]; /* 类型 string */
        char signal_strength[DEVICE_INFO_MAX_LEN]; /* 强度 string */
    } DEMO_SIGNAL_INFO;
    
    /* 定义保存的设备 */
    typedef struct demo_device_map {
        char name[DEVICE_INFO_MAX_LEN];
        int fd;
    } DEMO_DEVICE_MAP;
    
    /* 定义设备各属性,用于模拟设备属性的获取和设置 */
    typedef struct device {
        char name[DEVICE_INFO_MAX_LEN];
        char device_class[DEVICE_INFO_MAX_LEN];
        int present;
        float temperature;
        float voltage;
        int device_switch;
        long long memory;
        char version[DEVICE_INFO_MAX_LEN];
        DEMO_SIGNAL_INFO* signal_info;
    } DEVICE;
    
    /* 定义保存的模组列表 */
    typedef struct demo_device_ctl {
        DEMO_DEVICE_MAP device_map[DEVICE_MAP_MAX_LEN];
    } DEMO_DEVICE_CTRL;
    
    /* 定义TLV解析结构体 */
    typedef struct attr_tlv_struct {
        int type;
        int len;
        char value[0];
    } ATTR_TLV;
    
    /* 定义驱动提供的对外接口 */
    int dev_load();
    int dev_unload();
    int dev_open(char *name, int *fd);
    int dev_close(int fd);
    int get_attribute(int fd, unsigned int buffSize, unsigned char *buff);
    int set_attribute(int fd, unsigned int buffSize, unsigned char *buff);
    int dev_read(int fd, unsigned int buffSize, unsigned char *buff);
    int dev_write(int fd, unsigned int buffSize, unsigned char *buff);
    int dev_get_device_list(int type, unsigned int buffSize, unsigned char *buff, unsigned int device_name_len);
    
    #endif
  4. 在demo_module.c中实现接口以及接口关键字段。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <dlfcn.h>
    #include <pthread.h>
    #include <unistd.h>
    
    #include "demo_module.h"
    
    #ifdef __cplusplus
    #if __cplusplus
    extern "C" {
    #endif
    #endif
    
    /* 结构体指针g_demo_ctrl保存模组设备信息 */
    static DEMO_DEVICE_CTRL *g_demo_ctrl = NULL;
    
    /* 定义支持的设备名 */
    char* g_devices_name[DEVICE_MAP_MAX_LEN] = {
        "extend_device01",
        "extend_device02"
    };
    
    /* 定义支持的设备, 用于模拟模组各属性类型的获取与设置 */
    DEMO_SIGNAL_INFO signal1 = {"4g", "strong"};
    DEMO_SIGNAL_INFO signal2 = {"5g", "weak"};
    DEVICE device1 = {"extend_name", "extend_class", 1, 52, 1.0, 0, 51200000, "extend 1.0", &signal1};
    DEVICE device2 = {"extend_name", "extend_class", 1, 52, 1.0, 1, 51200000, "extend 1.0", &signal2};
    DEVICE* g_devices[DEVICE_MAP_MAX_LEN] = {&device1, &device2};
    
    /* 驱动适配资源加载以及模组初始化接口 */
    int dev_load()
    {
        /* 申请用于保存模组设备信息的内存资源 */
        g_demo_ctrl = malloc(sizeof(DEMO_DEVICE_CTRL));
        if (g_demo_ctrl == NULL) {
            return -1;
        }
    
        /* 初始化模组设备信息,生成区分设备的不同fd值以及 */
        for (int index = 0; index < DEVICE_MAP_MAX_LEN; index++) {
            g_demo_ctrl->device_map[index].fd = index;
            int ret = memcpy_s(g_demo_ctrl->device_map[index].name, DEVICE_INFO_MAX_LEN,
                               g_devices_name[index], DEVICE_INFO_MAX_LEN);
            if (ret != 0) {
                return -1;
            }
        }
        return 0;
    }
    
    /* 驱动适配资源释放接口 */
    int dev_unload()
    {
        /* 释放保存模组设备信息的指针并置空 */
        if (g_demo_ctrl != NULL) {
            free(g_demo_ctrl);
        }
        g_demo_ctrl = NULL;
        return 0;
    }
    
    /* 驱动适配设备打开接口,根据输入的设备名name,返回得到设备标识符fd */
    int dev_open(char *name, int *fd)
    {
        /* 判断是否初始化加载模组,以及输入参数是否为空指针 */
        if (g_demo_ctrl == NULL || name == NULL || fd == NULL) {
            return -1;
        }
        /* 遍历模组设备列表,查询是否已存在device_name的设备信息,若存在返回对应fd值 */
        for (int index = 0; index < DEVICE_MAP_MAX_LEN; index++) {
            if (strcmp(g_demo_ctrl->device_map[index].name, name) == 0) {
                *fd = g_demo_ctrl->device_map[index].fd;
                return 0;
            }
        }
        return -1;
    }
    
    /* 驱动适配设备关闭接口,根据输入的fd设备标识符关闭对应设备 */
    int dev_close(int fd)
    {
        if (g_demo_ctrl == NULL) {
            return -1;
        }
        /* 遍历模组设备列表,查询fd对应设备信息并置为初始值 */
        for (int index = 0; index < DEVICE_MAP_MAX_LEN; index++) {
            if (g_demo_ctrl->device_map[index].fd == fd) {
                memset_s(g_demo_ctrl->device_map[index].name, DEVICE_INFO_MAX_LEN, 0, DEVICE_INFO_MAX_LEN);
            }
        }
        return 0;
    }
    
    /* json类型数据获取封装接口,将TLV编码解析的value进行TLV解析完成json属性获取 */
    static int get_json_attribute(int buffSize, char *buff, DEVICE* device)
    {
        int pos = 0;
        while (pos < buffSize) {
            ATTR_TLV *sub_item = (ATTR_TLV *)(buff + pos);
            /* 判断TLV解析是否会内存越界,若解析错误则返回错误码 */
            if (pos + TLV_HEADER_LENGTH + sub_item->len > buffSize) {
                return -1;
            }
            switch (sub_item->type) {
                case SUB_ATTRIBUTE1: {
                    memcpy_s((char *)sub_item->value, DEVICE_INFO_MAX_LEN,
                             device->signal_info->signal_type, DEVICE_INFO_MAX_LEN);
                    break;
                }
                case SUB_ATTRIBUTE2: {
                    memcpy_s((char *)sub_item->value, DEVICE_INFO_MAX_LEN,
                             device->signal_info->signal_strength, DEVICE_INFO_MAX_LEN);
                    break;
                }
                default:
                    /* 若输入的模组子属性不支持设置,返回错误码 */
                    return -1;
            }
            pos += TLV_HEADER_LENGTH + sub_item->len;
        }
        return 0;
    }
    
    /* 驱动适配属性获取接口,将模组属性保存到TLV编码解析的buff中 */
    int get_attribute(int fd, unsigned int buffSize, unsigned char *buff)
    {
        DEVICE* device = NULL;
        /* 根据fd确定模组唯一设备,确认后对该模组设备属性获取 */
        for (int index = 0; index < DEVICE_MAP_MAX_LEN; index++) {
            if (g_demo_ctrl->device_map[index].fd == fd) {
                device = g_devices[fd];
                break;
            }
        }
        if (device == NULL) {
            /* 若存在该设备,则根据TLV解析获取该设备属性,若不存在该设备,返回错误码 */
            return -1;
        }
    
        /* 将输入的获取到模组属性的内存进行TLV转换进行解析 */
        ATTR_TLV *demo_attr = (ATTR_TLV *)buff;
    
        /* 使用switch case方法确定需要获取的模组属性,并将对应模组属性保存在buff内存段中 */
        switch (demo_attr->type) {
            /* case中模组属性ID与模组配置json文件保持一致 */
            case NAME:
                /* 模拟string类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                memcpy_s(demo_attr->value, demo_attr->len, device->name, DEVICE_INFO_MAX_LEN);
                break;
            case CLASS:
                /* 模拟string类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                memcpy_s(demo_attr->value, demo_attr->len, device->device_class, DEVICE_INFO_MAX_LEN);
                break;
            /* case中的全局变量仅是模拟不同类型的属性获取方式,实际适配开发中需修改为实际的模组属性接口 */
            case PRESENT:
                /* 模拟int类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                *(int *)demo_attr->value = device->present;
                break;
            case TEMPERATURE:
                /* 模拟float类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                *(float *)demo_attr->value = device->temperature;
                break;
            case VOLTAGE:
                /* 模拟float类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                *(float *)demo_attr->value = device->voltage;
                break;
            case SWITCH:
                /* 模拟bool类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                *demo_attr->value = device->device_switch;
                break;
            case MEMORY:
                /* 模拟long long类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                *(long long *)demo_attr->value = device->memory;
                break;
            case VERSION:
                /* 模拟string类型属性的获取方式,实际开发中:需将实际接口获取的属性值保存在TLV解析的value中 */
                memcpy_s(demo_attr->value, demo_attr->len, device->version, DEVICE_INFO_MAX_LEN);
                break;
            case SIGNAL_INFO:
                /* json类型的属性需要对buff再次进行TLV解析,使用偏移量的方式确定子属性的获取 */
                return get_json_attribute(demo_attr->len, (char *)demo_attr->value, device);
            default:
                /* 若输入的模组属性不支持获取,返回错误码 */
                return -1;
        }
        return 0;
    }
    
    /* json类型数据设置封装接口,将TLV编码解析的value进行TLV解析完成json属性设置 */
    static int set_json_attribute(int buffSize, char *buff, DEVICE* device)
    {
        int pos = 0;
        while (pos < buffSize) {
            ATTR_TLV *sub_item = (ATTR_TLV *)(buff + pos);
            /* 判断TLV解析是否会内存越界,若解析错误则返回错误码 */
            if (pos + TLV_HEADER_LENGTH + sub_item->len > buffSize) {
                return -1;
            }
            switch (sub_item->type) {
                case SUB_ATTRIBUTE1:
                    memcpy_s(device->signal_info->signal_type, DEVICE_INFO_MAX_LEN,
                             (char *)sub_item->value, DEVICE_INFO_MAX_LEN);
                    break;
                case SUB_ATTRIBUTE2:
                    memcpy_s(device->signal_info->signal_strength, DEVICE_INFO_MAX_LEN,
                             (char *)sub_item->value, DEVICE_INFO_MAX_LEN);
                    break;
                default:
                    /* 若输入的模组子属性不支持设置,返回错误码 */
                    return -1;
            }
            pos += TLV_HEADER_LENGTH + sub_item->len;
        }
        return 0;
    }
    
    /* 驱动适配属性设置接口,将TLV编码解析的buff中的属性值进行设置 */
    int set_attribute(int fd, unsigned int buffSize, unsigned char *buff)
    {
        DEVICE* device = NULL;
        /* 根据fd确定模组唯一设备,确认后对该模组设备属性获取 */
        for (int index = 0; index < DEVICE_MAP_MAX_LEN; index++) {
            if (g_demo_ctrl->device_map[index].fd == fd) {
                device = g_devices[fd];
                break;
            }
        }
        if (device == NULL) {
            /* 若存在该设备,则根据TLV解析获取该设备属性,若不存在该设备,返回错误码 */
            return -1;
        }
    
        /* 将输入的获取到模组属性的内存进行TLV转换进行解析 */
        ATTR_TLV *demo_attr = (ATTR_TLV *)buff;
    
        /* 使用switch case方法确定需要设置的模组属性,并将buff内存段中对应的属性值保存在模组中 */
        switch (demo_attr->type) {
            /* case中模组属性ID与模组配置json文件保持一致 */
            case PRESENT:
                /* 模拟int类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                device->present = *(int *)demo_attr->value;
                break;
            case TEMPERATURE:
                /* 模拟float类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                device->temperature = *(float *)demo_attr->value;
                break;
            case VOLTAGE:
                /* 模拟float类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                device->voltage = *(float *)demo_attr->value;
                break;
            case SWITCH:
                /* 模拟bool类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                device->device_switch = *(int *)demo_attr->value;
                break;
            case MEMORY:
                /* 模拟long long类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                device->memory = *(long long *)demo_attr->value;
                break;
            case VERSION:
                /* 模拟string类型属性的设置方式,实际开发中:需将保存在TLV解析的value值传入实际接口设置属性值 */
                memcpy_s(device->version, DEVICE_INFO_MAX_LEN, (char *)demo_attr->value, DEVICE_INFO_MAX_LEN);
                break;
            case SIGNAL_INFO:
                /* json类型的属性需要对buff再次进行TLV解析,使用偏移量的方式进行子属性的设置 */
                return set_json_attribute(demo_attr->len, (char *)demo_attr->value, device);
            default:
                /* 若输入的模组子属性不支持设置,返回错误码 */
                return -1;
        }
        return 0;
    }
    
    /* 驱动适配预留读接口,暂不设计开发使用 */
    int dev_read(int fd, unsigned int buffSize, unsigned char *buff)
    {
        return 0;
    }
    
    /* 驱动适配预留写接口,暂不设计开发使用 */
    int dev_write(int fd, unsigned int buffSize, unsigned char *buff)
    {
        return 0;
    }
    
    /* 可热插拔设备的模组接口,用于获取指定设备类型的设备列表。当模组信息会实时变化的情况下,使用此接口刷新模组设备信息 */
    int dev_get_device_list(int type, unsigned int buffSize, unsigned char *buff, unsigned int device_name_len)
    {
        if (g_demo_ctrl == NULL) {
            return -1;
        }
        int pos = 0;
        int ret;
        /* 根据不同的模组设备类型,使用首地址偏移的方式将模组设备信息保存在buff中 */
        ret = memcpy_s((char *)(buff + pos), device_name_len, "extend_device01", device_name_len);
        if (ret != 0) {
            return -1;
        }
        pos += device_name_len;
        ret = memcpy_s((char *)(buff + pos), device_name_len, "extend_device02", device_name_len);
        if (ret != 0) {
            return -1;
        }
        return 0;
    }
    
    #ifdef __cplusplus
    #if __cplusplus
    }
    #endif
    #endif
  5. 编译构建动态库so。
    1. “add_extend_driver_adapter”路径的CMakeLists.txt文件中编写构建方式,示例如下。
      #设置CMake的最低版本
      cmake_minimum_required(VERSION 3.16)
      
      #交叉编译选项
      if (CROSSCOMPILE_ENABLED)
          set(CMAKE_SYSTEM_NAME Linux)
          set(CMAKE_SYSTEM_PROCESSOR aarch64)
          set(target_arch aarch64-linux-gnu)
          set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
          set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
          set(CMAKE_LIBRARY_ARCHITECTURE ${target_arch} CACHE STRING "" FORCE)
          set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
          set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
          set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
          set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
      endif()
      #添加构建的项目名称
      project(libdemo_adapter)
      
      set(TOP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
      
      #在目录中查找所有源文件
      aux_source_directory(. SRC_LIST)
      
      #将源文件生成名为libdemo_adapter.so链接文件 STATIC:静态链接 SHARED:动态链接
      add_library(demo_adapter SHARED ${SRC_LIST})
    2. 构建.so文件。
      1. “add_extend_driver_adapter”工程下的build_extend_driver_adapter.sh中编写构建脚本,代码编写示例如下。
        #!/bin/bash
        
        CUR_DIR=$(dirname "$(readlink -f "$0")")
        
        function main()
        {
            echo "build demo adapter lib..."
            if [ ! -d "${CUR_DIR}/build" ];then
                mkdir -p "${CUR_DIR}/build"
            else
                rm -rf "${CUR_DIR}/build"/*
            fi
            cd "${CUR_DIR}/build"
            # 注意x86编译环境需要安装Arm64编译工具后,开启该选项
            cmake -DCROSSCOMPILE_ENABLED=ON ..
            make
            echo "build demo adapter lib success"
            return 0
        }
        main
        RESULT=$?
        exit "${RESULT}"
      2. {project_dir}/config/project_cfg/project.conf”“_NeedAdditionalDriver”设置为“yes”
  6. 编译新增模组文件。在{project_dir}/build/build.sh中,实现调用扩展模组的编译脚本。
    # 添加扩展模组驱动
    # TOP_DIR={project_dir}
    # OMSDK_TAR_PATH={project_dir}/platform/omsdk
    if [[ "${_NeedAdditionalDriver}" == "yes" ]]; then
        if ! bash "${TOP_DIR}"/src/app/add_extend_driver_adapter/build_extend_driver_adapter.sh;then
            return 1
        fi
        cp -rf "${TOP_DIR}"/src/app/add_extend_driver_adapter/build/libdemo_adapter.so "${OMSDK_TAR_PATH}"/lib/
        # copy additional configurations
        cp -rf "${TOP_DIR}"/config/module_def/*.json "${OMSDK_TAR_PATH}"/software/ibma/config/devm_configs/
    fi