本专栏主要介绍在Linux内核中的UWB Stack的实现,整体基于IEEE 802.15.4框架,采用Qorvo UWB芯片DW3000,开源协议版本为GPLv2。
在本篇文章中,主要介绍MCPS接口的定义,MCPS(MAC Common Part Sublayer,MAC公共部分子层)。
为MCPS接口相关定义,主要包括一些一些结构体的定义,主要包括底层驱动的连接,收发数据帧等,相关结构体定义如下:
struct mcps802154_llhw
,不带MCPS的底层硬件,必须使用mcps802154_alloc_llhw()
函数进行分配,然后底层驱动程序应对其进行初始化。struct mcps802154_tx_frame_info
,用于传输帧的信息。struct mcps802154_rx_info
,使能接收机的信息。struct mcps802154_rx_frame_info
,接收到数据帧的信息。struct mcps802154_sts_params
,HPR UWB的STS参数。struct mcps802154_ops
,MCPS从底层驱动程序的回调函数。struct mcps802154_llhw {
/**
* @dtu_freq_hz: Inverse of device time unit duration, in Hz.
*/
int dtu_freq_hz;
/**
* @symbol_dtu: Symbol duration in device time unit, can change if radio
* parameters are changed. Can be set to 1 if device time unit is the
* symbol.
*/
int symbol_dtu;
/**
* @cca_dtu: CCA duration in device time unit, can change if radio
* parameters or CCA modes are changed.
*/
int cca_dtu;
/**
* @shr_dtu: Synchronisation header duration in device time unit, can
* change if radio parameters are changed. If ranging is supported, this
* is the difference between the RMARKER and the first frame symbol.
*/
int shr_dtu;
/**
* @dtu_rctu: Duration of one device time unit in ranging counter time
* unit (RDEV only).
*/
int dtu_rctu;
/**
* @rstu_dtu: Duration of ranging slot time unit in device time unit
* (ERDEV only).
*/
int rstu_dtu;
/**
* @anticip_dtu: Reasonable delay between reading the current timestamp
* and doing an operation in device time unit.
*/
int anticip_dtu;
/**
* @idle_dtu: Duration long enough to prefer entering the idle mode
* rather than trying to find a valid access.
*/
int idle_dtu;
/**
* @flags: Low-level hardware flags, see &enum mcps802154_llhw_flags.
*/
u32 flags;
/**
* @hw: Pointer to IEEE802154 hardware exposed by MCPS. The low-level
* driver needs to update this and hw->phy according to supported
* hardware features and radio parameters. More specifically:
*
* * &ieee802154_hw.extra_tx_headroom
* * in &ieee802154_hw.flags:
*
* * IEEE802154_HW_TX_OMIT_CKSUM
* * IEEE802154_HW_RX_OMIT_CKSUM
* * IEEE802154_HW_RX_DROP_BAD_CKSUM
*
* * &wpan_phy.flags
* * &wpan_phy_supported
* * &wpan_phy.symbol_duration
*/
struct ieee802154_hw *hw;
/**
* @priv: Driver private data.
*/
void *priv;
};
enum mcps802154_tx_frame_info_flags {
MCPS802154_TX_FRAME_TIMESTAMP_DTU = BIT(0),
MCPS802154_TX_FRAME_CCA = BIT(1),
MCPS802154_TX_FRAME_RANGING = BIT(2),
MCPS802154_TX_FRAME_KEEP_RANGING_CLOCK = BIT(3),
MCPS802154_TX_FRAME_SP1 = BIT(4),
MCPS802154_TX_FRAME_SP2 = BIT(5),
MCPS802154_TX_FRAME_SP3 = BIT(4) | BIT(5),
MCPS802154_TX_FRAME_STS_MODE_MASK = BIT(4) | BIT(5),
};
struct mcps802154_tx_frame_info {
/**
* @timestamp_dtu: If timestamped, date of transmission start.
*/
u32 timestamp_dtu;
/**
* @rx_enable_after_tx_dtu: If positive, enable receiver this number of
* device time unit after the end of the transmitted frame.
*/
int rx_enable_after_tx_dtu;
/**
* @rx_enable_after_tx_timeout_dtu: When receiver is enabled after the
* end of the transmitted frame: if negative, no timeout, if zero, use
* a default timeout value, else this is the timeout value in device
* time unit.
*/
int rx_enable_after_tx_timeout_dtu;
/**
* @flags: See &enum mcps802154_tx_frame_info_flags.
*/
u8 flags;
/**
* @ant_id: antenna index to use for transmit.
*/
int ant_id;
};
enum mcps802154_rx_info_flags {
MCPS802154_RX_INFO_TIMESTAMP_DTU = BIT(0),
MCPS802154_RX_INFO_AACK = BIT(1),
MCPS802154_RX_INFO_RANGING = BIT(2),
MCPS802154_RX_INFO_KEEP_RANGING_CLOCK = BIT(3),
MCPS802154_RX_INFO_SP1 = BIT(4),
MCPS802154_RX_INFO_SP2 = BIT(5),
MCPS802154_RX_INFO_SP3 = BIT(4) | BIT(5),
MCPS802154_RX_INFO_STS_MODE_MASK = BIT(4) | BIT(5),
};
struct mcps802154_rx_info {
/**
* @timestamp_dtu: If timestamped, date to enable the receiver.
*/
u32 timestamp_dtu;
/**
* @timeout_dtu: 负数,无超时;0,默认超时;正数为设定的超时时间
*/
int timeout_dtu;
/**
* @flags: See &enum mcps802154_rx_info_flags.
*/
u8 flags;
/**
* @ant_pair_id: 用于接收的天线配对索引
*/
u8 ant_pair_id;
};
接收帧信息相关。
接收帧信息标志包括测距时间戳、LQI、RSSI、测距FOM、PDOA、STS等相关的接收帧标志。
enum mcps802154_rx_frame_info_flags {
MCPS802154_RX_FRAME_INFO_TIMESTAMP_DTU = BIT(0),
MCPS802154_RX_FRAME_INFO_TIMESTAMP_RCTU = BIT(1),
MCPS802154_RX_FRAME_INFO_LQI = BIT(2),
MCPS802154_RX_FRAME_INFO_RSSI = BIT(3),
MCPS802154_RX_FRAME_INFO_RANGING_FOM = BIT(4),
MCPS802154_RX_FRAME_INFO_RANGING_OFFSET = BIT(5),
MCPS802154_RX_FRAME_INFO_RANGING_PDOA = BIT(6),
MCPS802154_RX_FRAME_INFO_RANGING_PDOA_FOM = BIT(7),
MCPS802154_RX_FRAME_INFO_RANGING_STS_TIMESTAMP_RCTU = BIT(8),
MCPS802154_RX_FRAME_INFO_RANGING_STS_FOM = BIT(9),
MCPS802154_RX_FRAME_INFO_AACK = BIT(10),
};
struct mcps802154_rx_frame_info {
/**
* @timestamp_dtu: Timestamp of start of frame in device time unit.
*/
u32 timestamp_dtu;
/**
* @timestamp_rctu: Timestamp of RMARKER in ranging count time unit
* (RDEV only).
*/
u64 timestamp_rctu;
/**
* @frame_duration_dtu: Duration of the whole frame in device time unit
* or 0 if unknown.
*/
int frame_duration_dtu;
int rssi;
/**
* @ranging_tracking_interval_rctu: Interval on which tracking offset
* was measured (RDEV only).
*/
int ranging_tracking_interval_rctu;
/**
* @ranging_offset_rctu: Difference between the transmitter and the
* receiver clock measure over the tracking interval, if positive, the
* transmitter operates at a higher frequency (RDEV only).
*/
int ranging_offset_rctu;
/**
* @ranging_pdoa_rad_q11: Phase difference of arrival, unit is radian
* multiplied by 2048 (RDEV only).
*/
int ranging_pdoa_rad_q11;
/**
* @ranging_pdoa_spacing_mm_q11: Spacing between antennas, unit is mm
* multiplied by 2048 (RDEV only).
*/
int ranging_pdoa_spacing_mm_q11;
/**
* @ranging_sts_timestamp_diffs_rctu: For each SRMARKERx, difference
* between the measured timestamp and the expected timestamp relative to
* RMARKER in ranging count time unit (ERDEV only). When STS mode is
* 1 or 3, SRMARKER0 is the same as RMARKER and difference is always 0.
*/
s16 ranging_sts_timestamp_diffs_rctu[MCPS802154_STS_N_SEGS_MAX + 1];
/**
* @lqi: Link quality indicator (LQI).
*/
u8 lqi;
/**
* @ranging_fom: Ranging figure of merit (FoM, RDEV only). Should be
* formatted according to 802.15.4.
*/
u8 ranging_fom;
/**
* @ranging_pdoa_fom: Phase difference of arrival figure of merit (FoM,
* RDEV only). Range is 0 to 255, with 0 being an invalid measure and
* 255 being a 100% confidence.
*/
u8 ranging_pdoa_fom;
/**
* @ranging_sts_fom: Table of figures of merit measuring the correlation
* strength between the received STS segment and the expected one (FoM,
* ERDEV only). Range is 0 to 255, with 0 being an invalid measure and
* 255 being a 100% confidence.
*/
u8 ranging_sts_fom[MCPS802154_STS_N_SEGS_MAX];
/**
* @flags: See &enum mcps802154_rx_frame_info_flags.
*/
u16 flags;
};
HRP UWB的STS参数,包括用在DRBG中生成STS的Value与key,以及STS段的数量以及每个段内STS的长度(FiRa、CCC的标准中通常使用1个STS段,长度为64个Symbol)。
另外,针对SP2模式帧格式,定义了STS与payload之间的附加gap信息。
struct mcps802154_sts_params {
/**
* @v: Value V used in DRBG for generating the STS. The 32 LSB are the
* VCounter which is incremented every 128 generated pulse.
*/
u8 v[AES_BLOCK_SIZE];
/**
* @key: STS AES key used in DRBG for generating the STS.
*/
u8 key[AES_KEYSIZE_128];
int n_segs;
int seg_len;
/**
* @sp2_tx_gap_4chips: For SP2 frame format, additional gap in unit of
* 4 chips between the end of the payload and the start of the STS, used
* for TX.
*/
int sp2_tx_gap_4chips;
/**
* @sp2_rx_gap_4chips: For SP2 frame format, additional gap in unit of
* 4 chips between the end of the payload and the start of the STS, used
* for RX. A0 and A1 bits in PHR are used to index the array.
*/
int sp2_rx_gap_4chips[MCPS802154_STS_N_SEGS_MAX];
};
定义了底层驱动相关的实现接口回调,包括初始化底层设备、停止、发送、接收等常规操作接口。
struct mcps802154_ops {
/**
* @start: Initialize device. Reception should not be activated.
*/
int (*start)(struct mcps802154_llhw *llhw);
/**
* @stop: Stop device. Should stop any transmission or reception and put
* the device in a low power mode.
*/
void (*stop)(struct mcps802154_llhw *llhw);
/**
* @tx_frame: Transmit a frame. skb应包含从IEEE 802.15.4帧头开始的数据。底层驱动将根据设定发送帧信息发送。接收机应在没有收到帧的情况下自动关闭。
*
* @next_delay_dtu : 表示预期发送帧开始和下一动作之间的延迟时间
*
*/
int (*tx_frame)(struct mcps802154_llhw *llhw, struct sk_buff *skb,
const struct mcps802154_tx_frame_info *info,
int next_delay_dtu);
/**
* @rx_enable: 使能接收机。
* @next_delay_dtu: 表示预期从开始接受帧或帧接收超时之间的时间。
*/
int (*rx_enable)(struct mcps802154_llhw *llhw,
const struct mcps802154_rx_info *info,
int next_delay_dtu);
/**
* @rx_disable: Disable receiver
*/
int (*rx_disable)(struct mcps802154_llhw *llhw);
/**
* @rx_get_frame: Get previously received frame. MCPS calls this handler
* after a frame reception has been signaled by the low-level driver.
*
* The received buffer is owned by MCPS after this call. Only the
* requested information need to be filled in the information structure.
*
*/
int (*rx_get_frame)(struct mcps802154_llhw *llhw, struct sk_buff **skb,
struct mcps802154_rx_frame_info *info);
/**
* @rx_get_error_frame: Get information on rejected frame. MCPS can call
* this handler after a frame rejection has been signaled by the
* low-level driver.
*/
int (*rx_get_error_frame)(struct mcps802154_llhw *llhw,
struct mcps802154_rx_frame_info *info);
/**
* @idle: Put the device into idle mode without time limit or until the
* given timestamp. The driver should call &mcps802154_timer_expired()
* before the given timestamp so that an action can be programmed at the
* given timestamp.
*
* The &mcps802154_timer_expired() function must not be called
* immediately from this callback, but should be scheduled to be called
* later.
*
* If the driver is late, the regular handling of late actions will take
* care of the situation.
*/
int (*idle)(struct mcps802154_llhw *llhw, bool timestamp,
u32 timestamp_dtu);
/**
* @reset: Reset device after an unrecoverable error.
*/
int (*reset)(struct mcps802154_llhw *llhw);
/**
* @get_current_timestamp_dtu: Get current timestamp in device time
* unit.
*
* If the device is currently in a low power state, the eventual wake up
* delay should be added to the returned timestamp.
*
* If the current timestamp can not be determined precisely, it should
* return a pessimistic value, i.e. rounded up.
*/
int (*get_current_timestamp_dtu)(struct mcps802154_llhw *llhw,
u32 *timestamp_dtu);
/**
* @timestamp_dtu_to_rctu: Convert a timestamp in device time unit to
* a timestamp in ranging counter time unit.
*/
u64 (*timestamp_dtu_to_rctu)(struct mcps802154_llhw *llhw,
u32 timestamp_dtu);
/**
* @timestamp_rctu_to_dtu: Convert a timestamp in ranging counter time
* unit to a timestamp in device time unit.
*/
u32 (*timestamp_rctu_to_dtu)(struct mcps802154_llhw *llhw,
u64 timestamp_rctu);
/**
* @tx_timestamp_dtu_to_rmarker_rctu: Compute the RMARKER timestamp in
* ranging counter time unit for a frame transmitted at given timestamp
* in device time unit (RDEV only).
*
* Return: The RMARKER timestamp.
*/
u64 (*tx_timestamp_dtu_to_rmarker_rctu)(struct mcps802154_llhw *llhw,
u32 tx_timestamp_dtu,
int ant_id);
/**
* @difference_timestamp_rctu: Compute the difference between two
* timestamp values.
*
* Return: The difference between A and B.
*/
s64 (*difference_timestamp_rctu)(struct mcps802154_llhw *llhw,
u64 timestamp_a_rctu,
u64 timestamp_b_rctu);
/**
* @compute_frame_duration_dtu: Compute the duration of a frame with
* given payload length (header and checksum included) using the current
* radio parameters.
*
* Return: The duration in device time unit.
*/
int (*compute_frame_duration_dtu)(struct mcps802154_llhw *llhw,
int payload_bytes);
/**
* @set_channel: Set channel parameters.
*/
int (*set_channel)(struct mcps802154_llhw *llhw, u8 page, u8 channel,
u8 preamble_code);
/**
* @set_hrp_uwb_params: Set radio parameters for HRP UWB.
*
* The parameters in &mcps802154_llhw can change according to radio
* parameters.
*/
int (*set_hrp_uwb_params)(struct mcps802154_llhw *llhw, int prf,
int psr, int sfd_selector, int phr_rate,
int data_rate);
/**
* @set_sts_params: Set STS parameters (ERDEV only).
*/
int (*set_sts_params)(struct mcps802154_llhw *llhw,
const struct mcps802154_sts_params *params);
/**
* @set_hw_addr_filt: Set hardware filter parameters.
*/
int (*set_hw_addr_filt)(struct mcps802154_llhw *llhw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed);
/**
* @set_txpower: Set transmission power.
*/
int (*set_txpower)(struct mcps802154_llhw *llhw, s32 mbm);
/**
* @set_cca_mode: Set CCA mode.
*
* The CCA duration in &mcps802154_llhw can change according to CCA
* mode.
*/
int (*set_cca_mode)(struct mcps802154_llhw *llhw,
const struct wpan_phy_cca *cca);
/**
* @set_cca_ed_level: Set CCA energy detection threshold.
*/
int (*set_cca_ed_level)(struct mcps802154_llhw *llhw, s32 mbm);
/**
* @set_promiscuous_mode: Set promiscuous mode.
*/
int (*set_promiscuous_mode)(struct mcps802154_llhw *llhw, bool on);
/**
* @set_scanning_mode: Set SW scanning mode.
*/
int (*set_scanning_mode)(struct mcps802154_llhw *llhw, bool on);
/**
* @set_calibration: Set calibration value.
*
* Set the calibration parameter specified by the key string with the
* value specified in the provided buffer. The provided length must
* match the length returned by the @get_calibration() callback.
*/
int (*set_calibration)(struct mcps802154_llhw *llhw, const char *key,
void *value, size_t length);
/**
* @get_calibration: Get calibration value.
*
* Get the calibration parameter specified by the key string into the
* provided buffer.
*
* Return: size of parameter written in buffer or error.
*/
int (*get_calibration)(struct mcps802154_llhw *llhw, const char *key,
void *value, size_t length);
/**
* @list_calibration: Returns list of accepted calibration key strings.
*/
const char *const *(*list_calibration)(struct mcps802154_llhw *llhw);
/**
* @vendor_cmd: 运行一个供应商特定命令。Run a vendor specific command.
*/
int (*vendor_cmd)(struct mcps802154_llhw *llhw, u32 vendor_id,
u32 subcmd, void *data, size_t data_len);
#ifdef CONFIG_MCPS802154_TESTMODE
/**
* @testmode_cmd: Run a testmode command.
*/
int (*testmode_cmd)(struct mcps802154_llhw *llhw, void *data, int len);
#endif
};