aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenri Chataing <henrichataing@google.com>2024-02-29 14:09:14 -0800
committerhchataing <104974782+hchataing@users.noreply.github.com>2024-03-14 17:08:52 -0700
commit225d2513d392f525078c395273e2fb821646926a (patch)
tree30631739b465fd01974869dfb1edc88f55c86b91
parent4c63b1f5a790cd5bb1812b22e351d63bd19027e9 (diff)
downloadpica-225d2513d392f525078c395273e2fb821646926a.tar.gz
Refactor APP config management
- Move enum definitions to uci_packets.pdl - Move AppConfig declaration to separate module for readability - Sync APP config definitions with UCI 2.0 - Fix mis-declaration of Device Role (responder and initiator reversed)
-rw-r--r--Cargo.lock2
-rw-r--r--py/pica/pica/packets/uci.py482
-rw-r--r--src/app_config.rs497
-rw-r--r--src/lib.rs12
-rw-r--r--src/mac_address.rs15
-rw-r--r--src/session.rs784
-rw-r--r--src/uci_packets.pdl235
-rwxr-xr-xtests/data_transfer.py54
-rwxr-xr-xtests/ranging.py54
9 files changed, 1352 insertions, 783 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a59c5c0..67143ef 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -648,7 +648,7 @@ dependencies = [
[[package]]
name = "pica"
-version = "0.1.7"
+version = "0.1.8"
dependencies = [
"anyhow",
"bytes",
diff --git a/py/pica/pica/packets/uci.py b/py/pica/pica/packets/uci.py
index 32ffbdc..0043c45 100644
--- a/py/pica/pica/packets/uci.py
+++ b/py/pica/pica/packets/uci.py
@@ -351,7 +351,7 @@ class AppConfigTlvType(enum.IntEnum):
STS_CONFIG = 0x2
MULTI_NODE_MODE = 0x3
CHANNEL_NUMBER = 0x4
- NO_OF_CONTROLEE = 0x5
+ NUMBER_OF_CONTROLEES = 0x5
DEVICE_MAC_ADDRESS = 0x6
DST_MAC_ADDRESS = 0x7
SLOT_DURATION = 0x8
@@ -360,9 +360,9 @@ class AppConfigTlvType(enum.IntEnum):
MAC_FCS_TYPE = 0xb
RANGING_ROUND_CONTROL = 0xc
AOA_RESULT_REQ = 0xd
- RNG_DATA_NTF = 0xe
- RNG_DATA_NTF_PROXIMITY_NEAR = 0xf
- RNG_DATA_NTF_PROXIMITY_FAR = 0x10
+ SESSION_INFO_NTF_CONFIG = 0xe
+ NEAR_PROXIMITY_CONFIG = 0xf
+ FAR_PROXIMITY_CONFIG = 0x10
DEVICE_ROLE = 0x11
RFRAME_CONFIG = 0x12
RSSI_REPORTING = 0x13
@@ -374,13 +374,11 @@ class AppConfigTlvType(enum.IntEnum):
DATA_REPETITION_COUNT = 0x19
RANGING_TIME_STRUCT = 0x1a
SLOTS_PER_RR = 0x1b
- TX_ADAPTIVE_PAYLOAD_POWER = 0x1c
- RNG_DATA_NTF_AOA_BOUND = 0x1d
- RESPONDER_SLOT_INDEX = 0x1e
+ AOA_BOUND_CONFIG = 0x1d
PRF_MODE = 0x1f
CAP_SIZE_RANGE = 0x20
TX_JITTER_WINDOW_SIZE = 0x21
- SCHEDULED_MODE = 0x22
+ SCHEDULE_MODE = 0x22
KEY_ROTATION = 0x23
KEY_ROTATION_RATE = 0x24
SESSION_PRIORITY = 0x25
@@ -397,13 +395,7 @@ class AppConfigTlvType(enum.IntEnum):
SUB_SESSION_ID = 0x30
BPRF_PHR_DATA_RATE = 0x31
MAX_NUMBER_OF_MEASUREMENTS = 0x32
- UL_TDOA_TX_INTERVAL = 0x33
- UL_TDOA_RANDOM_WINDOW = 0x34
STS_LENGTH = 0x35
- SUSPEND_RANGING_ROUNDS = 0x36
- UL_TDOA_NTF_REPORT_CONFIG = 0x37
- UL_TDOA_DEVICE_ID = 0x38
- UL_TDOA_TX_TIMESTAMP = 0x39
MIN_FRAMES_PER_RR = 0x3a
MTU_SIZE = 0x3b
INTER_FRAME_INTERVAL = 0x3c
@@ -413,10 +405,10 @@ class AppConfigTlvType(enum.IntEnum):
DL_TDOA_ANCHOR_CFO = 0x40
DL_TDOA_ANCHOR_LOCATION = 0x41
DL_TDOA_TX_ACTIVE_RANGING_ROUNDS = 0x42
- DL_TDOA_BLOCK_STRIDING = 0x43
+ DL_TDOA_BLOCK_SKIPPING = 0x43
DL_TDOA_TIME_REFERENCE_ANCHOR = 0x44
SESSION_KEY = 0x45
- SUBSESSION_KEY = 0x46
+ SUB_SESSION_KEY = 0x46
SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG = 0x47
SESSION_TIME_BASE = 0x48
DL_TDOA_RESPONDER_TOF = 0x49
@@ -433,15 +425,434 @@ class AppConfigTlvType(enum.IntEnum):
return v
-class FrameReportTlvType(enum.IntEnum):
- RSSI = 0x0
- AOA = 0x1
- CIR = 0x2
+class DeviceType(enum.IntEnum):
+ CONTROLEE = 0x0
+ CONTROLLER = 0x1
@staticmethod
- def from_int(v: int) -> Union[int, 'FrameReportTlvType']:
+ def from_int(v: int) -> Union[int, 'DeviceType']:
try:
- return FrameReportTlvType(v)
+ return DeviceType(v)
+ except ValueError as exn:
+ raise exn
+
+
+class RangingRoundUsage(enum.IntEnum):
+ SS_TWR_DEFERRED_MODE = 0x1
+ DS_TWR_DEFERRED_MODE = 0x2
+ SS_TWR_NON_DEFERRED_MODE = 0x3
+ DS_TWR_NON_DEFERRED_MODE = 0x4
+ ON_WAY_RANGING_DL_TDOA = 0x5
+ OWR_AOA_MEASUREMENT = 0x6
+ ESS_TWR_NON_DEFERRED = 0x7
+ ADS_TWR_NON_DEFERRED = 0x8
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'RangingRoundUsage']:
+ try:
+ return RangingRoundUsage(v)
+ except ValueError as exn:
+ raise exn
+
+
+class StsConfig(enum.IntEnum):
+ STATIC = 0x0
+ DYNAMIC = 0x1
+ DYNAMIC_FOR_RESPONDER_SUB_SESSION_KEY = 0x2
+ PROVISIONED = 0x3
+ PROVISIONED_FOR_RESPONDER_SUB_SESSION_KEY = 0x4
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'StsConfig']:
+ try:
+ return StsConfig(v)
+ except ValueError as exn:
+ raise exn
+
+
+class MultiNodeMode(enum.IntEnum):
+ ONE_TO_ONE = 0x0
+ ONE_TO_MANY = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'MultiNodeMode']:
+ try:
+ return MultiNodeMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class ChannelNumber(enum.IntEnum):
+ CHANNEL_NUMBER_5 = 0x5
+ CHANNEL_NUMBER_6 = 0x6
+ CHANNEL_NUMBER_8 = 0x8
+ CHANNEL_NUMBER_9 = 0x9
+ CHANNEL_NUMBER_10 = 0xa
+ CHANNEL_NUMBER_12 = 0xc
+ CHANNEL_NUMBER_13 = 0xd
+ CHANNEL_NUMBER_14 = 0xe
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'ChannelNumber']:
+ try:
+ return ChannelNumber(v)
+ except ValueError as exn:
+ raise exn
+
+
+class MacFcsType(enum.IntEnum):
+ CRC_16 = 0x0
+ CRC_32 = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'MacFcsType']:
+ try:
+ return MacFcsType(v)
+ except ValueError as exn:
+ raise exn
+
+
+@dataclass
+class RangingRoundControl(Packet):
+ rrrm: int = field(kw_only=True, default=0)
+ rcp: int = field(kw_only=True, default=0)
+ mrp: int = field(kw_only=True, default=0)
+ mrm: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ pass
+
+ @staticmethod
+ def parse(span: bytes) -> Tuple['RangingRoundControl', bytes]:
+ fields = {'payload': None}
+ if len(span) < 1:
+ raise Exception('Invalid packet size')
+ fields['rrrm'] = (span[0] >> 0) & 0x1
+ if (span[0] >> 1) & 0x1 != 0x1:
+ raise Exception('Unexpected fixed field value')
+ fields['rcp'] = (span[0] >> 2) & 0x1
+ fields['mrp'] = (span[0] >> 6) & 0x1
+ fields['mrm'] = (span[0] >> 7) & 0x1
+ span = span[1:]
+ return RangingRoundControl(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.rrrm > 1:
+ print(f"Invalid value for field RangingRoundControl::rrrm: {self.rrrm} > 1; the value will be truncated")
+ self.rrrm &= 1
+ if self.rcp > 1:
+ print(f"Invalid value for field RangingRoundControl::rcp: {self.rcp} > 1; the value will be truncated")
+ self.rcp &= 1
+ if self.mrp > 1:
+ print(f"Invalid value for field RangingRoundControl::mrp: {self.mrp} > 1; the value will be truncated")
+ self.mrp &= 1
+ if self.mrm > 1:
+ print(f"Invalid value for field RangingRoundControl::mrm: {self.mrm} > 1; the value will be truncated")
+ self.mrm &= 1
+ _value = (
+ (self.rrrm << 0) |
+ (1 << 1) |
+ (self.rcp << 2) |
+ (self.mrp << 6) |
+ (self.mrm << 7)
+ )
+ _span.append(_value)
+ return bytes(_span)
+
+ @property
+ def size(self) -> int:
+ return 1
+
+class AoaResultReq(enum.IntEnum):
+ AOA_DISABLED = 0x0
+ AOA_ENABLED = 0x1
+ AOA_ENABLED_AZIMUTH_ONLY = 0x2
+ AOA_ENABLED_ELEVATION_ONLY = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'AoaResultReq']:
+ try:
+ return AoaResultReq(v)
+ except ValueError as exn:
+ raise exn
+
+
+class SessionInfoNtfConfig(enum.IntEnum):
+ DISABLE = 0x0
+ ENABLE = 0x1
+ ENABLE_PROXIMITY_TRIGGER = 0x2
+ ENABLE_AOA_TRIGGER = 0x3
+ ENABLE_PROXIMITY_AOA_TRIGGER = 0x4
+ ENABLE_PROXIMITY_EDGE_TRIGGER = 0x5
+ ENABLE_AOA_EDGE_TRIGGER = 0x6
+ ENABLE_PROXIMITY_AOA_EDGE_TRIGGER = 0x7
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'SessionInfoNtfConfig']:
+ try:
+ return SessionInfoNtfConfig(v)
+ except ValueError as exn:
+ raise exn
+
+
+class DeviceRole(enum.IntEnum):
+ RESPONDER = 0x0
+ INITIATOR = 0x1
+ ADVERTISER = 0x5
+ OBSERVER = 0x6
+ DT_ANCHOR = 0x7
+ DT_TAG = 0x8
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'DeviceRole']:
+ try:
+ return DeviceRole(v)
+ except ValueError as exn:
+ raise exn
+
+
+class RframeConfig(enum.IntEnum):
+ SP0 = 0x0
+ SP1 = 0x1
+ SP3 = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'RframeConfig']:
+ try:
+ return RframeConfig(v)
+ except ValueError as exn:
+ raise exn
+
+
+class RssiReporting(enum.IntEnum):
+ DISABLE = 0x0
+ ENABLE = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'RssiReporting']:
+ try:
+ return RssiReporting(v)
+ except ValueError as exn:
+ raise exn
+
+
+class PsduDataRate(enum.IntEnum):
+ DATA_RATE_6M81 = 0x0
+ DATA_RATE_7M80 = 0x1
+ DATA_RATE_27M2 = 0x2
+ DATA_RATE_31M2 = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'PsduDataRate']:
+ try:
+ return PsduDataRate(v)
+ except ValueError as exn:
+ raise exn
+
+
+class PreambleDuration(enum.IntEnum):
+ DURATION_32_SYMBOLS = 0x0
+ DURATION_64_SYMBOLS = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'PreambleDuration']:
+ try:
+ return PreambleDuration(v)
+ except ValueError as exn:
+ raise exn
+
+
+class LinkLayerMode(enum.IntEnum):
+ BYPASS_MODE = 0x0
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'LinkLayerMode']:
+ try:
+ return LinkLayerMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class RangingTimeStruct(enum.IntEnum):
+ BLOCK_BASED_SCHEDULING = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'RangingTimeStruct']:
+ try:
+ return RangingTimeStruct(v)
+ except ValueError as exn:
+ raise exn
+
+
+class PrfMode(enum.IntEnum):
+ BPRF_MODE = 0x0
+ HPRF_MODE_124M8 = 0x1
+ HPRF_MODE_249M6 = 0x2
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'PrfMode']:
+ try:
+ return PrfMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class ScheduleMode(enum.IntEnum):
+ CONTENTION_BASED = 0x0
+ TIME_SCHEDULED = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'ScheduleMode']:
+ try:
+ return ScheduleMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class KeyRotation(enum.IntEnum):
+ DISABLE = 0x0
+ ENABLE = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'KeyRotation']:
+ try:
+ return KeyRotation(v)
+ except ValueError as exn:
+ raise exn
+
+
+class MacAddressMode(enum.IntEnum):
+ MODE_0 = 0x0
+ MODE_1 = 0x1
+ MODE_2 = 0x2
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'MacAddressMode']:
+ try:
+ return MacAddressMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+class HoppingMode(enum.IntEnum):
+ DISABLE = 0x0
+ ENABLE = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'HoppingMode']:
+ try:
+ return HoppingMode(v)
+ except ValueError as exn:
+ raise exn
+
+
+@dataclass
+class ResultReportConfig(Packet):
+ tof: int = field(kw_only=True, default=0)
+ aoa_azimuth: int = field(kw_only=True, default=0)
+ aoa_elevation: int = field(kw_only=True, default=0)
+ aoa_fom: int = field(kw_only=True, default=0)
+
+ def __post_init__(self):
+ pass
+
+ @staticmethod
+ def parse(span: bytes) -> Tuple['ResultReportConfig', bytes]:
+ fields = {'payload': None}
+ if len(span) < 1:
+ raise Exception('Invalid packet size')
+ fields['tof'] = (span[0] >> 0) & 0x1
+ fields['aoa_azimuth'] = (span[0] >> 1) & 0x1
+ fields['aoa_elevation'] = (span[0] >> 2) & 0x1
+ fields['aoa_fom'] = (span[0] >> 3) & 0x1
+ span = span[1:]
+ return ResultReportConfig(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ if self.tof > 1:
+ print(f"Invalid value for field ResultReportConfig::tof: {self.tof} > 1; the value will be truncated")
+ self.tof &= 1
+ if self.aoa_azimuth > 1:
+ print(f"Invalid value for field ResultReportConfig::aoa_azimuth: {self.aoa_azimuth} > 1; the value will be truncated")
+ self.aoa_azimuth &= 1
+ if self.aoa_elevation > 1:
+ print(f"Invalid value for field ResultReportConfig::aoa_elevation: {self.aoa_elevation} > 1; the value will be truncated")
+ self.aoa_elevation &= 1
+ if self.aoa_fom > 1:
+ print(f"Invalid value for field ResultReportConfig::aoa_fom: {self.aoa_fom} > 1; the value will be truncated")
+ self.aoa_fom &= 1
+ _value = (
+ (self.tof << 0) |
+ (self.aoa_azimuth << 1) |
+ (self.aoa_elevation << 2) |
+ (self.aoa_fom << 3)
+ )
+ _span.append(_value)
+ return bytes(_span)
+
+ @property
+ def size(self) -> int:
+ return 1
+
+class BprfPhrDataRate(enum.IntEnum):
+ DATA_RATE_850K = 0x0
+ DATA_RATE_6M81 = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'BprfPhrDataRate']:
+ try:
+ return BprfPhrDataRate(v)
+ except ValueError as exn:
+ raise exn
+
+
+class StsLength(enum.IntEnum):
+ LENGTH_32_SYMBOLS = 0x0
+ LENGTH_64_SYMBOLS = 0x1
+ LENGTH_128_SYMBOLS = 0x2
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'StsLength']:
+ try:
+ return StsLength(v)
+ except ValueError as exn:
+ raise exn
+
+
+class DlTdoaRangingMethod(enum.IntEnum):
+ SS_TWR = 0x0
+ DS_TWR = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'DlTdoaRangingMethod']:
+ try:
+ return DlTdoaRangingMethod(v)
+ except ValueError as exn:
+ raise exn
+
+
+class DlTdoaAnchorCfo(enum.IntEnum):
+ ANCHOR_CFO_NOT_INCLUDED = 0x0
+ ANCHOR_CFO_INCLUDED = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'DlTdoaAnchorCfo']:
+ try:
+ return DlTdoaAnchorCfo(v)
+ except ValueError as exn:
+ raise exn
+
+
+class SessionDataTransferStatusNtfConfig(enum.IntEnum):
+ DISABLE = 0x0
+ ENABLE = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'SessionDataTransferStatusNtfConfig']:
+ try:
+ return SessionDataTransferStatusNtfConfig(v)
except ValueError as exn:
raise exn
@@ -2875,7 +3286,7 @@ class SessionSetAppConfigRsp(SessionConfigResponse):
@dataclass
class SessionGetAppConfigCmd(SessionConfigCommand):
session_token: int = field(kw_only=True, default=0)
- app_cfg: bytearray = field(kw_only=True, default_factory=bytearray)
+ app_cfg: List[AppConfigTlvType] = field(kw_only=True, default_factory=list)
def __post_init__(self):
self.opcode = 4
@@ -2894,7 +3305,10 @@ class SessionGetAppConfigCmd(SessionConfigCommand):
span = span[5:]
if len(span) < app_cfg_count:
raise Exception('Invalid packet size')
- fields['app_cfg'] = list(span[:app_cfg_count])
+ app_cfg = []
+ for n in range(app_cfg_count):
+ app_cfg.append(AppConfigTlvType(int.from_bytes(span[n:n + 1], byteorder='little')))
+ fields['app_cfg'] = app_cfg
span = span[app_cfg_count:]
return SessionGetAppConfigCmd(**fields), span
@@ -2908,12 +3322,13 @@ class SessionGetAppConfigCmd(SessionConfigCommand):
print(f"Invalid length for field SessionGetAppConfigCmd::app_cfg: {len(self.app_cfg)} > 255; the array will be truncated")
del self.app_cfg[255:]
_span.append((len(self.app_cfg) << 0))
- _span.extend(self.app_cfg)
+ for _elt in self.app_cfg:
+ _span.append(_elt)
return SessionConfigCommand.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.app_cfg) * 1 + 5
+ return len(self.app_cfg) * 8 + 5
@dataclass
class SessionGetAppConfigRsp(SessionConfigResponse):
@@ -3279,7 +3694,7 @@ class UpdateMulticastListAction(enum.IntEnum):
ADD_CONTROLEE = 0x0
REMOVE_CONTROLEE = 0x1
ADD_CONTROLEE_WITH_SHORT_SUB_SESSION_KEY = 0x2
- ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY = 0x3
+ ADD_CONTROLEE_WITH_EXTENDED_SUB_SESSION_KEY = 0x3
@staticmethod
def from_int(v: int) -> Union[int, 'UpdateMulticastListAction']:
@@ -4908,6 +5323,19 @@ class AndroidSetCountryCodeRsp(AndroidResponse):
def size(self) -> int:
return 1
+class FrameReportTlvType(enum.IntEnum):
+ RSSI = 0x0
+ AOA = 0x1
+ CIR = 0x2
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'FrameReportTlvType']:
+ try:
+ return FrameReportTlvType(v)
+ except ValueError as exn:
+ raise exn
+
+
@dataclass
class FrameReportTlv(Packet):
t: FrameReportTlvType = field(kw_only=True, default=FrameReportTlvType.RSSI)
diff --git a/src/app_config.rs b/src/app_config.rs
new file mode 100644
index 0000000..82cb738
--- /dev/null
+++ b/src/app_config.rs
@@ -0,0 +1,497 @@
+use crate::packets::uci;
+use crate::MacAddress;
+
+/// [UCI] 8.3 Application Configuration Parameters.
+/// The configuration is initially filled with default values from the
+/// specification.
+/// See [UCI] Table 45: APP Configuration Parameters IDs
+/// for the format of each parameter and the default value.
+/// Mandatory APP configuration parameters are declared as optional,
+/// and must be set before moving the session from SESSION_STATE_INIT to
+/// SESSION_STATE_IDLE.
+#[derive(Clone, PartialEq, Eq)]
+pub struct AppConfig {
+ pub device_type: Option<uci::DeviceType>,
+ pub ranging_round_usage: Option<uci::RangingRoundUsage>,
+ pub sts_config: uci::StsConfig,
+ pub multi_node_mode: Option<uci::MultiNodeMode>,
+ channel_number: uci::ChannelNumber,
+ /// Number of Controlees(N) 1<=N<=8 (Default is 1)
+ pub number_of_controlees: u8,
+ /// MAC Address of the UWBS itself participating in UWB session.
+ /// The short address (2 bytes) or extended MAC address (8 bytes)
+ /// shall be indicated via MAC_ADDRESS_MODE config.
+ pub device_mac_address: Option<MacAddress>,
+ /// MAC Address list(N) for NUMBER_OF_CONTROLEES
+ /// devices participating in UWB Session.
+ ///
+ /// The size of this list shall be:
+ /// - equal to 1 when MULTI_NODE_MODE is set 0x00 (O2O).
+ /// - ranging from 1 to 8 when MULTI_NODE_MODE is set to 0x01 (O2M).
+ pub dst_mac_address: Vec<MacAddress>,
+ slot_duration: u16,
+ pub ranging_duration: u32,
+ sts_index: u32,
+ mac_fcs_type: uci::MacFcsType,
+ ranging_round_control: u8,
+ aoa_result_req: uci::AoaResultReq,
+ pub session_info_ntf_config: uci::SessionInfoNtfConfig,
+ near_proximity_config: u16,
+ far_proximity_config: u16,
+ pub device_role: Option<uci::DeviceRole>,
+ rframe_config: uci::RframeConfig,
+ rssi_reporting: uci::RssiReporting,
+ preamble_code_index: u8,
+ sfd_id: u8,
+ psdu_data_rate: uci::PsduDataRate,
+ preamble_duration: uci::PreambleDuration,
+ link_layer_mode: uci::LinkLayerMode,
+ data_repetition_count: u8,
+ ranging_time_struct: uci::RangingTimeStruct,
+ slots_per_rr: u8,
+ aoa_bound_config: [u16; 4],
+ prf_mode: uci::PrfMode,
+ cap_size_range: [u8; 2],
+ tx_jitter_window_size: u8,
+ pub schedule_mode: Option<uci::ScheduleMode>,
+ key_rotation: uci::KeyRotation,
+ key_rotation_rate: u8,
+ session_priority: u8,
+ pub mac_address_mode: uci::MacAddressMode,
+ vendor_id: u16,
+ static_sts_iv: [u8; 6],
+ number_of_sts_segments: u8,
+ max_rr_retry: u16,
+ uwb_initiation_time: u64,
+ hopping_mode: uci::HoppingMode,
+ block_stride_length: u8,
+ result_report_config: u8,
+ pub in_band_termination_attempt_count: u8,
+ sub_session_id: u32,
+ bprf_phr_data_rate: uci::BprfPhrDataRate,
+ max_number_of_measurements: u16,
+ sts_length: uci::StsLength,
+ min_frames_per_rr: u8,
+ mtu_size: u16,
+ inter_frame_interval: u8,
+ session_key: Vec<u8>,
+ sub_session_key: Vec<u8>,
+ pub session_data_transfer_status_ntf_config: uci::SessionDataTransferStatusNtfConfig,
+ session_time_base: [u8; 9],
+ application_data_endpoint: u8,
+}
+
+impl Default for AppConfig {
+ fn default() -> Self {
+ AppConfig {
+ device_type: None,
+ ranging_round_usage: None,
+ sts_config: uci::StsConfig::Static,
+ multi_node_mode: None,
+ channel_number: uci::ChannelNumber::ChannelNumber9,
+ number_of_controlees: 1,
+ device_mac_address: None,
+ dst_mac_address: vec![],
+ slot_duration: 2400,
+ ranging_duration: 200,
+ sts_index: 0,
+ mac_fcs_type: uci::MacFcsType::Crc16,
+ // The default is 0x03 when Time Scheduled Ranging is used,
+ // 0x06 when Contention-based Ranging is used.
+ ranging_round_control: 0x06,
+ aoa_result_req: uci::AoaResultReq::AoaEnabled,
+ session_info_ntf_config: uci::SessionInfoNtfConfig::Enable,
+ near_proximity_config: 0,
+ far_proximity_config: 20000,
+ device_role: None,
+ rframe_config: uci::RframeConfig::Sp3,
+ rssi_reporting: uci::RssiReporting::Disable,
+ preamble_code_index: 10,
+ sfd_id: 2,
+ psdu_data_rate: uci::PsduDataRate::DataRate6m81,
+ preamble_duration: uci::PreambleDuration::Duration64Symbols,
+ link_layer_mode: uci::LinkLayerMode::BypassMode,
+ data_repetition_count: 0,
+ ranging_time_struct: uci::RangingTimeStruct::BlockBasedScheduling,
+ slots_per_rr: 25,
+ aoa_bound_config: [0; 4],
+ prf_mode: uci::PrfMode::BprfMode,
+ // Default for Octet[0] is SLOTS_PER_RR - 1
+ cap_size_range: [24, 5],
+ tx_jitter_window_size: 0,
+ schedule_mode: None,
+ key_rotation: uci::KeyRotation::Disable,
+ key_rotation_rate: 0,
+ session_priority: 50,
+ mac_address_mode: uci::MacAddressMode::Mode0,
+ vendor_id: 0,
+ static_sts_iv: [0; 6],
+ number_of_sts_segments: 1,
+ max_rr_retry: 0,
+ uwb_initiation_time: 0,
+ hopping_mode: uci::HoppingMode::Disable,
+ block_stride_length: 0,
+ result_report_config: 0x01,
+ in_band_termination_attempt_count: 1,
+ sub_session_id: 0, // XX
+ bprf_phr_data_rate: uci::BprfPhrDataRate::DataRate850k,
+ max_number_of_measurements: 0,
+ sts_length: uci::StsLength::Length64Symbols,
+ min_frames_per_rr: 4,
+ mtu_size: 0, // XX
+ inter_frame_interval: 1,
+ session_key: vec![],
+ sub_session_key: vec![],
+ session_data_transfer_status_ntf_config:
+ uci::SessionDataTransferStatusNtfConfig::Disable,
+ session_time_base: [0; 9],
+ application_data_endpoint: 0,
+ }
+ }
+}
+
+impl AppConfig {
+ /// Set the APP configuration value with the selected identifier
+ /// and value. Returns `Ok` if the identifier is known and the value
+ /// well formatted, `Err` otherwise.
+ pub fn set(&mut self, id: uci::AppConfigTlvType, value: &[u8]) -> anyhow::Result<()> {
+ fn try_parse<T: TryFrom<u8, Error = u8>>(value: &[u8]) -> anyhow::Result<T> {
+ T::try_from(u8::from_le_bytes(value.try_into()?)).map_err(anyhow::Error::msg)
+ }
+
+ fn try_parse_u8(value: &[u8]) -> anyhow::Result<u8> {
+ Ok(u8::from_le_bytes(value.try_into()?))
+ }
+
+ fn try_parse_u16(value: &[u8]) -> anyhow::Result<u16> {
+ Ok(u16::from_le_bytes(value.try_into()?))
+ }
+
+ fn try_parse_u32(value: &[u8]) -> anyhow::Result<u32> {
+ Ok(u32::from_le_bytes(value.try_into()?))
+ }
+
+ fn try_parse_u64(value: &[u8]) -> anyhow::Result<u64> {
+ Ok(u64::from_le_bytes(value.try_into()?))
+ }
+
+ match id {
+ uci::AppConfigTlvType::DeviceType => self.device_type = Some(try_parse(value)?),
+ uci::AppConfigTlvType::RangingRoundUsage => {
+ self.ranging_round_usage = Some(try_parse(value)?)
+ }
+ uci::AppConfigTlvType::StsConfig => self.sts_config = try_parse(value)?,
+ uci::AppConfigTlvType::MultiNodeMode => self.multi_node_mode = Some(try_parse(value)?),
+ uci::AppConfigTlvType::ChannelNumber => self.channel_number = try_parse(value)?,
+ uci::AppConfigTlvType::NumberOfControlees => {
+ self.number_of_controlees = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::DeviceMacAddress => {
+ self.device_mac_address = Some(match self.mac_address_mode {
+ uci::MacAddressMode::Mode0 => MacAddress::Short(value.try_into()?),
+ uci::MacAddressMode::Mode1 => unimplemented!(),
+ uci::MacAddressMode::Mode2 => MacAddress::Extended(value.try_into()?),
+ })
+ }
+ uci::AppConfigTlvType::DstMacAddress => {
+ let mac_address_size = match self.mac_address_mode {
+ uci::MacAddressMode::Mode0 => 2,
+ uci::MacAddressMode::Mode1 => unimplemented!(),
+ uci::MacAddressMode::Mode2 => 8,
+ };
+ if value.len() != self.number_of_controlees as usize * mac_address_size {
+ log::error!(
+ "invalid dst_mac_address len: expected {}x{}, got {}",
+ self.number_of_controlees,
+ mac_address_size,
+ value.len()
+ );
+ anyhow::bail!("invalid dst_mac_address len")
+ }
+ self.dst_mac_address = value
+ .chunks(mac_address_size)
+ .map(|value| match self.mac_address_mode {
+ uci::MacAddressMode::Mode0 => MacAddress::Short(value.try_into().unwrap()),
+ uci::MacAddressMode::Mode1 => unimplemented!(),
+ uci::MacAddressMode::Mode2 => {
+ MacAddress::Extended(value.try_into().unwrap())
+ }
+ })
+ .collect();
+ }
+ uci::AppConfigTlvType::SlotDuration => self.slot_duration = try_parse_u16(value)?,
+ uci::AppConfigTlvType::RangingDuration => self.ranging_duration = try_parse_u32(value)?,
+ uci::AppConfigTlvType::StsIndex => self.sts_index = try_parse_u32(value)?,
+ uci::AppConfigTlvType::MacFcsType => self.mac_fcs_type = try_parse(value)?,
+ uci::AppConfigTlvType::RangingRoundControl => {
+ self.ranging_round_control = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::AoaResultReq => self.aoa_result_req = try_parse(value)?,
+ uci::AppConfigTlvType::SessionInfoNtfConfig => {
+ self.session_info_ntf_config = try_parse(value)?
+ }
+ uci::AppConfigTlvType::NearProximityConfig => {
+ self.near_proximity_config = try_parse_u16(value)?
+ }
+ uci::AppConfigTlvType::FarProximityConfig => {
+ self.far_proximity_config = try_parse_u16(value)?
+ }
+ uci::AppConfigTlvType::DeviceRole => self.device_role = Some(try_parse(value)?),
+ uci::AppConfigTlvType::RframeConfig => self.rframe_config = try_parse(value)?,
+ uci::AppConfigTlvType::RssiReporting => self.rssi_reporting = try_parse(value)?,
+ uci::AppConfigTlvType::PreambleCodeIndex => {
+ self.preamble_code_index = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::SfdId => self.sfd_id = try_parse_u8(value)?,
+ uci::AppConfigTlvType::PsduDataRate => self.psdu_data_rate = try_parse(value)?,
+ uci::AppConfigTlvType::PreambleDuration => self.preamble_duration = try_parse(value)?,
+ uci::AppConfigTlvType::LinkLayerMode => self.link_layer_mode = try_parse(value)?,
+ uci::AppConfigTlvType::DataRepetitionCount => {
+ self.data_repetition_count = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::RangingTimeStruct => {
+ self.ranging_time_struct = try_parse(value)?
+ }
+ uci::AppConfigTlvType::SlotsPerRr => self.slots_per_rr = try_parse_u8(value)?,
+ uci::AppConfigTlvType::AoaBoundConfig => {
+ if value.len() != 8 {
+ log::error!(
+ "invalid aoa_bound_config len: expected 8, got {}",
+ value.len()
+ );
+ anyhow::bail!("invalid aoa_bound_config len")
+ }
+ self.aoa_bound_config = [
+ u16::from_le_bytes([value[0], value[1]]),
+ u16::from_le_bytes([value[2], value[3]]),
+ u16::from_le_bytes([value[4], value[5]]),
+ u16::from_le_bytes([value[6], value[7]]),
+ ]
+ }
+ uci::AppConfigTlvType::PrfMode => self.prf_mode = try_parse(value)?,
+ uci::AppConfigTlvType::CapSizeRange => self.cap_size_range = value.try_into()?,
+ uci::AppConfigTlvType::TxJitterWindowSize => {
+ self.tx_jitter_window_size = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::ScheduleMode => self.schedule_mode = Some(try_parse(value)?),
+ uci::AppConfigTlvType::KeyRotation => self.key_rotation = try_parse(value)?,
+ uci::AppConfigTlvType::KeyRotationRate => self.key_rotation_rate = try_parse_u8(value)?,
+ uci::AppConfigTlvType::SessionPriority => self.session_priority = try_parse_u8(value)?,
+ uci::AppConfigTlvType::MacAddressMode => self.mac_address_mode = try_parse(value)?,
+ uci::AppConfigTlvType::VendorId => self.vendor_id = try_parse_u16(value)?,
+ uci::AppConfigTlvType::StaticStsIv => self.static_sts_iv = value.try_into()?,
+ uci::AppConfigTlvType::NumberOfStsSegments => {
+ self.number_of_sts_segments = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::MaxRrRetry => self.max_rr_retry = try_parse_u16(value)?,
+ uci::AppConfigTlvType::UwbInitiationTime => {
+ // Implement backward compatiblity for UCI 1.0
+ // where the value is 4 bytes instead of 8.
+ self.uwb_initiation_time = match value.len() {
+ 4 => try_parse_u32(value)? as u64,
+ _ => try_parse_u64(value)?,
+ }
+ }
+ uci::AppConfigTlvType::HoppingMode => self.hopping_mode = try_parse(value)?,
+ uci::AppConfigTlvType::BlockStrideLength => {
+ self.block_stride_length = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::ResultReportConfig => {
+ self.result_report_config = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::InBandTerminationAttemptCount => {
+ self.in_band_termination_attempt_count = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::SubSessionId => self.sub_session_id = try_parse_u32(value)?,
+ uci::AppConfigTlvType::BprfPhrDataRate => self.bprf_phr_data_rate = try_parse(value)?,
+ uci::AppConfigTlvType::MaxNumberOfMeasurements => {
+ self.max_number_of_measurements = try_parse_u16(value)?
+ }
+ uci::AppConfigTlvType::StsLength => self.sts_length = try_parse(value)?,
+ uci::AppConfigTlvType::MinFramesPerRr => self.min_frames_per_rr = try_parse_u8(value)?,
+ uci::AppConfigTlvType::MtuSize => self.mtu_size = try_parse_u16(value)?,
+ uci::AppConfigTlvType::InterFrameInterval => {
+ self.inter_frame_interval = try_parse_u8(value)?
+ }
+ uci::AppConfigTlvType::SessionKey => self.session_key = value.to_vec(),
+ uci::AppConfigTlvType::SubSessionKey => self.sub_session_key = value.to_vec(),
+ uci::AppConfigTlvType::SessionDataTransferStatusNtfConfig => {
+ self.session_data_transfer_status_ntf_config = try_parse(value)?
+ }
+ uci::AppConfigTlvType::SessionTimeBase => self.session_time_base = value.try_into()?,
+ uci::AppConfigTlvType::ApplicationDataEndpoint => {
+ self.application_data_endpoint = try_parse_u8(value)?
+ }
+
+ uci::AppConfigTlvType::CccHopModeKey
+ | uci::AppConfigTlvType::CccUwbTime0
+ | uci::AppConfigTlvType::CccRangingProtocolVer
+ | uci::AppConfigTlvType::CccUwbConfigId
+ | uci::AppConfigTlvType::CccPulseshapeCombo
+ | uci::AppConfigTlvType::CccUrskTtl
+ | uci::AppConfigTlvType::CccLastIndexUsed
+ | uci::AppConfigTlvType::NbOfRangeMeasurements
+ | uci::AppConfigTlvType::NbOfAzimuthMeasurements
+ | uci::AppConfigTlvType::NbOfElevationMeasurements
+ | uci::AppConfigTlvType::EnableDiagnostics
+ | uci::AppConfigTlvType::DiagramsFrameReportsFields => {
+ log::error!("unsupported vendor config type {:?}", id);
+ anyhow::bail!("unsupported vendor config type {:?}", id)
+ }
+ _ => {
+ log::error!("unsupported app config type {:?}", id);
+ anyhow::bail!("unsupported app config type {:?}", id)
+ }
+ }
+ Ok(())
+ }
+
+ /// Retrieve the APP configuration value with the selected identifier
+ /// Returns `Ok` if the identifier is known, `Err` otherwise.
+ pub fn get(&self, id: uci::AppConfigTlvType) -> anyhow::Result<Vec<u8>> {
+ match id {
+ uci::AppConfigTlvType::DeviceType => Ok(vec![self
+ .device_type
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()]),
+ uci::AppConfigTlvType::RangingRoundUsage => Ok(vec![self
+ .ranging_round_usage
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()]),
+ uci::AppConfigTlvType::StsConfig => Ok(vec![self.sts_config.into()]),
+ uci::AppConfigTlvType::MultiNodeMode => Ok(vec![self
+ .multi_node_mode
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()]),
+ uci::AppConfigTlvType::ChannelNumber => Ok(vec![self.channel_number.into()]),
+ uci::AppConfigTlvType::NumberOfControlees => Ok(vec![self.number_of_controlees]),
+ uci::AppConfigTlvType::DeviceMacAddress => Ok(self
+ .device_mac_address
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()),
+ uci::AppConfigTlvType::DstMacAddress => Ok(self
+ .dst_mac_address
+ .iter()
+ .flat_map(Vec::<u8>::from)
+ .collect()),
+ uci::AppConfigTlvType::SlotDuration => Ok(self.slot_duration.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::RangingDuration => {
+ Ok(self.ranging_duration.to_le_bytes().to_vec())
+ }
+ uci::AppConfigTlvType::StsIndex => Ok(self.sts_index.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::MacFcsType => Ok(vec![self.mac_fcs_type.into()]),
+ uci::AppConfigTlvType::RangingRoundControl => Ok(vec![self.ranging_round_control]),
+ uci::AppConfigTlvType::AoaResultReq => Ok(vec![self.aoa_result_req.into()]),
+ uci::AppConfigTlvType::SessionInfoNtfConfig => {
+ Ok(vec![self.session_info_ntf_config.into()])
+ }
+ uci::AppConfigTlvType::NearProximityConfig => {
+ Ok(self.near_proximity_config.to_le_bytes().to_vec())
+ }
+ uci::AppConfigTlvType::FarProximityConfig => {
+ Ok(self.far_proximity_config.to_le_bytes().to_vec())
+ }
+ uci::AppConfigTlvType::DeviceRole => Ok(vec![self
+ .device_role
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()]),
+ uci::AppConfigTlvType::RframeConfig => Ok(vec![self.rframe_config.into()]),
+ uci::AppConfigTlvType::RssiReporting => Ok(vec![self.rssi_reporting.into()]),
+ uci::AppConfigTlvType::PreambleCodeIndex => Ok(vec![self.preamble_code_index]),
+ uci::AppConfigTlvType::SfdId => Ok(vec![self.sfd_id]),
+ uci::AppConfigTlvType::PsduDataRate => Ok(vec![self.psdu_data_rate.into()]),
+ uci::AppConfigTlvType::PreambleDuration => Ok(vec![self.preamble_duration.into()]),
+ uci::AppConfigTlvType::LinkLayerMode => Ok(vec![self.link_layer_mode.into()]),
+ uci::AppConfigTlvType::DataRepetitionCount => Ok(vec![self.data_repetition_count]),
+ uci::AppConfigTlvType::RangingTimeStruct => Ok(vec![self.ranging_time_struct.into()]),
+ uci::AppConfigTlvType::SlotsPerRr => Ok(vec![self.slots_per_rr]),
+ uci::AppConfigTlvType::AoaBoundConfig => Ok(self
+ .aoa_bound_config
+ .iter()
+ .copied()
+ .flat_map(u16::to_le_bytes)
+ .collect()),
+ uci::AppConfigTlvType::PrfMode => Ok(vec![self.prf_mode.into()]),
+ uci::AppConfigTlvType::CapSizeRange => Ok(self.cap_size_range.to_vec()),
+ uci::AppConfigTlvType::TxJitterWindowSize => Ok(vec![self.tx_jitter_window_size]),
+ uci::AppConfigTlvType::ScheduleMode => Ok(vec![self
+ .schedule_mode
+ .ok_or(anyhow::anyhow!("optional app config not set"))?
+ .into()]),
+ uci::AppConfigTlvType::KeyRotation => Ok(vec![self.key_rotation.into()]),
+ uci::AppConfigTlvType::KeyRotationRate => Ok(vec![self.key_rotation_rate]),
+ uci::AppConfigTlvType::SessionPriority => Ok(vec![self.session_priority]),
+ uci::AppConfigTlvType::MacAddressMode => Ok(vec![self.mac_address_mode.into()]),
+ uci::AppConfigTlvType::VendorId => Ok(self.vendor_id.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::StaticStsIv => Ok(self.static_sts_iv.to_vec()),
+ uci::AppConfigTlvType::NumberOfStsSegments => Ok(vec![self.number_of_sts_segments]),
+ uci::AppConfigTlvType::MaxRrRetry => Ok(self.max_rr_retry.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::UwbInitiationTime => {
+ Ok(self.uwb_initiation_time.to_le_bytes().to_vec())
+ }
+ uci::AppConfigTlvType::HoppingMode => Ok(vec![self.hopping_mode.into()]),
+ uci::AppConfigTlvType::BlockStrideLength => Ok(vec![self.block_stride_length]),
+ uci::AppConfigTlvType::ResultReportConfig => Ok(vec![self.result_report_config]),
+ uci::AppConfigTlvType::InBandTerminationAttemptCount => {
+ Ok(vec![self.in_band_termination_attempt_count])
+ }
+ uci::AppConfigTlvType::SubSessionId => Ok(self.sub_session_id.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::BprfPhrDataRate => Ok(vec![self.bprf_phr_data_rate.into()]),
+ uci::AppConfigTlvType::MaxNumberOfMeasurements => {
+ Ok(self.max_number_of_measurements.to_le_bytes().to_vec())
+ }
+ uci::AppConfigTlvType::StsLength => Ok(vec![self.sts_length.into()]),
+ uci::AppConfigTlvType::MinFramesPerRr => Ok(vec![self.min_frames_per_rr]),
+ uci::AppConfigTlvType::MtuSize => Ok(self.mtu_size.to_le_bytes().to_vec()),
+ uci::AppConfigTlvType::InterFrameInterval => Ok(vec![self.inter_frame_interval]),
+ uci::AppConfigTlvType::SessionKey => Ok(self.session_key.clone()),
+ uci::AppConfigTlvType::SubSessionKey => Ok(self.sub_session_key.clone()),
+ uci::AppConfigTlvType::SessionDataTransferStatusNtfConfig => {
+ Ok(vec![self.session_data_transfer_status_ntf_config.into()])
+ }
+ uci::AppConfigTlvType::SessionTimeBase => Ok(self.session_time_base.to_vec()),
+ uci::AppConfigTlvType::ApplicationDataEndpoint => {
+ Ok(vec![self.application_data_endpoint])
+ }
+
+ uci::AppConfigTlvType::CccHopModeKey
+ | uci::AppConfigTlvType::CccUwbTime0
+ | uci::AppConfigTlvType::CccRangingProtocolVer
+ | uci::AppConfigTlvType::CccUwbConfigId
+ | uci::AppConfigTlvType::CccPulseshapeCombo
+ | uci::AppConfigTlvType::CccUrskTtl
+ | uci::AppConfigTlvType::CccLastIndexUsed
+ | uci::AppConfigTlvType::NbOfRangeMeasurements
+ | uci::AppConfigTlvType::NbOfAzimuthMeasurements
+ | uci::AppConfigTlvType::NbOfElevationMeasurements
+ | uci::AppConfigTlvType::EnableDiagnostics
+ | uci::AppConfigTlvType::DiagramsFrameReportsFields => {
+ log::error!("unsupported vendor config type {:?}", id);
+ anyhow::bail!("unsupported vendor config type {:?}", id)
+ }
+ _ => {
+ log::error!("unsupported app config type {:?}", id);
+ anyhow::bail!("unsupported app config type {:?}", id)
+ }
+ }
+ }
+
+ pub fn is_compatible_for_ranging(&self, peer_config: &Self) -> bool {
+ self.device_role != peer_config.device_role
+ && self.device_type != peer_config.device_type
+ && peer_config
+ .dst_mac_address
+ .contains(&self.device_mac_address.unwrap())
+ && self
+ .dst_mac_address
+ .contains(&peer_config.device_mac_address.unwrap())
+ }
+
+ pub fn can_start_data_transfer(&self) -> bool {
+ self.device_role == Some(uci::DeviceRole::Initiator)
+ }
+
+ pub fn can_receive_data_transfer(&self) -> bool {
+ self.device_role == Some(uci::DeviceRole::Responder)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index bd154f7..25a09d0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,7 +36,8 @@ use session::MAX_SESSION;
mod mac_address;
pub use mac_address::MacAddress;
-use crate::session::RangeDataNtfConfig;
+mod app_config;
+pub use app_config::AppConfig;
pub type UciPacket = Vec<u8>;
pub type UciStream = Pin<Box<dyn futures::stream::Stream<Item = Vec<u8>> + Send>>;
@@ -412,7 +413,7 @@ impl Pica {
let mut measurements = Vec::new();
// Look for compatible anchors.
- for mac_address in session.get_dst_mac_addresses() {
+ for mac_address in session.get_dst_mac_address() {
if let Some(other) = self.anchors.get(mac_address) {
let local = self
.ranging_estimator
@@ -437,7 +438,8 @@ impl Pica {
.session(session_id)
.unwrap()
.app_config
- .device_mac_address;
+ .device_mac_address
+ .unwrap();
let local = self
.ranging_estimator
.estimate(&device.handle, &peer_device.handle)
@@ -475,7 +477,7 @@ impl Pica {
)
.unwrap();
}
- if session.is_ranging_data_ntf_enabled() != RangeDataNtfConfig::Disable {
+ if session.is_session_info_ntf_enabled() {
device
.tx
.send(
@@ -554,7 +556,7 @@ impl Pica {
continue;
};
- if &session.app_config.device_mac_address != mac_address {
+ if session.app_config.device_mac_address != Some(*mac_address) {
continue;
}
diff --git a/src/mac_address.rs b/src/mac_address.rs
index 79cfe94..6b67e7e 100644
--- a/src/mac_address.rs
+++ b/src/mac_address.rs
@@ -52,6 +52,21 @@ impl From<MacAddress> for u64 {
}
}
+impl From<&MacAddress> for Vec<u8> {
+ fn from(mac_address: &MacAddress) -> Self {
+ match mac_address {
+ MacAddress::Short(addr) => addr.to_vec(),
+ MacAddress::Extended(addr) => addr.to_vec(),
+ }
+ }
+}
+
+impl From<MacAddress> for Vec<u8> {
+ fn from(mac_address: MacAddress) -> Self {
+ Vec::<u8>::from(&mac_address)
+ }
+}
+
impl TryFrom<String> for MacAddress {
type Error = Error;
fn try_from(mac_address: String) -> std::result::Result<Self, Error> {
diff --git a/src/session.rs b/src/session.rs
index bbd23bb..dc0ed30 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -17,674 +17,25 @@
//! - [UCI] FiRa Consortium UWB Command Interface Generic Technical specification
use crate::packets::uci::{self, *};
-use crate::{MacAddress, PicaCommand};
+use crate::{AppConfig, MacAddress, PicaCommand};
use bytes::BytesMut;
-use std::collections::HashMap;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use tokio::time;
-use num_derive::{FromPrimitive, ToPrimitive};
-use num_traits::FromPrimitive;
-
use super::UciPacket;
pub const MAX_SESSION: usize = 255;
-pub const DEFAULT_RANGING_INTERVAL: Duration = time::Duration::from_millis(200);
-pub const DEFAULT_SLOT_DURATION: u16 = 2400; // RTSU unit
/// cf. [UCI] 8.3 Table 29
pub const MAX_NUMBER_OF_CONTROLEES: usize = 8;
-pub const FIRA_1_1_INITIATION_TIME_SIZE: usize = 4;
-pub const FIRA_2_0_INITIATION_TIME_SIZE: usize = 8;
-
-#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq)]
-pub enum DeviceType {
- /// [MAC] 5.1.2 Device utilizing the ranging features set through Control Messages
- Controlee = 0x00,
- /// [MAC] 5.1.1 Device controlling the ranging features through Control Messages
- Controller = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq)]
-pub enum DeviceRole {
- /// [MAC] 5.1.3 Device initiating a ranging exchange with a ranging initiation message
- Initiator,
- /// [MAC] 5.1.4 Device responding to ranging initiation messages
- Responder,
-}
-
-/// cf. [UCI] 8.4 Table 29
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq, Eq)]
-#[repr(u8)]
-pub enum MacAddressMode {
- /// MAC address is 2 bytes and 2 bytes to be used in MAC header
- AddressMode0 = 0x00,
- /// Not Supported: MAC address is 8 bytes and 2 bytes to be used in MAC header
- AddressMode1 = 0x01,
- /// MAC address is 8 bytes and 8 bytes to be used in MAC header
- AddressMode2 = 0x02,
-}
-
-/// cf. [UCI] 8.3 Table 29
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq, Eq)]
-#[repr(u8)]
-pub enum ChannelNumber {
- ChannelNumber5 = 0x05,
- ChannelNumber6 = 0x06,
- ChannelNumber8 = 0x08,
- ChannelNumber9 = 0x09,
- ChannelNumber10 = 0x0a,
- ChannelNumber12 = 0x0c,
- ChannelNumber13 = 0x0d,
- ChannelNumber14 = 0x0e,
-}
-
-const DEFAULT_CHANNEL_NUMBER: ChannelNumber = ChannelNumber::ChannelNumber9;
-
-/// cf. [UCI] 8.3 Table 29
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum MultiNodeMode {
- /// Single device to single device
- Unicast = 0x00,
- OneToMany = 0x01,
- ManyToMany = 0x02,
-}
-
-/// cf. [UCI] 7.7
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum UpdateMulticastListAction {
- Add = 0x00,
- Delete = 0x01,
- AddWithShortSubSessionKey = 0x02,
- AddwithExtendedSubSessionKey = 0x03,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum RangingRoundUsage {
- UlTdoa = 0x00,
- SsTwrDeferredMode = 0x01,
- DsTwrDeferredMode = 0x02,
- SsTwrNonDeferredMode = 0x03,
- DsTwrNonDeferredMode = 0x04,
- DlTdoa = 0x05,
- OwrAoaMeasurement = 0x06,
- DataTransferMode = 0x09,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum StsConfig {
- Static = 0x00,
- Dynamic = 0x01,
- DynamicForControleeIndividualKey = 0x02,
- Provisioned = 0x03,
- ProvisionedForControleeIndividualKey = 0x04,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum MacFcsType {
- MacFcsTypeCrc16 = 0x00,
- MacFcsTypeCrc32 = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum AoaResultReq {
- NoAoaResult = 0x00,
- ReqAoaResults = 0x01,
- ReqAoaResultsAzimuthOnly = 0x02,
- ReqAoaResultsElevationOnly = 0x03,
- ReqAoaResultsInterleaved = 0x04,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum RframeConfig {
- Sp0 = 0x00,
- Sp1 = 0x01,
- Sp3 = 0x03,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum PsduDataRate {
- Rate6M81 = 0x00,
- Rate7M80 = 0x01,
- Rate27M2 = 0x02,
- Rate31M2 = 0x03,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum PreambleDuration {
- PreambleDurationT32Symbols = 0x00,
- PreambleDurationT64Symbols = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum RangingTimeStruct {
- IntervalBasedScheduling = 0x00,
- BlockBasedScheduling = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum PrfMode {
- PrfModeBprf = 0x00,
- PrfModeHprf = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum SchedulingMode {
- ContentionBased = 0x00,
- TimeScheduled = 0x01,
- HybridScheduled = 0x02,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum HoppingMode {
- Disable = 0x00,
- FiraEnable = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum StsLength {
- StsLength32 = 0x00,
- StsLength64 = 0x01,
- StsLength128 = 0x02,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum BprfPhrDataRate {
- BprfPhrDataRate850K = 0x00,
- BprfPhrDataRate6M81 = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum SfdIdValue {
- SfdIdValue0 = 0x00,
- SfdIdValue1 = 0x01,
- SfdIdValue2 = 0x02,
- SfdIdValue3 = 0x03,
- SfdIdValue4 = 0x04,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-enum StsSegmentCountValue {
- StsSegmentCountValue0 = 0x00,
- StsSegmentCountValue1 = 0x01,
- StsSegmentCountValue2 = 0x02,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-pub enum RangeDataNtfConfig {
- Disable = 0x00,
- Enable = 0x01,
- EnableProximityLevelTrig = 0x02,
- EnableAoaLevelTrig = 0x03,
- EnableProximityAoaLevelTrig = 0x04,
- EnableProximityEdgeTrig = 0x05,
- EnableAoaEdgeTrig = 0x06,
- EnableProximityAoaEdgeTrig = 0x07,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-pub enum LinkLayerMode {
- Bypass = 0x00,
- Assigned = 0x01,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-pub enum DataRepetitionCount {
- NoRepetition = 0x00,
- Infinite = 0xFF,
-}
-
-#[derive(Copy, Clone, FromPrimitive, ToPrimitive, PartialEq)]
-#[repr(u8)]
-pub enum SessionDataTransferStatusNtfConfig {
- Disable = 0x00,
- Enable = 0x01,
-}
-/// cf. [UCI] 8.3 Table 29
-#[derive(Clone)]
-pub struct AppConfig {
- /// Copy of the valid App Configuration parameters provided by host
- raw: HashMap<AppConfigTlvType, Vec<u8>>,
-
- device_type: DeviceType,
- device_role: DeviceRole,
- mac_address_mode: MacAddressMode,
- pub device_mac_address: MacAddress,
- number_of_controlees: usize,
- dst_mac_addresses: Vec<MacAddress>,
- ranging_interval: time::Duration,
- slot_duration: u16,
- channel_number: ChannelNumber,
- multi_node_mode: MultiNodeMode,
- ranging_round_usage: RangingRoundUsage,
- sts_config: StsConfig,
- mac_fcs_type: MacFcsType,
- ranging_round_control: u8,
- aoa_result_req: AoaResultReq,
- rng_data_ntf: RangeDataNtfConfig,
- rng_data_ntf_proximity_near: u16,
- rng_data_ntf_proximity_far: u16,
- r_frame_config: RframeConfig,
- rssi_reporting: bool,
- preamble_code_index: u8,
- sfd_id: SfdIdValue,
- psdu_data_rate: PsduDataRate,
- preamble_duration: PreambleDuration,
- ranging_time_struct: RangingTimeStruct,
- slots_per_rr: u8,
- tx_adaptive_payload_power: bool,
- prf_mode: PrfMode,
- schedule_mode: SchedulingMode,
- key_rotation: bool,
- key_rotation_rate: u8,
- session_priority: u8,
- number_of_sts_segments: StsSegmentCountValue,
- max_rr_retry: u16,
- hopping_mode: HoppingMode,
- block_stride_length: u8,
- result_report_config: bool,
- in_band_termination_attempt_count: u8,
- bprf_phr_data_rate: BprfPhrDataRate,
- max_number_of_measurements: u8,
- sts_length: StsLength,
- uwb_initiation_time: u64,
- vendor_id: Option<Vec<u8>>,
- static_sts_iv: Option<Vec<u8>>,
- session_key: Option<Vec<u8>>,
- sub_session_key: Option<Vec<u8>>,
- sub_session_id: u32,
- link_layer_mode: LinkLayerMode,
- data_repetition_count: DataRepetitionCount,
- session_data_transfer_status_ntf_config: SessionDataTransferStatusNtfConfig,
- application_data_endpoint: u8,
-}
-
-impl Default for AppConfig {
- fn default() -> Self {
- AppConfig {
- raw: HashMap::new(),
- mac_address_mode: MacAddressMode::AddressMode0,
- device_role: DeviceRole::Responder,
- device_type: DeviceType::Controlee,
- ranging_interval: DEFAULT_RANGING_INTERVAL,
- slot_duration: DEFAULT_SLOT_DURATION,
- channel_number: DEFAULT_CHANNEL_NUMBER,
- device_mac_address: MacAddress::Short([0x00, 0x00]),
- number_of_controlees: 0,
- dst_mac_addresses: Vec::new(),
- multi_node_mode: MultiNodeMode::Unicast,
- ranging_round_usage: RangingRoundUsage::DsTwrDeferredMode,
- sts_config: StsConfig::Static,
- mac_fcs_type: MacFcsType::MacFcsTypeCrc16,
- ranging_round_control: 6_u8,
- aoa_result_req: AoaResultReq::ReqAoaResults,
- rng_data_ntf: RangeDataNtfConfig::Enable,
- rng_data_ntf_proximity_near: 0,
- rng_data_ntf_proximity_far: 0,
- r_frame_config: RframeConfig::Sp3,
- rssi_reporting: false,
- preamble_code_index: 10,
- sfd_id: SfdIdValue::SfdIdValue2,
- psdu_data_rate: PsduDataRate::Rate6M81,
- preamble_duration: PreambleDuration::PreambleDurationT64Symbols,
- ranging_time_struct: RangingTimeStruct::IntervalBasedScheduling,
- slots_per_rr: 25,
- tx_adaptive_payload_power: false,
- prf_mode: PrfMode::PrfModeBprf,
- schedule_mode: SchedulingMode::TimeScheduled,
- key_rotation: false,
- key_rotation_rate: 0,
- session_priority: 50,
- number_of_sts_segments: StsSegmentCountValue::StsSegmentCountValue1,
- max_rr_retry: 0,
- hopping_mode: HoppingMode::Disable,
- block_stride_length: 0,
- result_report_config: true,
- in_band_termination_attempt_count: 1,
- bprf_phr_data_rate: BprfPhrDataRate::BprfPhrDataRate850K,
- max_number_of_measurements: 0,
- sts_length: StsLength::StsLength64,
- uwb_initiation_time: 0,
- vendor_id: None,
- static_sts_iv: None,
- session_key: None,
- sub_session_key: None,
- sub_session_id: 0,
- link_layer_mode: LinkLayerMode::Bypass,
- data_repetition_count: DataRepetitionCount::NoRepetition,
- session_data_transfer_status_ntf_config: SessionDataTransferStatusNtfConfig::Disable,
- application_data_endpoint: 0,
- }
- }
-}
-
-impl PartialEq for AppConfig {
- fn eq(&self, other: &Self) -> bool {
- self.mac_address_mode == other.mac_address_mode
- && self.ranging_interval == other.ranging_interval
- && self.slot_duration == other.slot_duration
- && self.channel_number == other.channel_number
- && self.multi_node_mode == other.multi_node_mode
- && self.ranging_round_usage == other.ranging_round_usage
- && self.sts_config == other.sts_config
- && self.mac_fcs_type == other.mac_fcs_type
- && self.ranging_round_control == other.ranging_round_control
- && self.aoa_result_req == other.aoa_result_req
- && self.rng_data_ntf == other.rng_data_ntf
- && self.rng_data_ntf_proximity_near == other.rng_data_ntf_proximity_near
- && self.rng_data_ntf_proximity_far == other.rng_data_ntf_proximity_far
- && self.r_frame_config == other.r_frame_config
- && self.rssi_reporting == other.rssi_reporting
- && self.preamble_code_index == other.preamble_code_index
- && self.sfd_id == other.sfd_id
- && self.psdu_data_rate == other.psdu_data_rate
- && self.preamble_duration == other.preamble_duration
- && self.ranging_time_struct == other.ranging_time_struct
- && self.slots_per_rr == other.slots_per_rr
- && self.tx_adaptive_payload_power == other.tx_adaptive_payload_power
- && self.prf_mode == other.prf_mode
- && self.schedule_mode == other.schedule_mode
- && self.key_rotation == other.key_rotation
- && self.key_rotation_rate == other.key_rotation_rate
- && self.session_priority == other.session_priority
- && self.number_of_sts_segments == other.number_of_sts_segments
- && self.max_rr_retry == other.max_rr_retry
- && self.result_report_config == other.result_report_config
- && self.bprf_phr_data_rate == other.bprf_phr_data_rate
- && self.max_number_of_measurements == other.max_number_of_measurements
- && self.sts_length == other.sts_length
- && self.uwb_initiation_time == other.uwb_initiation_time
- && self.vendor_id == other.vendor_id
- && self.static_sts_iv == other.static_sts_iv
- }
-}
-
-fn app_config_has_mandatory_parameters(configs: &[AppConfigTlv]) -> bool {
- const MANDATORY_PARAMETERS: [AppConfigTlvType; 6] = [
- AppConfigTlvType::DeviceRole,
- AppConfigTlvType::MultiNodeMode,
- AppConfigTlvType::NoOfControlee,
- AppConfigTlvType::DeviceMacAddress,
- AppConfigTlvType::DstMacAddress,
- AppConfigTlvType::DeviceType,
- ];
-
- MANDATORY_PARAMETERS
- .iter()
- .all(|&mparam| configs.iter().any(|param| mparam == param.cfg_id))
-}
-
-impl AppConfig {
- fn set_config(
- &mut self,
- id: AppConfigTlvType,
- value: &[u8],
- ) -> std::result::Result<(), StatusCode> {
- match id {
- AppConfigTlvType::MacAddressMode => {
- let mode = MacAddressMode::from_u8(value[0]).unwrap();
- if mode == MacAddressMode::AddressMode1 {
- return Err(StatusCode::UciStatusInvalidParam);
- }
- self.mac_address_mode = mode;
- }
- AppConfigTlvType::RangingDuration => {
- let interval = u32::from_le_bytes(value[..].try_into().unwrap());
- self.ranging_interval = time::Duration::from_millis(interval as u64)
- }
- AppConfigTlvType::SlotDuration => {
- self.slot_duration = u16::from_le_bytes(value[..].try_into().unwrap())
- }
- AppConfigTlvType::ChannelNumber => {
- self.channel_number = ChannelNumber::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::DeviceMacAddress => {
- self.device_mac_address = match self.mac_address_mode {
- MacAddressMode::AddressMode0 => {
- MacAddress::Short(value[..].try_into().unwrap())
- }
- MacAddressMode::AddressMode2 => {
- MacAddress::Extended(value[..].try_into().unwrap())
- }
- _ => panic!("Unexpected MAC Address Mode"),
- };
- }
- AppConfigTlvType::NoOfControlee => {
- assert!(value[0] as usize <= MAX_NUMBER_OF_CONTROLEES);
- self.number_of_controlees = value[0] as usize;
- }
- AppConfigTlvType::DstMacAddress => {
- let mac_address_size = match self.mac_address_mode {
- MacAddressMode::AddressMode0 => 2,
- MacAddressMode::AddressMode2 => 8,
- _ => panic!("Unexpected MAC Address Mode"),
- };
- if value.len() % mac_address_size != 0
- || (value.len() / mac_address_size) != self.number_of_controlees
- {
- return Err(StatusCode::UciStatusInvalidParam);
- }
- self.dst_mac_addresses = value
- .chunks(mac_address_size)
- .map(|c| match self.mac_address_mode {
- MacAddressMode::AddressMode0 => MacAddress::Short(c.try_into().unwrap()),
- MacAddressMode::AddressMode2 => MacAddress::Extended(c.try_into().unwrap()),
- _ => panic!("Unexpected MAC Address Mode"),
- })
- .collect();
- assert_eq!(self.dst_mac_addresses.len(), self.number_of_controlees);
- }
- AppConfigTlvType::MultiNodeMode => {
- self.multi_node_mode = MultiNodeMode::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::DeviceType => {
- self.device_type = DeviceType::from_u8(value[0]).unwrap();
- }
- AppConfigTlvType::RangingRoundUsage => {
- self.ranging_round_usage = RangingRoundUsage::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::StsConfig => self.sts_config = StsConfig::from_u8(value[0]).unwrap(),
- AppConfigTlvType::MacFcsType => {
- self.mac_fcs_type = MacFcsType::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::RangingRoundControl => self.ranging_round_control = value[0],
- AppConfigTlvType::AoaResultReq => {
- self.aoa_result_req = AoaResultReq::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::RngDataNtf => {
- self.rng_data_ntf = RangeDataNtfConfig::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::RngDataNtfProximityNear => {
- self.rng_data_ntf_proximity_near = u16::from_le_bytes(value[..].try_into().unwrap())
- }
- AppConfigTlvType::RngDataNtfProximityFar => {
- self.rng_data_ntf_proximity_far = u16::from_le_bytes(value[..].try_into().unwrap())
- }
- AppConfigTlvType::DeviceRole => {
- self.device_role = DeviceRole::from_u8(value[0]).unwrap();
- }
- AppConfigTlvType::RframeConfig => {
- self.r_frame_config = RframeConfig::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::RssiReporting => {
- self.rssi_reporting = match value[0] {
- 0 => false,
- 1 => true,
- _ => panic!("Invalid rssi reporting value!"),
- }
- }
- AppConfigTlvType::PreambleCodeIndex => self.preamble_code_index = value[0],
- AppConfigTlvType::SfdId => self.sfd_id = SfdIdValue::from_u8(value[0]).unwrap(),
- AppConfigTlvType::PsduDataRate => {
- self.psdu_data_rate = PsduDataRate::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::PreambleDuration => {
- self.preamble_duration = PreambleDuration::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::RangingTimeStruct => {
- self.ranging_time_struct = RangingTimeStruct::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::SlotsPerRr => self.slots_per_rr = value[0],
- AppConfigTlvType::TxAdaptivePayloadPower => {
- self.tx_adaptive_payload_power = match value[0] {
- 0 => false,
- 1 => true,
- _ => panic!("Invalid tx adaptive payload power value!"),
- }
- }
- AppConfigTlvType::PrfMode => self.prf_mode = PrfMode::from_u8(value[0]).unwrap(),
- AppConfigTlvType::ScheduledMode => {
- self.schedule_mode = SchedulingMode::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::KeyRotation => {
- self.key_rotation = match value[0] {
- 0 => false,
- 1 => true,
- _ => panic!("Invalid key rotation value!"),
- }
- }
- AppConfigTlvType::KeyRotationRate => self.key_rotation_rate = value[0],
- AppConfigTlvType::SessionPriority => self.session_priority = value[0],
- AppConfigTlvType::VendorId => {
- self.vendor_id = Some(value.to_vec());
- }
- AppConfigTlvType::StaticStsIv => {
- self.static_sts_iv = Some(value.to_vec());
- }
- AppConfigTlvType::NumberOfStsSegments => {
- self.number_of_sts_segments = StsSegmentCountValue::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::MaxRrRetry => {
- self.max_rr_retry = u16::from_le_bytes(value[..].try_into().unwrap())
- }
- AppConfigTlvType::UwbInitiationTime => {
- self.uwb_initiation_time = match value.len() {
- // Backward compatible with Fira 1.1 Version UCI host.
- FIRA_1_1_INITIATION_TIME_SIZE => {
- u32::from_le_bytes(value[..].try_into().unwrap()) as u64
- }
- FIRA_2_0_INITIATION_TIME_SIZE => {
- u64::from_le_bytes(value[..].try_into().unwrap())
- }
- _ => panic!("Invalid initiation time!"),
- }
- }
- AppConfigTlvType::HoppingMode => {
- self.hopping_mode = HoppingMode::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::BlockStrideLength => self.block_stride_length = value[0],
- AppConfigTlvType::ResultReportConfig => {
- self.result_report_config = match value[0] {
- 0 => false,
- 1 => true,
- _ => panic!("Invalid result report config value!"),
- }
- }
- AppConfigTlvType::BprfPhrDataRate => {
- self.bprf_phr_data_rate = BprfPhrDataRate::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::MaxNumberOfMeasurements => self.max_number_of_measurements = value[0],
- AppConfigTlvType::StsLength => self.sts_length = StsLength::from_u8(value[0]).unwrap(),
- AppConfigTlvType::InBandTerminationAttemptCount => {
- self.in_band_termination_attempt_count = value[0]
- }
- AppConfigTlvType::SessionKey => self.session_key = Some(value.to_vec()),
- AppConfigTlvType::SubSessionId => {
- self.sub_session_id = u32::from_le_bytes(value[..].try_into().unwrap())
- }
- AppConfigTlvType::SubsessionKey => self.sub_session_key = Some(value.to_vec()),
- AppConfigTlvType::LinkLayerMode => {
- self.link_layer_mode = LinkLayerMode::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::DataRepetitionCount => {
- self.data_repetition_count = DataRepetitionCount::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::SessionDataTransferStatusNtfConfig => {
- self.session_data_transfer_status_ntf_config =
- SessionDataTransferStatusNtfConfig::from_u8(value[0]).unwrap()
- }
- AppConfigTlvType::ApplicationDataEndpoint => self.application_data_endpoint = value[0],
- id => {
- log::error!("Ignored AppConfig parameter {:?}", id);
- return Err(StatusCode::UciStatusInvalidParam);
- }
- };
-
- self.raw.insert(id, value.to_vec());
-
- Ok(())
- }
-
- fn get_config(&self, id: AppConfigTlvType) -> Option<Vec<u8>> {
- self.raw.get(&id).cloned()
- }
-
- pub fn is_compatible_for_ranging(&self, peer_config: &Self) -> bool {
- self == peer_config
- && self.device_role != peer_config.device_role
- && self.device_type != peer_config.device_type
- && peer_config
- .dst_mac_addresses
- .contains(&self.device_mac_address)
- && self
- .dst_mac_addresses
- .contains(&peer_config.device_mac_address)
- }
-
- pub fn can_start_data_transfer(&self) -> bool {
- self.device_role == DeviceRole::Initiator
- }
-
- pub fn can_receive_data_transfer(&self) -> bool {
- self.device_role == DeviceRole::Responder
- }
-
- fn extend(&mut self, configs: &[AppConfigTlv]) -> Vec<AppConfigStatus> {
- if !app_config_has_mandatory_parameters(configs) {
- // TODO: What shall we do in this situation?
- }
-
- configs
- .iter()
- .fold(Vec::new(), |mut invalid_parameters, config| {
- match self.set_config(config.cfg_id, &config.v) {
- Ok(_) => (),
- Err(status) => invalid_parameters.push(AppConfigStatus {
- cfg_id: config.cfg_id,
- status,
- }),
- };
- invalid_parameters
- })
- }
-}
enum SubSessionKey {
None,
Short([u8; 16]),
Extended([u8; 32]),
}
+
struct Controlee {
short_address: MacAddress,
sub_session_id: u32,
@@ -785,12 +136,18 @@ impl Session {
});
}
- pub fn get_dst_mac_addresses(&self) -> &Vec<MacAddress> {
- &self.app_config.dst_mac_addresses
+ pub fn get_dst_mac_address(&self) -> &[MacAddress] {
+ &self.app_config.dst_mac_address
+ }
+
+ pub fn is_session_info_ntf_enabled(&self) -> bool {
+ self.app_config.session_info_ntf_config != uci::SessionInfoNtfConfig::Disable
}
- pub fn is_ranging_data_ntf_enabled(&self) -> RangeDataNtfConfig {
- self.app_config.rng_data_ntf
+ #[allow(unused)]
+ pub fn is_session_data_transfer_status_ntf_enabled(&self) -> bool {
+ self.app_config.session_data_transfer_status_ntf_config
+ != uci::SessionDataTransferStatusNtfConfig::Disable
}
pub fn data(&self) -> &BytesMut {
@@ -852,7 +209,47 @@ impl Session {
(StatusCode::UciStatusRejected, Vec::new())
} else {
let mut app_config = self.app_config.clone();
- let invalid_parameters = app_config.extend(cmd.get_tlvs());
+ let mut invalid_parameters = vec![];
+ for cfg in cmd.get_tlvs() {
+ match app_config.set(cfg.cfg_id, &cfg.v) {
+ Ok(_) => (),
+ Err(_) => invalid_parameters.push(AppConfigStatus {
+ cfg_id: cfg.cfg_id,
+ status: uci::StatusCode::UciStatusInvalidParam,
+ }),
+ }
+ }
+
+ // [UCI] 7.5.1 Configuration of a Session
+ // This section defines the mandatory APP Configuration Parameters to be applied
+ // by the Host for FiRa defined UWB Session types. The Host shall apply these
+ // mandatory configurations to move the Session State from SESSION_STATE_INIT
+ // to SESSION_STATE_IDLE.
+ //
+ // - DEVICE_ROLE
+ // - MULTI_NODE_MODE
+ // - RANGING_ROUND_USAGE
+ // - DEVICE_MAC_ADDRESS
+ // - DEVICE_TYPE (see Note1)
+ // - SCHEDULE_MODE
+ if app_config.device_role.is_none()
+ || app_config.multi_node_mode.is_none()
+ || app_config.ranging_round_usage.is_none()
+ || app_config.device_mac_address.is_none()
+ || app_config.schedule_mode.is_none()
+ {
+ log::error!(
+ "[{}:0x{:x}] missing mandatory APP config parameters",
+ self.device_handle,
+ self.id
+ );
+ return SessionSetAppConfigRspBuilder {
+ status: uci::StatusCode::UciStatusRejected,
+ cfg_status: vec![],
+ }
+ .build();
+ }
+
if invalid_parameters.is_empty() {
self.app_config = app_config;
if self.state == SessionState::SessionStateInit {
@@ -883,25 +280,21 @@ impl Session {
assert_eq!(self.id, cmd.get_session_token());
let (status, valid_parameters) = {
- let (valid_parameters, invalid_parameters) = cmd.get_app_cfg().iter().fold(
- (Vec::new(), Vec::new()),
- |(mut valid_parameters, mut invalid_parameters), config_id| {
- match AppConfigTlvType::try_from(*config_id) {
- Ok(id) => match self.app_config.get_config(id) {
- Some(value) => valid_parameters.push(AppConfigTlv {
- cfg_id: id,
- v: value,
- }),
- None => invalid_parameters.push(AppConfigTlv {
- cfg_id: id,
- v: Vec::new(),
- }),
- },
- Err(_) => log::error!("Failed to parse AppConfigTlv: {:?}", *config_id),
- }
- (valid_parameters, invalid_parameters)
- },
- );
+ let mut valid_parameters = vec![];
+ let mut invalid_parameters = vec![];
+ for id in cmd.get_app_cfg() {
+ match self.app_config.get(*id) {
+ Ok(value) => valid_parameters.push(AppConfigTlv {
+ cfg_id: *id,
+ v: value,
+ }),
+ Err(_) => invalid_parameters.push(AppConfigTlv {
+ cfg_id: *id,
+ v: vec![],
+ }),
+ }
+ }
+
if invalid_parameters.is_empty() {
(StatusCode::UciStatusOk, valid_parameters)
} else {
@@ -937,19 +330,19 @@ impl Session {
assert_eq!(self.id, cmd.get_session_token());
if (self.state != SessionState::SessionStateActive
&& self.state != SessionState::SessionStateIdle)
- || self.app_config.device_type != DeviceType::Controller
- || (self.app_config.multi_node_mode != MultiNodeMode::OneToMany
- && self.app_config.multi_node_mode != MultiNodeMode::ManyToMany)
+ || self.app_config.device_type != Some(DeviceType::Controller)
+ || self.app_config.multi_node_mode != Some(MultiNodeMode::OneToMany)
{
return SessionUpdateControllerMulticastListRspBuilder {
status: StatusCode::UciStatusRejected,
}
.build();
}
- let action = UpdateMulticastListAction::from_u8(cmd.get_action().into()).unwrap();
- let mut dst_addresses = self.app_config.dst_mac_addresses.clone();
+ let action = cmd.get_action();
+ let mut dst_addresses = self.app_config.dst_mac_address.clone();
let new_controlees: Vec<Controlee> = match action {
- UpdateMulticastListAction::Add | UpdateMulticastListAction::Delete => {
+ UpdateMulticastListAction::AddControlee
+ | UpdateMulticastListAction::RemoveControlee => {
if let Ok(packet) =
SessionUpdateControllerMulticastListCmdPayload::parse(cmd.get_payload())
{
@@ -965,7 +358,7 @@ impl Session {
.build();
}
}
- UpdateMulticastListAction::AddWithShortSubSessionKey => {
+ UpdateMulticastListAction::AddControleeWithShortSubSessionKey => {
if let Ok(packet) =
SessionUpdateControllerMulticastListCmd_2_0_16_Byte_Payload::parse(
cmd.get_payload(),
@@ -983,7 +376,7 @@ impl Session {
.build();
}
}
- UpdateMulticastListAction::AddwithExtendedSubSessionKey => {
+ UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey => {
if let Ok(packet) =
SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload::parse(
cmd.get_payload(),
@@ -1008,19 +401,21 @@ impl Session {
let mut status = StatusCode::UciStatusOk;
match action {
- UpdateMulticastListAction::Add
- | UpdateMulticastListAction::AddWithShortSubSessionKey
- | UpdateMulticastListAction::AddwithExtendedSubSessionKey => {
+ UpdateMulticastListAction::AddControlee
+ | UpdateMulticastListAction::AddControleeWithShortSubSessionKey
+ | UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey => {
new_controlees.iter().for_each(|controlee| {
let mut update_status = MulticastUpdateStatusCode::StatusOkMulticastListUpdate;
if !dst_addresses.contains(&controlee.short_address) {
if dst_addresses.len() == MAX_NUMBER_OF_CONTROLEES {
status = StatusCode::UciStatusMulticastListFull;
update_status = MulticastUpdateStatusCode::StatusErrorMulticastListFull;
- } else if (action == UpdateMulticastListAction::AddWithShortSubSessionKey
- || action == UpdateMulticastListAction::AddwithExtendedSubSessionKey)
+ } else if (action
+ == UpdateMulticastListAction::AddControleeWithShortSubSessionKey
+ || action
+ == UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey)
&& self.app_config.sts_config
- != StsConfig::ProvisionedForControleeIndividualKey
+ != uci::StsConfig::ProvisionedForResponderSubSessionKey
{
// If Action is 0x02 or 0x03 for STS_CONFIG values other than
// 0x04, the UWBS shall return SESSION_UPDATE_CONTROLLER_MULTICAST_LIST_NTF
@@ -1043,7 +438,7 @@ impl Session {
});
});
}
- UpdateMulticastListAction::Delete => {
+ UpdateMulticastListAction::RemoveControlee => {
new_controlees.iter().for_each(|controlee: &Controlee| {
let pica_tx = self.pica_tx.clone();
let address = controlee.short_address;
@@ -1080,12 +475,12 @@ impl Session {
});
}
}
- self.app_config.number_of_controlees = dst_addresses.len();
- self.app_config.dst_mac_addresses = dst_addresses.clone();
+ self.app_config.number_of_controlees = dst_addresses.len() as u8;
+ self.app_config.dst_mac_address = dst_addresses.clone();
// If the multicast list becomes empty, the UWBS shall move the session to
// SESSION_STATE_IDLE by sending the SESSION_STATUS_NTF with Reason Code
// set to ERROR_INVALID_NUM_OF_CONTROLEES.
- if self.app_config.dst_mac_addresses.is_empty() {
+ if self.app_config.dst_mac_address.is_empty() {
self.set_state(
SessionState::SessionStateIdle,
ReasonCode::ErrorInvalidNumOfControlees,
@@ -1118,7 +513,8 @@ impl Session {
assert_eq!(self.state, SessionState::SessionStateIdle);
let session_id = self.id;
- let ranging_interval = self.app_config.ranging_interval;
+ let ranging_interval =
+ time::Duration::from_millis(self.app_config.ranging_duration as u64);
let device_handle = self.device_handle;
let tx = self.pica_tx.clone();
self.ranging_task = Some(tokio::spawn(async move {
diff --git a/src/uci_packets.pdl b/src/uci_packets.pdl
index 2213e02..ebb8db2 100644
--- a/src/uci_packets.pdl
+++ b/src/uci_packets.pdl
@@ -199,13 +199,14 @@ enum DeviceConfigId : 8 {
LOW_POWER_MODE = 0x01,
}
+// [UCI] Table 45: APP Configuration Parameters IDs
enum AppConfigTlvType : 8 {
DEVICE_TYPE = 0x00,
RANGING_ROUND_USAGE = 0x01,
STS_CONFIG = 0x02,
MULTI_NODE_MODE = 0x03,
CHANNEL_NUMBER = 0x04,
- NO_OF_CONTROLEE = 0x05,
+ NUMBER_OF_CONTROLEES = 0x05,
DEVICE_MAC_ADDRESS = 0x06,
DST_MAC_ADDRESS = 0x07,
SLOT_DURATION = 0x08,
@@ -214,9 +215,9 @@ enum AppConfigTlvType : 8 {
MAC_FCS_TYPE = 0x0B,
RANGING_ROUND_CONTROL = 0x0C,
AOA_RESULT_REQ = 0x0D,
- RNG_DATA_NTF = 0x0E,
- RNG_DATA_NTF_PROXIMITY_NEAR = 0x0F,
- RNG_DATA_NTF_PROXIMITY_FAR = 0x10,
+ SESSION_INFO_NTF_CONFIG = 0x0E,
+ NEAR_PROXIMITY_CONFIG = 0x0F,
+ FAR_PROXIMITY_CONFIG = 0x10,
DEVICE_ROLE = 0x11,
RFRAME_CONFIG = 0x12,
RSSI_REPORTING = 0x13,
@@ -228,14 +229,11 @@ enum AppConfigTlvType : 8 {
DATA_REPETITION_COUNT = 0x19,
RANGING_TIME_STRUCT = 0x1A,
SLOTS_PER_RR = 0x1B,
- TX_ADAPTIVE_PAYLOAD_POWER = 0x1C,
- // TODO: Ensure this value is correct in the final 2.0 specification.
- RNG_DATA_NTF_AOA_BOUND = 0x1D,
- RESPONDER_SLOT_INDEX = 0x1E,
+ AOA_BOUND_CONFIG = 0x1D,
PRF_MODE = 0x1F,
CAP_SIZE_RANGE = 0x20,
TX_JITTER_WINDOW_SIZE = 0x21,
- SCHEDULED_MODE = 0x22,
+ SCHEDULE_MODE = 0x22,
KEY_ROTATION = 0x23,
KEY_ROTATION_RATE = 0x24,
SESSION_PRIORITY = 0x25,
@@ -252,13 +250,7 @@ enum AppConfigTlvType : 8 {
SUB_SESSION_ID = 0x30,
BPRF_PHR_DATA_RATE = 0x31,
MAX_NUMBER_OF_MEASUREMENTS = 0x32,
- UL_TDOA_TX_INTERVAL = 0x33,
- UL_TDOA_RANDOM_WINDOW = 0x34,
STS_LENGTH = 0x35,
- SUSPEND_RANGING_ROUNDS = 0x36,
- UL_TDOA_NTF_REPORT_CONFIG = 0x37,
- UL_TDOA_DEVICE_ID = 0x38,
- UL_TDOA_TX_TIMESTAMP = 0x39,
MIN_FRAMES_PER_RR = 0x3A,
MTU_SIZE = 0x3B,
INTER_FRAME_INTERVAL = 0x3C,
@@ -268,10 +260,10 @@ enum AppConfigTlvType : 8 {
DL_TDOA_ANCHOR_CFO = 0x40,
DL_TDOA_ANCHOR_LOCATION = 0x41,
DL_TDOA_TX_ACTIVE_RANGING_ROUNDS = 0x42,
- DL_TDOA_BLOCK_STRIDING = 0x43,
+ DL_TDOA_BLOCK_SKIPPING = 0x43,
DL_TDOA_TIME_REFERENCE_ANCHOR = 0x44,
SESSION_KEY = 0x45,
- SUBSESSION_KEY = 0x46,
+ SUB_SESSION_KEY = 0x46,
SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG = 0x47,
SESSION_TIME_BASE = 0x48,
DL_TDOA_RESPONDER_TOF = 0x49,
@@ -279,9 +271,9 @@ enum AppConfigTlvType : 8 {
SECURE_RANGING_CSW_LENGTH = 0x4B,
APPLICATION_DATA_ENDPOINT = 0x4C,
OWR_AOA_MEASUREMENT_NTF_PERIOD = 0x4D,
- RFU_APP_CFG_TLV_TYPE_RANGE = 0x4E..0x9F,
+ RFU = 0x4E..0x9F,
- VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_1 = 0xA0..0xDF {
+ VENDOR_SPECIFIC_1 = 0xA0..0xDF {
// CCC specific
CCC_HOP_MODE_KEY = 0xA0,
CCC_UWB_TIME0 = 0xA1,
@@ -293,9 +285,10 @@ enum AppConfigTlvType : 8 {
},
// Reserved for extension IDs.
- RFU_APP_CFG_TLV_TYPE_RANGE_3 = 0xE0..0xE2,
+ // ID is 2 Octets in length. Refer section 8.1 for details
+ ID_EXTENSION = 0xE0..0xE2,
- VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_2 = 0xE3..0xFF {
+ VENDOR_SPECIFIC_2 = 0xE3..0xFF {
// Interleaving ratio if AOA_RESULT_REQ is set to 0xF0.
NB_OF_RANGE_MEASUREMENTS = 0xE3,
NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
@@ -305,10 +298,189 @@ enum AppConfigTlvType : 8 {
},
}
-enum FrameReportTlvType : 8 {
- RSSI = 0x0,
- AOA = 0x1,
- CIR = 0x2,
+enum DeviceType : 8 {
+ // [MAC] 5.1.2
+ // Device utilizing the ranging features set through Control Messages
+ CONTROLEE = 0x00,
+ // [MAC] 5.1.1
+ // Device controlling the ranging features through Control Messages
+ CONTROLLER = 0x01,
+}
+
+enum RangingRoundUsage : 8 {
+ SS_TWR_DEFERRED_MODE = 0x01,
+ DS_TWR_DEFERRED_MODE = 0x02,
+ SS_TWR_NON_DEFERRED_MODE = 0x03,
+ DS_TWR_NON_DEFERRED_MODE = 0x04,
+ ON_WAY_RANGING_DL_TDOA = 0x05,
+ OWR_AOA_MEASUREMENT = 0x06,
+ ESS_TWR_NON_DEFERRED = 0x07,
+ ADS_TWR_NON_DEFERRED = 0x08,
+}
+
+enum StsConfig : 8 {
+ STATIC = 0x00, // Default
+ DYNAMIC = 0x01,
+ DYNAMIC_FOR_RESPONDER_SUB_SESSION_KEY = 0x02,
+ PROVISIONED = 0x03,
+ PROVISIONED_FOR_RESPONDER_SUB_SESSION_KEY = 0x04,
+}
+
+enum MultiNodeMode : 8 {
+ ONE_TO_ONE = 0x00,
+ ONE_TO_MANY = 0x01,
+}
+
+enum ChannelNumber : 8 {
+ CHANNEL_NUMBER_5 = 0x05,
+ CHANNEL_NUMBER_6 = 0x06,
+ CHANNEL_NUMBER_8 = 0x08,
+ CHANNEL_NUMBER_9 = 0x09, // Default
+ CHANNEL_NUMBER_10 = 0x0a,
+ CHANNEL_NUMBER_12 = 0x0c,
+ CHANNEL_NUMBER_13 = 0x0d,
+ CHANNEL_NUMBER_14 = 0x0e,
+}
+
+enum MacFcsType : 8 {
+ CRC_16 = 0x00, // Default
+ CRC_32 = 0x01,
+}
+
+struct RangingRoundControl {
+ rrrm : 1, // Default 1
+ _fixed_ = 1 : 1,
+ rcp : 1, // Default 0
+ _reserved_ : 3,
+ mrp : 1, // Default 0
+ mrm : 1, // Default 0
+}
+
+enum AoaResultReq : 8 {
+ AOA_DISABLED = 0x00,
+ AOA_ENABLED = 0x01, // Default
+ AOA_ENABLED_AZIMUTH_ONLY = 0x02,
+ AOA_ENABLED_ELEVATION_ONLY = 0x03,
+}
+
+enum SessionInfoNtfConfig : 8 {
+ DISABLE = 0x00,
+ ENABLE = 0x01, // Default
+ ENABLE_PROXIMITY_TRIGGER = 0x02,
+ ENABLE_AOA_TRIGGER = 0x03,
+ ENABLE_PROXIMITY_AOA_TRIGGER = 0x04,
+ ENABLE_PROXIMITY_EDGE_TRIGGER = 0x05,
+ ENABLE_AOA_EDGE_TRIGGER = 0x06,
+ ENABLE_PROXIMITY_AOA_EDGE_TRIGGER = 0x07,
+}
+
+enum DeviceRole : 8 {
+ // [MAC] 5.1.3
+ // Device initiating a ranging exchange with a ranging initiation message
+ RESPONDER = 0x00,
+ // [MAC] 5.1.4
+ // Device responding to ranging initiation messages
+ INITIATOR = 0x01,
+ ADVERTISER = 0x05,
+ OBSERVER = 0x06,
+ DT_ANCHOR = 0x07,
+ DT_TAG = 0x08,
+}
+
+enum RframeConfig : 8 {
+ SP0 = 0x00,
+ SP1 = 0x01,
+ SP3 = 0x03, // Default
+}
+
+enum RssiReporting : 8 {
+ DISABLE = 0x00, // Default
+ ENABLE = 0x01,
+}
+
+enum PsduDataRate : 8 {
+ DATA_RATE_6M81 = 0x00,
+ DATA_RATE_7M80 = 0x01,
+ DATA_RATE_27M2 = 0x02,
+ DATA_RATE_31M2 = 0x03,
+}
+
+enum PreambleDuration : 8 {
+ DURATION_32_SYMBOLS = 0x00,
+ DURATION_64_SYMBOLS = 0x01, // Default
+}
+
+enum LinkLayerMode : 8 {
+ BYPASS_MODE = 0x00, // Default
+}
+
+enum RangingTimeStruct : 8 {
+ BLOCK_BASED_SCHEDULING = 0x01, // Default
+}
+
+enum PrfMode : 8 {
+ BPRF_MODE = 0x00, // Default
+ HPRF_MODE_124M8 = 0x01,
+ HPRF_MODE_249M6 = 0x02,
+}
+
+enum ScheduleMode : 8 {
+ CONTENTION_BASED = 0x00,
+ TIME_SCHEDULED = 0x01,
+}
+
+enum KeyRotation : 8 {
+ DISABLE = 0x00, // Default
+ ENABLE = 0x01,
+}
+
+enum MacAddressMode : 8 {
+ // MAC address is 2 bytes and 2 bytes to be used in MAC header
+ MODE_0 = 0x00, // Default
+ // MAC address is 8 bytes and 2 bytes to be used in MAC header
+ // (Not supported).
+ MODE_1 = 0x01,
+ // MAC address is 8 bytes and 8 bytes to be used in MAC header
+ MODE_2 = 0x02,
+}
+
+enum HoppingMode : 8 {
+ DISABLE = 0x00, // Default
+ ENABLE = 0x01,
+}
+
+struct ResultReportConfig {
+ tof : 1, // Default 1
+ aoa_azimuth : 1,
+ aoa_elevation : 1,
+ aoa_fom : 1,
+ _reserved_ : 4,
+}
+
+enum BprfPhrDataRate : 8 {
+ DATA_RATE_850K = 0x00, // Default
+ DATA_RATE_6M81 = 0x01
+}
+
+enum StsLength : 8 {
+ LENGTH_32_SYMBOLS = 0x00, // Default
+ LENGTH_64_SYMBOLS = 0x01,
+ LENGTH_128_SYMBOLS = 0x02,
+}
+
+enum DlTdoaRangingMethod : 8 {
+ SS_TWR = 0x00,
+ DS_TWR = 0x01, // Default
+}
+
+enum DlTdoaAnchorCfo : 8 {
+ ANCHOR_CFO_NOT_INCLUDED = 0x00,
+ ANCHOR_CFO_INCLUDED = 0x01, // Default
+}
+
+enum SessionDataTransferStatusNtfConfig : 8 {
+ DISABLE = 0x00, // Default
+ ENABLE = 0x01,
}
enum CapTlvType : 8 {
@@ -706,7 +878,7 @@ test SetConfigRsp {
packet GetConfigCmd : CoreCommand (opcode = 0x5) { //CORE_GET_CONFIG
_count_(cfg_id): 8,
- cfg_id: 8[], // DeviceConfigId (Infra does not allow array of enums)
+ cfg_id: 8[], // DeviceConfigId
}
test GetConfigCmd {
@@ -839,7 +1011,7 @@ test SessionSetAppConfigRsp {
packet SessionGetAppConfigCmd : SessionConfigCommand (opcode = 0x4) { //SESSION_GET_APP_CONFIG
session_token: 32, // Session ID or Session Handle (based on UWBS version)
_count_(app_cfg): 8,
- app_cfg: 8[], // AppConfigTlvType (Infra does not allow array of enums)
+ app_cfg: AppConfigTlvType[],
}
test SessionGetAppConfigCmd {
@@ -926,11 +1098,12 @@ struct Controlee_V2_0_32_Byte_Version {
subsession_key: 8[32],
}
+/// cf. [UCI] 7.7
enum UpdateMulticastListAction: 8 {
ADD_CONTROLEE = 0x00,
REMOVE_CONTROLEE = 0x01,
ADD_CONTROLEE_WITH_SHORT_SUB_SESSION_KEY = 0x02,
- ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY = 0x03,
+ ADD_CONTROLEE_WITH_EXTENDED_SUB_SESSION_KEY = 0x03,
}
packet SessionUpdateControllerMulticastListCmd : SessionConfigCommand (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
@@ -1262,6 +1435,12 @@ test AndroidSetCountryCodeRsp {
"\x4c\x01\x00\x01\x00\x00\x00\x00",
}
+enum FrameReportTlvType : 8 {
+ RSSI = 0x0,
+ AOA = 0x1,
+ CIR = 0x2,
+}
+
struct FrameReportTlv {
t: FrameReportTlvType,
_size_(v): 16,
diff --git a/tests/data_transfer.py b/tests/data_transfer.py
index 241a6b9..7449a35 100755
--- a/tests/data_transfer.py
+++ b/tests/data_transfer.py
@@ -45,32 +45,45 @@ async def controller(host: Host, peer: Host, file: Path):
)
)
- mac_address_mode = 0x0
+ ranging_round_usage = 0x06
ranging_duration = int(1000).to_bytes(4, byteorder="little")
- device_role_initiator = bytes([0])
- device_type_controller = bytes([1])
+
host.send_control(
uci.SessionSetAppConfigCmd(
session_token=0,
tlvs=[
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_ROLE, v=device_role_initiator
+ cfg_id=uci.AppConfigTlvType.DEVICE_ROLE,
+ v=bytes([uci.DeviceRole.INITIATOR]),
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_TYPE, v=device_type_controller
+ cfg_id=uci.AppConfigTlvType.DEVICE_TYPE,
+ v=bytes([uci.DeviceType.CONTROLLER]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DEVICE_MAC_ADDRESS, v=host.mac_address
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.MAC_ADDRESS_MODE,
- v=bytes([mac_address_mode]),
+ v=bytes([uci.MacAddressMode.MODE_0]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.MULTI_NODE_MODE,
+ v=bytes([uci.MultiNodeMode.ONE_TO_ONE]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.SCHEDULE_MODE,
+ v=bytes([uci.ScheduleMode.CONTENTION_BASED]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.RANGING_ROUND_USAGE,
+ v=bytes([ranging_round_usage]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.RANGING_DURATION, v=ranging_duration
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.NO_OF_CONTROLEE, v=bytes([1])
+ cfg_id=uci.AppConfigTlvType.NUMBER_OF_CONTROLEES, v=bytes([1])
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DST_MAC_ADDRESS, v=peer.mac_address
@@ -159,32 +172,45 @@ async def controlee(host: Host, peer: Host, file: Path):
)
)
- mac_address_mode = 0x0
+ ranging_round_usage = 0x06
ranging_duration = int(1000).to_bytes(4, byteorder="little")
- device_role_responder = bytes([1])
- device_type_controllee = bytes([0])
+
host.send_control(
uci.SessionSetAppConfigCmd(
session_token=0,
tlvs=[
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_ROLE, v=device_role_responder
+ cfg_id=uci.AppConfigTlvType.DEVICE_ROLE,
+ v=bytes([uci.DeviceRole.RESPONDER]),
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_TYPE, v=device_type_controllee
+ cfg_id=uci.AppConfigTlvType.DEVICE_TYPE,
+ v=bytes([uci.DeviceType.CONTROLEE]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DEVICE_MAC_ADDRESS, v=host.mac_address
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.MAC_ADDRESS_MODE,
- v=bytes([mac_address_mode]),
+ v=bytes([uci.MacAddressMode.MODE_0]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.MULTI_NODE_MODE,
+ v=bytes([uci.MultiNodeMode.ONE_TO_ONE]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.SCHEDULE_MODE,
+ v=bytes([uci.ScheduleMode.CONTENTION_BASED]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.RANGING_ROUND_USAGE,
+ v=bytes([ranging_round_usage]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.RANGING_DURATION, v=ranging_duration
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.NO_OF_CONTROLEE, v=bytes([1])
+ cfg_id=uci.AppConfigTlvType.NUMBER_OF_CONTROLEES, v=bytes([1])
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DST_MAC_ADDRESS, v=peer.mac_address
diff --git a/tests/ranging.py b/tests/ranging.py
index 7af8224..9af4376 100755
--- a/tests/ranging.py
+++ b/tests/ranging.py
@@ -42,32 +42,45 @@ async def controller(host: Host, peer: Host):
)
)
- mac_address_mode = 0x0
+ ranging_round_usage = 0x06
ranging_duration = int(1000).to_bytes(4, byteorder="little")
- device_role_initiator = bytes([0])
- device_type_controller = bytes([1])
+
host.send_control(
uci.SessionSetAppConfigCmd(
session_token=0,
tlvs=[
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_ROLE, v=device_role_initiator
+ cfg_id=uci.AppConfigTlvType.DEVICE_ROLE,
+ v=bytes([uci.DeviceRole.INITIATOR]),
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_TYPE, v=device_type_controller
+ cfg_id=uci.AppConfigTlvType.DEVICE_TYPE,
+ v=bytes([uci.DeviceType.CONTROLLER]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DEVICE_MAC_ADDRESS, v=host.mac_address
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.MAC_ADDRESS_MODE,
- v=bytes([mac_address_mode]),
+ v=bytes([uci.MacAddressMode.MODE_0]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.MULTI_NODE_MODE,
+ v=bytes([uci.MultiNodeMode.ONE_TO_ONE]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.SCHEDULE_MODE,
+ v=bytes([uci.ScheduleMode.CONTENTION_BASED]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.RANGING_ROUND_USAGE,
+ v=bytes([ranging_round_usage]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.RANGING_DURATION, v=ranging_duration
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.NO_OF_CONTROLEE, v=bytes([1])
+ cfg_id=uci.AppConfigTlvType.NUMBER_OF_CONTROLEES, v=bytes([1])
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DST_MAC_ADDRESS, v=peer.mac_address
@@ -148,32 +161,45 @@ async def controlee(host: Host, peer: Host):
)
)
- mac_address_mode = 0x0
+ ranging_round_usage = 0x06
ranging_duration = int(1000).to_bytes(4, byteorder="little")
- device_role_responder = bytes([1])
- device_type_controlee = bytes([0])
+
host.send_control(
uci.SessionSetAppConfigCmd(
session_token=0,
tlvs=[
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_ROLE, v=device_role_responder
+ cfg_id=uci.AppConfigTlvType.DEVICE_ROLE,
+ v=bytes([uci.DeviceRole.RESPONDER]),
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.DEVICE_TYPE, v=device_type_controlee
+ cfg_id=uci.AppConfigTlvType.DEVICE_TYPE,
+ v=bytes([uci.DeviceType.CONTROLEE]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DEVICE_MAC_ADDRESS, v=host.mac_address
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.MAC_ADDRESS_MODE,
- v=bytes([mac_address_mode]),
+ v=bytes([uci.MacAddressMode.MODE_0]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.MULTI_NODE_MODE,
+ v=bytes([uci.MultiNodeMode.ONE_TO_ONE]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.SCHEDULE_MODE,
+ v=bytes([uci.ScheduleMode.CONTENTION_BASED]),
+ ),
+ uci.AppConfigTlv(
+ cfg_id=uci.AppConfigTlvType.RANGING_ROUND_USAGE,
+ v=bytes([ranging_round_usage]),
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.RANGING_DURATION, v=ranging_duration
),
uci.AppConfigTlv(
- cfg_id=uci.AppConfigTlvType.NO_OF_CONTROLEE, v=bytes([1])
+ cfg_id=uci.AppConfigTlvType.NUMBER_OF_CONTROLEES, v=bytes([1])
),
uci.AppConfigTlv(
cfg_id=uci.AppConfigTlvType.DST_MAC_ADDRESS, v=peer.mac_address