• UWB NI框架嵌入式实现——Qorvo示例


    在Qorvo提供的DW3000示例代码中,实现了与Apple的NI框架的互通的示例,本文中针对其示例程序进行简要的分析。测试中使用Qorvo提供的模块,该模块为nRF52833+DW3000的架构。

    1. Qorvo相关库文件

    Qorvo在提供示例时,仅提供了相关的库文件代码以及使用说明,因此,本文也只能在整体库文件的基础上进行介绍。
    Qorvo库文件封装了NI框架相关的操作,提供了库访问的头文件:niq.h注意:根据Qorvo Licence文件,需要商用,需要获得相关授权。
    库文件:libniq-m4-hfp-0.9.9.1.a,版本:0.9.9.1
    引用库相关框架,主要包括:Qorvo的NI框架库、DW3000相关驱动(libdwt_uwb_driver-hfp-6.0.0d.a,版本:6.0.0)、uwbstack_lib(主要是与FiRa相关内容),可以理解NI框架为在FiRa标准之上,根据苹果设备的特性进行了一层封装。

    1.1 关于NIQ库

    niq库文件主要的内容如下,头文件niq.h
    其中,初始化niq库,调用niq_init函数,该函数主要涉及了UWB的开始与结束,加密相关秘钥的初始化与去初始化,包括测距秘钥向量生成等函数指针。

    //vector生成等(STS需要使用)
    int  niq_init(const void (*start_uwb)(void), 
                  const void (*stop_uwb)(void), 
                  const void (*crypto_init)(void), 
                  const void (*crypto_deinit)(void),
      const void (*crypto_range_vector_geneator)(uint8_t * const data, size_t data_len));
    
    /* 重启NI框架,每次UWB TWR会话停止均需要调用 */
    void niq_reinit(void);
    /* 取消初始化NI Qorvo 模块,前置调用设置的crypto_deinit函数 */
    void niq_deinit(void);
    /* 停止 NI UWB TWR会话 */
    void niq_stop_uwb(void);
    
    //设置测距角色,0 - Controlee + Responder, 1 - Controller + Initiator
    void niq_set_ranging_role(uint8_t role);
    // 提供第三方配件配置数据,用于OOB握手——>对外输出配置数据。
    void niq_populate_accessory_uwb_config_data(void * out_buffer, 
                                                uint8_t * out_buffer_len);
    // 配置UWB会话参数,调用start_uwb()
    int  niq_configure_and_start_uwb(uint8_t *payload, uint8_t length, void *arg);
    
    
    /// ----------------------------------------------------------------------
    /// The following definitions exposed to the embedded application
    /// ----------------------------------------------------------------------
    
    #define E_NIQ_INPVAL              1
    #define E_NIQ_VERSIONNOTSUPPORTED 2
    
    #define NI_ACCESSORY_PROTOCOL_SPEC_MAJOR_VERSION 1
    #define NI_ACCESSORY_PROTOCOL_SPEC_MINOR_VERSION 0
    
    #define MAX_UWB_CONFIG_SIZE (64)
    #define ACCESSORY_CONFIGURATION_DATA_FIX_LEN (16)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    关于NI框架中,外设相关的配置数据内容结构体(在iOS NI框架介绍中有简单介绍)如下:

    /* 80字节 */
    struct AccessoryConfigurationData {
        uint16_t            majorVersion; // NI Accessory Protocol major version
        uint16_t            minorVersion; // NI Accessory Protocol minor version
        uint8_t             preferredUpdateRate;
        uint8_t             rfu[10];
        uint8_t             uwbConfigDataLength;
        uint8_t             uwbConfigData[MAX_UWB_CONFIG_SIZE];
    } __attribute__((packed));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    另外,可以看到,在底层UWB设备的配置中,包含了FiRa标准中对于设备的详细定义要求,如会话ID、测距轮使用、多节点模式等等参数的定义。

    /* UWB Device unicast configuration,具体参数含义需要结合芯片手册以及FiRa相关要求 */
    struct fira_device_configure_s {
    	uint8_t role;
    	uint8_t enc_payload;
    	uint32_t Session_ID;
    	uint8_t Ranging_Round_Usage;
    	uint8_t Multi_Node_Mode;
    	uint8_t Rframe_Config;
    	uint8_t ToF_Report;
    	uint8_t AoA_Azimuth_Report;
    	uint8_t AoA_Elevation_Report;
    	uint8_t AoA_FOM_Report;
    	uint8_t nonDeferred_Mode;
    	uint8_t STS_Config;
    	uint8_t Round_Hopping;
    	uint8_t Block_Striding;
    	uint32_t Block_Duration_ms;
    	uint32_t Round_Duration_RSTU;
    	uint32_t Slot_Duration_RSTU;
    	uint8_t Channel_Number;
    	uint8_t Preamble_Code;
    	uint8_t PRF_Mode;
    	uint8_t SP0_PHY_Set;
    	uint8_t SP1_PHY_Set;
    	uint8_t SP3_PHY_Set;
    	uint32_t MAX_RR_Retry;
    	uint8_t Constraint_Length_Conv_Code_HPRF;
    	uint32_t UWB_Init_Time_ms;
    	uint8_t Block_Timing_Stability;
    	uint8_t Key_Rotation;
    	uint8_t Key_Rotation_Rate;
    	uint8_t MAC_FCS_TYPE;
    	uint8_t MAC_ADDRESS_MODE;
    	uint8_t SRC_ADDR[2];
    	uint8_t Number_of_Controlee;
    	uint8_t DST_ADDR[2];
       // 用于测距中STS生成的秘钥 
        uint8_t Vendor_ID[2];
        uint8_t Static_STS_IV[6];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    1.2 UWBStack Lib

    uwbstack_lib库部分,主要提供了FiRa协议相关参数等,其中相关参数、相关数据结构类型定义如下:

    #define FIRA_HELPER_H
    
    //主要为FiRa定义的相关会话参数
    struct session_parameters {
    	uint8_t device_type;
    	uint8_t device_role;
      // 测距轮使用
    	uint8_t ranging_round_usage;
      // ono-to-one, one-to-many, many-to-many
    	uint8_t multi_node_mode;
    	uint16_t destination_short_address;
    	uint32_t initiation_time_ms;
    	/**
    	 * @slot_duration_rstu: 测距时隙周期,单位RSTU,FiRa中为1200 RSTU = 1ms
    	 */
    	uint32_t slot_duration_rstu;
        //每个round的时隙数
    	uint32_t round_duration_slots;
    	uint32_t block_duration_ms;
    	// 是否使能多跳
    	bool round_hopping;
        // 通道,5/9
    	uint8_t channel_number;
    	/**
    	 * @preamble_code_index: Uwb preamble code index.
    	 * BPRF (9-24), HPRF (25-32)
    	 */
    	uint8_t preamble_code_index;
    	uint8_t rframe_config;
    	uint8_t sfd_id;
    	/**
    	 * @vupper64: vUpper64 for static STS (STATIC_STS_IV | VENDOR_ID).
         *            8 Bytes
    	 */
    	u8 vupper64[FIRA_VUPPER64_SIZE];
    	uint8_t rx_antenna_selection;
    	uint8_t rx_antenna_pair_azimuth;
    	uint8_t rx_antenna_pair_elevation;
    	uint8_t tx_antenna_selection;
    	uint8_t rx_antenna_switch;
    	uint8_t aoa_result_req;
    	uint8_t report_tof;
    	uint8_t report_aoa_azimuth;
    	uint8_t report_aoa_elevation;
    	uint8_t report_aoa_fom;
        u32 data_vendor_oui;
    };
    
    struct controlee_parameters {
    	/**
    	 * @address: Controlee short address.
    	 */
    	uint16_t address;
    };
    // 受控端参数,FIRA最大受控端数为16,参数主要是受控端的u16短地址
    struct controlees_parameters {
    	/**
    	 * @controlees: List of controlees.
    	 */
    	struct controlee_parameters controlees[FIRA_CONTROLEES_MAX];
    	/**
    	 * @n_controlees: Number of controlees in the list.
    	 */
    	int n_controlees;
    };
    
    enum aoa_measurements_index {
    	FIRA_HELPER_AOA_AZIMUTH,
    	FIRA_HELPER_AOA_ELEVATION,
    	FIRA_HELPER_AOA_MAX
    };
    /* FiRa AoA 测量 */
    struct aoa_measurements {
    	uint8_t rx_antenna_pair;  //天线对索引
        uint8_t aoa_fom;  //本地AoA估计的质量
        int16_t aoa_2pi;  //估计接收角度
    };
    
    struct ranging_measurements {
        //...
    };
    
    struct ranging_results {
        //...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    FiRa库相关涉及函数原型如下定义:

    // 设置调度器,Fira域,调用时UWB MAC必须停止
    int fira_helper_set_scheduler(void);
    // 初始化FiRa会话,用于创建和初始化fira会话
    int fira_helper_init_session(uint32_t session_id);
    // 启动FiRa会话,port_id用于通知
    int fira_helper_start_session(uint32_t session_id, uint32_t port_id);
    int fira_helper_stop_session(uint32_t session_id);
    // 释放会话分配的内存,必须在会话已经停止的情况下调用。即在stop_session后调用
    int fira_helper_deinit_session(uint32_t session_id);
    // 设置FiRa会话参数
    int fira_helper_set_session_parameters(
    	uint32_t session_id, const struct session_parameters *session_params);
    // 特定FiRa会话中添加受控端
    int fira_helper_add_controlees(uint32_t session_id,
    			       const struct controlees_parameters *controlees);
    int fira_helper_delete_controlees(
    	uint32_t session_id, const struct controlees_parameters *controlees);
    int fira_helper_parse_ranging_report(struct sk_buff *msg,
    				     struct ranging_results *results);
    int fira_helper_send_data(uint32_t session_id,
    			  const struct data_parameters *data_params);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    fira_region_params.h为FiRa域相关参数,包括设备类型(Controller或Controlee),设备角色(发起者、应答者)、ROUND使用方式(OWR、SSTWR、DSTWR)、模式(单播、一对多、多对多)、结果报告(AT_RESPONDER,AT_INITIATOR)、RF帧的模式(SP0、SP1、SP2、SP3,Qorvo主要是0,1,3,未支持2)、PRF模式等。

    1.3 底层驱动实现

    在本示例中使用nRF52833作为主控芯片,一方面需要实现DW3000的底层访问相关驱动的移植。

    • HAL_DW3000.c主要为针对Nordic平台的移植工作,包括中断处理等操作。
    • 注意:在代码中提到NRF芯片仅有1个IRQ用于所有的GPIO引脚,因此DW3000的(中断)irqN、(复位RST)rstIrqN均挂在GPIOTE_IRQn上,具体在中断函数中process_deca_irq处理,根据IRQ引脚的状态判断是IRQ中断还是RST中断。

    另外,由于NI框架在实现中,需要使用BLE来实现与苹果设备的数据交换,即利用BLE实现OOB,在本示例中使用nRF52833相关蓝牙服务实现。

    2. MAC层数据服务相关实现简介

    从IEEE 802.15.4协议中,MAC层数据传输服务提供了三种数据传输的原语:MCPS-DATA.request、MCPS-DATA.confirm、MCPS-DATA.indication。
    在本示例的实现中,依然按照相关框架来进行实现。

    #incluce <net/mac802154.h>
    
    struct ieee802154_hw {
    	int extra_tx_headroom;
    	u32 flags;
    	struct device *parent;
    	void *priv;
    	struct wpan_phy *phy; //底层设备驱动
    };
    
    
    //头文件主要提供内容,包括ieee802154_hw的分配与释放
    struct ieee802154_hw *ieee802154_hw_alloc(void);
    struct ieee802154_hw *ieee802154_hw_free(void);
    
    //struct dwchip_s在deca_interface.h中定义。
    // IEEE 802.15.4 MCPS相关实现API接口
    struct dwchip_s *dw3000_mcps_alloc(void);
    int dw3000_mcps_register(struct dwchip_s *dw);
    void dw3000_mcps_unregister(struct dwchip_s *dw);
    void dw3000_mcps_free(struct dwchip_s *dw);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    //芯片结构体,包括硬件抽象层(HAL)、驱动、MCPS已经接收结构体
    struct dwchip_s
    {   
        /*HAL*/
        struct dwt_spi_s *SPI; // first
        void(*wakeup_device_with_io)(void);
    
        /*Driver*/
        struct dwt_driver_s *dwt_driver;
        struct dwt_callbacks_s callbacks;
    
        /* driver configuration */
        struct dwt_mcps_config_s *config;
    
        /* MCPS */
        struct mcps802154_llhw *llhw;  
        struct mcps802154_ops *mcps_ops; //
        struct dw3000_calibration_data *calib_data;
        struct dwt_mcps_runtime_s *mcps_runtime;
    
        /* rx structure */
        struct dwt_mcps_rx_s *rx;
    
        /* GPIO used to switch off WIFI while transmitting, for example */
        int8_t coex_gpio_pin;
        int8_t coex_gpio_active_state;
    
        /** driver data*/
        void *priv; // last
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    当然,在当前Qorvo提供的示例代码中均对相关源码进行了封装,在后续的文章中,尽量从其实现的框架上来和大家一起来对其实现进行剖析。

    /**
     *  mac层相关操作回调接口,包括启动、停止,同步,ED检测,设置信道,
     */
    struct ieee802154_ops {
    	struct module *owner;
    	int (*start)(struct ieee802154_hw *hw);
    	void (*stop)(struct ieee802154_hw *hw);
    	int (*xmit_sync)(struct ieee802154_hw *hw, struct sk_buff *skb);
    	int (*xmit_async)(struct ieee802154_hw *hw, struct sk_buff *skb);
        // 能量检测
    	int (*ed)(struct ieee802154_hw *hw, u8 *level);
        // 通道设置
    	int (*set_channel)(struct ieee802154_hw *hw, u8 page, u8 channel);
    	int (*set_hw_addr_filt)(struct ieee802154_hw *hw,
    				struct ieee802154_hw_addr_filt *filt,
    				unsigned long changed);
        // 功率设置
    	int (*set_txpower)(struct ieee802154_hw *hw, s32 mbm);
    	int (*set_lbt)(struct ieee802154_hw *hw, bool on);
        // CCA模式,当前从相关注释来看并没有支持,cfg802154.h中struct wpan_phy_cca为空。
    	int (*set_cca_mode)(struct ieee802154_hw *hw,
    			    const struct wpan_phy_cca *cca);
    	int (*set_cca_ed_level)(struct ieee802154_hw *hw, s32 mbm);
    	int (*set_csma_params)(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
    			       u8 retries);
    	int (*set_frame_retries)(struct ieee802154_hw *hw, s8 retries);
    	int (*set_promiscuous_mode)(struct ieee802154_hw *hw, const bool on);
    	void (*sw_scan_start)(struct ieee802154_hw *hw, __le64 addr);
    	void (*sw_scan_complete)(struct ieee802154_hw *hw);
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ieee802154_ops结构体来看,基本为标准IEEE 802154相关操作定义,在前面介绍的Linux相关UWB Stack实现中均会涉及。

    相关术语

    MAC,Medium Access Control,媒介访问控制,负责控制共享介质的访问方式和规则,保证多个节点间的通信能够有效地进行。
    MCPS,MAC Common Part Sublayer,MAC公共部分子层,是整个MAC层的核心,提供数据传输服务。
    MLME,MAC Layer Management Entity,为MAC层管理实体,提供管理服务。

    Linux内核 IEEE 802.15.4规范相关实现,头文件定义:mac802154.h

  • 相关阅读:
    皮肤暗黄怎么办?
    计算机毕业设计之java+ssm峰值预警停车场管理系统
    我的AI音乐梦:ChatGPT帮我做专辑
    LaTex 控制图片表格位置[h][t][b][htb]等
    python第三方库之pretty_errors——美化traceback 报错信息
    【ES6】阮一峰ES6学习(五)Set和Map联系及区别
    家用洗地机哪个品牌耐用?推荐这四款清洁力强的机型
    推荐两款开源的绘制流程图软件
    【ACWing】230. 排列计数
    找不到msvcr90.dll无法继续执行代码怎么解决
  • 原文地址:https://blog.csdn.net/luo58614013/article/details/133846319