aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenri Chataing <henrichataing@google.com>2024-04-05 23:49:30 +0000
committerHenri Chataing <henrichataing@google.com>2024-04-05 23:53:16 +0000
commit2fa040978d9004a07be97597cf4b3a758f1b7b6b (patch)
tree948bad0adf585b1939c9c8612add3921c708fe9b
parentd32b655bf547114b57812e3218d61607a23382ff (diff)
parent1c4360d02d1496589fb1597a0e49f1b042eaf96c (diff)
downloadpica-master.tar.gz
Update pica to v0.1.9 from upstreamHEADmastermain
Merge remote-tracking branch 'aosp/upstream-main' into pica-update Test: TreeHugger Test: atest CtsUwbTestCases Change-Id: Icd5f2ef8e5443ce800cfdce15a96d3ff171132b2
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--METADATA4
-rw-r--r--py/pica/pica/packets/uci.py3127
-rw-r--r--src/app_config.rs517
-rw-r--r--src/device.rs975
-rw-r--r--src/lib.rs24
-rw-r--r--src/mac_address.rs25
-rw-r--r--src/session.rs1112
-rw-r--r--src/uci_packets.pdl904
-rwxr-xr-xtests/data_transfer.py94
-rw-r--r--tests/helper.py8
-rwxr-xr-xtests/ranging.py82
13 files changed, 3064 insertions, 3812 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a59c5c0..ca8765e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -648,7 +648,7 @@ dependencies = [
[[package]]
name = "pica"
-version = "0.1.7"
+version = "0.1.9"
dependencies = [
"anyhow",
"bytes",
diff --git a/Cargo.toml b/Cargo.toml
index 7fea374..d27cd71 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "pica"
-version = "0.1.8"
+version = "0.1.9"
edition = "2021"
description = "Pica is a virtual UWB Controller implementing the FiRa UCI specification."
repository = "https://github.com/google/pica"
diff --git a/METADATA b/METADATA
index 36c8e14..46cbcbf 100644
--- a/METADATA
+++ b/METADATA
@@ -12,7 +12,7 @@ third_party {
type: GIT
value: "https://github.com/google/pica.git"
}
- version: "v0.1.8"
+ version: "v0.1.9"
license_type: NOTICE
- last_upgrade_date { year: 2024 month: 3 day: 13 }
+ last_upgrade_date { year: 2024 month: 4 day: 5 }
}
diff --git a/py/pica/pica/packets/uci.py b/py/pica/pica/packets/uci.py
index 32ffbdc..574feab 100644
--- a/py/pica/pica/packets/uci.py
+++ b/py/pica/pica/packets/uci.py
@@ -94,16 +94,30 @@ class PacketBoundaryFlag(enum.IntEnum):
raise exn
+class MessageType(enum.IntEnum):
+ DATA = 0x0
+ COMMAND = 0x1
+ RESPONSE = 0x2
+ NOTIFICATION = 0x3
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'MessageType']:
+ try:
+ return MessageType(v)
+ except ValueError as exn:
+ raise exn
+
+
class GroupId(enum.IntEnum):
CORE = 0x0
SESSION_CONFIG = 0x1
SESSION_CONTROL = 0x2
DATA_CONTROL = 0x3
- TEST = 0xd
VENDOR_RESERVED_9 = 0x9
VENDOR_RESERVED_A = 0xa
VENDOR_RESERVED_B = 0xb
VENDOR_ANDROID = 0xc
+ TEST = 0xd
VENDOR_RESERVED_E = 0xe
VENDOR_RESERVED_F = 0xf
@@ -127,154 +141,112 @@ class DataPacketFormat(enum.IntEnum):
raise exn
-class GroupIdOrDataPacketFormat(enum.IntEnum):
- CORE = 0x0
- SESSION_CONFIG_OR_DATA_SND = 0x1
- SESSION_CONTROL_OR_DATA_RCV = 0x2
- DATA_CONTROL = 0x3
- TEST = 0xd
- VENDOR_RESERVED_9 = 0x9
- VENDOR_RESERVED_A = 0xa
- VENDOR_RESERVED_B = 0xb
- VENDOR_ANDROID = 0xc
- VENDOR_RESERVED_E = 0xe
- VENDOR_RESERVED_F = 0xf
+class CoreOpcodeId(enum.IntEnum):
+ DEVICE_RESET = 0x0
+ DEVICE_STATUS = 0x1
+ GET_DEVICE_INFO = 0x2
+ GET_CAPS_INFO = 0x3
+ SET_CONFIG = 0x4
+ GET_CONFIG = 0x5
+ GENERIC_ERROR = 0x7
+ QUERY_UWBS_TIMESTAMP = 0x8
@staticmethod
- def from_int(v: int) -> Union[int, 'GroupIdOrDataPacketFormat']:
+ def from_int(v: int) -> Union[int, 'CoreOpcodeId']:
try:
- return GroupIdOrDataPacketFormat(v)
+ return CoreOpcodeId(v)
except ValueError as exn:
raise exn
-class CoreOpCode(enum.IntEnum):
- CORE_DEVICE_RESET = 0x0
- CORE_DEVICE_STATUS_NTF = 0x1
- CORE_DEVICE_INFO = 0x2
- CORE_GET_CAPS_INFO = 0x3
- CORE_SET_CONFIG = 0x4
- CORE_GET_CONFIG = 0x5
- CORE_DEVICE_SUSPEND = 0x6
- CORE_GENERIC_ERROR_NTF = 0x7
- CORE_QUERY_UWBS_TIMESTAMP = 0x8
+class SessionConfigOpcodeId(enum.IntEnum):
+ INIT = 0x0
+ DEINIT = 0x1
+ STATUS = 0x2
+ SET_APP_CONFIG = 0x3
+ GET_APP_CONFIG = 0x4
+ GET_COUNT = 0x5
+ GET_STATE = 0x6
+ UPDATE_CONTROLLER_MULTICAST_LIST = 0x7
+ UPDATE_DT_ANCHOR_RANGING_ROUNDS = 0x8
+ UPDATE_DT_TAG_RANGING_ROUNDS = 0x9
+ QUERY_DATA_SIZE_IN_RANGING = 0xb
@staticmethod
- def from_int(v: int) -> Union[int, 'CoreOpCode']:
+ def from_int(v: int) -> Union[int, 'SessionConfigOpcodeId']:
try:
- return CoreOpCode(v)
+ return SessionConfigOpcodeId(v)
except ValueError as exn:
raise exn
-class SessionConfigOpCode(enum.IntEnum):
- SESSION_INIT = 0x0
- SESSION_DEINIT = 0x1
- SESSION_STATUS_NTF = 0x2
- SESSION_SET_APP_CONFIG = 0x3
- SESSION_GET_APP_CONFIG = 0x4
- SESSION_GET_COUNT = 0x5
- SESSION_GET_STATE = 0x6
- SESSION_UPDATE_CONTROLLER_MULTICAST_LIST = 0x7
- SESSION_UPDATE_ACTIVE_ROUNDS_ANCHOR = 0x8
- SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG = 0x9
- SESSION_SET_INITIATOR_DT_ANCHOR_RR_RDM_LIST = 0xa
- SESSION_QUERY_DATA_SIZE_IN_RANGING = 0xb
- SESSION_SET_HUS_CONFIG = 0xc
+class SessionControlOpcodeId(enum.IntEnum):
+ START = 0x0
+ STOP = 0x1
+ GET_RANGING_COUNT = 0x3
+ DATA_CREDIT = 0x4
+ DATA_TRANSFER_STATUS = 0x5
@staticmethod
- def from_int(v: int) -> Union[int, 'SessionConfigOpCode']:
+ def from_int(v: int) -> Union[int, 'SessionControlOpcodeId']:
try:
- return SessionConfigOpCode(v)
+ return SessionControlOpcodeId(v)
except ValueError as exn:
raise exn
-class SessionControlOpCode(enum.IntEnum):
- SESSION_START = 0x0
- SESSION_STOP = 0x1
- SESSION_RESERVED = 0x2
- SESSION_GET_RANGING_COUNT = 0x3
- SESSION_DATA_CREDIT_NTF = 0x4
- SESSION_DATA_TRANSFER_STATUS_NTF = 0x5
+class AndroidOpcodeId(enum.IntEnum):
+ GET_POWER_STATS = 0x0
+ SET_COUNTRY_CODE = 0x1
+ FIRA_RANGE_DIAGNOSTICS = 0x2
@staticmethod
- def from_int(v: int) -> Union[int, 'SessionControlOpCode']:
+ def from_int(v: int) -> Union[int, 'AndroidOpcodeId']:
try:
- return SessionControlOpCode(v)
+ return AndroidOpcodeId(v)
except ValueError as exn:
raise exn
-class AppDataOpCode(enum.IntEnum):
- APP_DATA_TX = 0x0
- APP_DATA_RX = 0x1
-
- @staticmethod
- def from_int(v: int) -> Union[int, 'AppDataOpCode']:
- try:
- return AppDataOpCode(v)
- except ValueError as exn:
- raise exn
-
-
-class AndroidOpCode(enum.IntEnum):
- ANDROID_GET_POWER_STATS = 0x0
- ANDROID_SET_COUNTRY_CODE = 0x1
- ANDROID_FIRA_RANGE_DIAGNOSTICS = 0x2
-
- @staticmethod
- def from_int(v: int) -> Union[int, 'AndroidOpCode']:
- try:
- return AndroidOpCode(v)
- except ValueError as exn:
- raise exn
-
-
-class StatusCode(enum.IntEnum):
- UCI_STATUS_OK = 0x0
- UCI_STATUS_REJECTED = 0x1
- UCI_STATUS_FAILED = 0x2
- UCI_STATUS_SYNTAX_ERROR = 0x3
- UCI_STATUS_INVALID_PARAM = 0x4
- UCI_STATUS_INVALID_RANGE = 0x5
- UCI_STATUS_INVALID_MSG_SIZE = 0x6
- UCI_STATUS_UNKNOWN_GID = 0x7
- UCI_STATUS_UNKNOWN_OID = 0x8
- UCI_STATUS_READ_ONLY = 0x9
- UCI_STATUS_COMMAND_RETRY = 0xa
- UCI_STATUS_UNKNOWN = 0xb
- UCI_STATUS_NOT_APPLICABLE = 0xc
- UCI_STATUS_SESSION_NOT_EXIST = 0x11
- UCI_STATUS_SESSION_DUPLICATE = 0x12
- UCI_STATUS_SESSION_ACTIVE = 0x13
- UCI_STATUS_MAX_SESSIONS_EXCEEDED = 0x14
- UCI_STATUS_SESSION_NOT_CONFIGURED = 0x15
- UCI_STATUS_ACTIVE_SESSIONS_ONGOING = 0x16
- UCI_STATUS_MULTICAST_LIST_FULL = 0x17
- UCI_STATUS_ADDRESS_NOT_FOUND = 0x18
- UCI_STATUS_ADDRESS_ALREADY_PRESENT = 0x19
- UCI_STATUS_ERROR_UWB_INITIATION_TIME_TOO_OLD = 0x1a
- UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT = 0x1b
- UCI_STATUS_RANGING_TX_FAILED = 0x20
- UCI_STATUS_RANGING_RX_TIMEOUT = 0x21
- UCI_STATUS_RANGING_RX_PHY_DEC_FAILED = 0x22
- UCI_STATUS_RANGING_RX_PHY_TOA_FAILED = 0x23
- UCI_STATUS_RANGING_RX_PHY_STS_FAILED = 0x24
- UCI_STATUS_RANGING_RX_MAC_DEC_FAILED = 0x25
- UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED = 0x26
- UCI_STATUS_RANGING_RX_MAC_IE_MISSING = 0x27
- UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED = 0x28
- UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 0x29
- UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 0x2a
- UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED = 0x30
- UCI_STATUS_DATA_RX_CRC_ERROR = 0x31
- VENDOR_SPECIFIC_STATUS_CODE_2 = 0xff
-
- @staticmethod
- def from_int(v: int) -> Union[int, 'StatusCode']:
- try:
- return StatusCode(v)
+class Status(enum.IntEnum):
+ OK = 0x0
+ REJECTED = 0x1
+ FAILED = 0x2
+ SYNTAX_ERROR = 0x3
+ INVALID_PARAM = 0x4
+ INVALID_RANGE = 0x5
+ INVALID_MESSAGE_SIZE = 0x6
+ UNKNOWN_GID = 0x7
+ UNKNOWN_OID = 0x8
+ READ_ONLY = 0x9
+ UCI_MESSAGE_RETRY = 0xa
+ UNKNOWN = 0xb
+ NOT_APPLICABLE = 0xc
+ ERROR_SESSION_NOT_EXIST = 0x11
+ ERROR_SESSION_DUPLICATE = 0x12
+ ERROR_SESSION_ACTIVE = 0x13
+ ERROR_MAX_SESSIONS_EXCEEDED = 0x14
+ ERROR_SESSION_NOT_CONFIGURED = 0x15
+ ERROR_ACTIVE_SESSIONS_ONGOING = 0x16
+ ERROR_MULTICAST_LIST_FULL = 0x17
+ ERROR_UWB_INITIATION_TIME_TOO_OLD = 0x1a
+ OK_NEGATIVE_DISTANCE_REPORT = 0x1b
+ RANGING_TX_FAILED = 0x20
+ RANGING_RX_TIMEOUT = 0x21
+ RANGING_RX_PHY_DEC_FAILED = 0x22
+ RANGING_RX_PHY_TOA_FAILED = 0x23
+ RANGING_RX_PHY_STS_FAILED = 0x24
+ RANGING_RX_MAC_DEC_FAILED = 0x25
+ RANGING_RX_MAC_IE_DEC_FAILED = 0x26
+ RANGING_RX_MAC_IE_MISSING = 0x27
+ ERROR_ROUND_INDEX_NOT_ACTIVATED = 0x28
+ ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 0x29
+ ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 0x2a
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'Status']:
+ try:
+ return Status(v)
except ValueError as exn:
return v
@@ -333,25 +305,13 @@ class ResetConfig(enum.IntEnum):
raise exn
-class DeviceConfigId(enum.IntEnum):
- DEVICE_STATE = 0x0
- LOW_POWER_MODE = 0x1
-
- @staticmethod
- def from_int(v: int) -> Union[int, 'DeviceConfigId']:
- try:
- return DeviceConfigId(v)
- except ValueError as exn:
- raise exn
-
-
class AppConfigTlvType(enum.IntEnum):
DEVICE_TYPE = 0x0
RANGING_ROUND_USAGE = 0x1
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 +320,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 +334,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 +355,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 +365,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 +385,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
@@ -571,20 +942,21 @@ class ReasonCode(enum.IntEnum):
return v
-class MulticastUpdateStatusCode(enum.IntEnum):
- STATUS_OK_MULTICAST_LIST_UPDATE = 0x0
- STATUS_ERROR_MULTICAST_LIST_FULL = 0x1
- STATUS_ERROR_KEY_FETCH_FAIL = 0x2
- STATUS_ERROR_SUB_SESSION_ID_NOT_FOUND = 0x3
- STATUS_ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x5
- STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x6
- STATUS_ERROR_SESSION_KEY_NOT_FOUND = 0x7
- STATUS_ERROR_ADDRESS_ALREADY_PRESENT = 0x8
+class MulticastUpdateStatus(enum.IntEnum):
+ OK_MULTICAST_LIST_UPDATE = 0x0
+ ERROR_MULTICAST_LIST_FULL = 0x1
+ ERROR_KEY_FETCH_FAIL = 0x2
+ ERROR_SUB_SESSION_ID_NOT_FOUND = 0x3
+ ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x4
+ ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x5
+ ERROR_SESSION_KEY_NOT_FOUND = 0x6
+ ERROR_ADDRESS_NOT_FOUND = 0x7
+ ERROR_ADDRESS_ALREADY_PRESENT = 0x8
@staticmethod
- def from_int(v: int) -> Union[int, 'MulticastUpdateStatusCode']:
+ def from_int(v: int) -> Union[int, 'MulticastUpdateStatus']:
try:
- return MulticastUpdateStatusCode(v)
+ return MulticastUpdateStatus(v)
except ValueError as exn:
raise exn
@@ -619,22 +991,6 @@ class SessionType(enum.IntEnum):
raise exn
-class MessageType(enum.IntEnum):
- DATA = 0x0
- COMMAND = 0x1
- RESPONSE = 0x2
- NOTIFICATION = 0x3
- RESERVED_FOR_TESTING_1 = 0x4
- RESERVED_FOR_TESTING_2 = 0x5
-
- @staticmethod
- def from_int(v: int) -> Union[int, 'MessageType']:
- try:
- return MessageType(v)
- except ValueError as exn:
- raise exn
-
-
@dataclass
class CommonPacketHeader(Packet):
pbf: PacketBoundaryFlag = field(kw_only=True, default=PacketBoundaryFlag.COMPLETE)
@@ -748,7 +1104,6 @@ class DataPacketHeader(Packet):
class ControlPacket(Packet):
gid: GroupId = field(kw_only=True, default=GroupId.CORE)
mt: MessageType = field(kw_only=True, default=MessageType.DATA)
- opcode: int = field(kw_only=True, default=0)
def __post_init__(self):
pass
@@ -756,210 +1111,28 @@ class ControlPacket(Packet):
@staticmethod
def parse(span: bytes) -> Tuple['ControlPacket', bytes]:
fields = {'payload': None}
- if len(span) < 4:
+ if len(span) < 1:
raise Exception('Invalid packet size')
fields['gid'] = GroupId.from_int((span[0] >> 0) & 0xf)
fields['mt'] = MessageType.from_int((span[0] >> 5) & 0x7)
- fields['opcode'] = (span[1] >> 0) & 0x3f
- value_ = int.from_bytes(span[2:4], byteorder='little')
- span = span[4:]
+ span = span[1:]
payload = span
span = bytes([])
fields['payload'] = payload
try:
- return DeviceResetCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetDeviceInfoCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetCapsInfoCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SetConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return CoreQueryTimeStampCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionInitCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionDeinitCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetAppConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetAppConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetCountCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetStateCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateDtTagRangingRoundsCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateControllerMulticastListCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetHybridConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionQueryMaxDataSizeCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionControlCommand.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidGetPowerStatsCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidSetCountryCodeCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return DeviceResetRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetDeviceInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetCapsInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return CoreQueryTimeStampRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionInitRsp_V2.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionInitRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionDeinitRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetAppConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetAppConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetCountRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetStateRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateDtTagRangingRoundsRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetHybridConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateControllerMulticastListRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionQueryMaxDataSizeRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionStartRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionStopRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetRangingCountRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidGetPowerStatsRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidSetCountryCodeRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return DeviceStatusNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GenericError.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionStatusNtf.parse(fields.copy(), payload)
+ return CorePacket.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionUpdateControllerMulticastListNtf.parse(fields.copy(), payload)
+ return SessionConfigPacket.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return DataCreditNtf.parse(fields.copy(), payload)
+ return SessionControlPacket.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return DataTransferStatusNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionInfoNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidRangeDiagnosticsNtf.parse(fields.copy(), payload)
+ return AndroidPacket.parse(fields.copy(), payload)
except Exception as exn:
pass
return ControlPacket(**fields), span
@@ -971,17 +1144,12 @@ class ControlPacket(Packet):
(self.mt << 5)
)
_span.append(_value)
- if self.opcode > 63:
- print(f"Invalid value for field ControlPacket::opcode: {self.opcode} > 63; the value will be truncated")
- self.opcode &= 63
- _span.append((self.opcode << 0))
- _span.extend([0] * 2)
_span.extend(payload or self.payload or [])
return bytes(_span)
@property
def size(self) -> int:
- return len(self.payload) + 4
+ return len(self.payload) + 1
@dataclass
class DataPacket(Packet):
@@ -1089,7 +1257,7 @@ class DataMessageSnd(DataPacket):
@dataclass
class DataMessageRcv(DataPacket):
session_handle: int = field(kw_only=True, default=0)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
source_address: int = field(kw_only=True, default=0)
data_sequence_number: int = field(kw_only=True, default=0)
application_data: bytearray = field(kw_only=True, default_factory=bytearray)
@@ -1106,7 +1274,7 @@ class DataMessageRcv(DataPacket):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:4], byteorder='little')
fields['session_handle'] = value_
- fields['status'] = StatusCode.from_int(span[4])
+ fields['status'] = Status.from_int(span[4])
value_ = int.from_bytes(span[5:13], byteorder='little')
fields['source_address'] = value_
value_ = int.from_bytes(span[13:15], byteorder='little')
@@ -1144,142 +1312,114 @@ class DataMessageRcv(DataPacket):
return len(self.application_data) * 1 + 17
@dataclass
-class UciCommand(ControlPacket):
-
+class CorePacket(ControlPacket):
+ oid: CoreOpcodeId = field(kw_only=True, default=CoreOpcodeId.DEVICE_RESET)
def __post_init__(self):
- self.mt = MessageType.COMMAND
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciCommand', bytes]:
- if fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CorePacket', bytes]:
+ if fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
+ if len(span) < 3:
+ raise Exception('Invalid packet size')
+ fields['oid'] = CoreOpcodeId.from_int((span[0] >> 0) & 0x3f)
+ value_ = int.from_bytes(span[1:3], byteorder='little')
+ span = span[3:]
payload = span
span = bytes([])
fields['payload'] = payload
try:
- return DeviceResetCmd.parse(fields.copy(), payload)
+ return CoreDeviceResetCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return GetDeviceInfoCmd.parse(fields.copy(), payload)
+ return CoreDeviceResetRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return GetCapsInfoCmd.parse(fields.copy(), payload)
+ return CoreDeviceStatusNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SetConfigCmd.parse(fields.copy(), payload)
+ return CoreGetDeviceInfoCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return GetConfigCmd.parse(fields.copy(), payload)
+ return CoreGetDeviceInfoRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return CoreQueryTimeStampCmd.parse(fields.copy(), payload)
+ return CoreGetCapsInfoCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionInitCmd.parse(fields.copy(), payload)
+ return CoreGetCapsInfoRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionDeinitCmd.parse(fields.copy(), payload)
+ return CoreSetConfigCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionSetAppConfigCmd.parse(fields.copy(), payload)
+ return CoreSetConfigRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetAppConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetCountCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetStateCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateDtTagRangingRoundsCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateControllerMulticastListCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetHybridConfigCmd.parse(fields.copy(), payload)
+ return CoreGetConfigCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionQueryMaxDataSizeCmd.parse(fields.copy(), payload)
+ return CoreGetConfigRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionControlCommand.parse(fields.copy(), payload)
+ return CoreGenericErrorNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return AndroidGetPowerStatsCmd.parse(fields.copy(), payload)
+ return CoreQueryTimeStampCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return AndroidSetCountryCodeCmd.parse(fields.copy(), payload)
+ return CoreQueryTimeStampRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return UciCommand(**fields), span
+ return CorePacket(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
+ _span.append((self.oid << 0))
+ _span.extend([0] * 2)
_span.extend(payload or self.payload or [])
return ControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.payload)
+ return len(self.payload) + 3
@dataclass
-class UciResponse(ControlPacket):
-
+class SessionConfigPacket(ControlPacket):
+ oid: SessionConfigOpcodeId = field(kw_only=True, default=SessionConfigOpcodeId.INIT)
def __post_init__(self):
- self.mt = MessageType.RESPONSE
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciResponse', bytes]:
- if fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionConfigPacket', bytes]:
+ if fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
+ if len(span) < 3:
+ raise Exception('Invalid packet size')
+ fields['oid'] = SessionConfigOpcodeId.from_int((span[0] >> 0) & 0x3f)
+ value_ = int.from_bytes(span[1:3], byteorder='little')
+ span = span[3:]
payload = span
span = bytes([])
fields['payload'] = payload
try:
- return DeviceResetRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetDeviceInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetCapsInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return CoreQueryTimeStampRsp.parse(fields.copy(), payload)
+ return SessionInitCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
@@ -1291,92 +1431,11 @@ class UciResponse(ControlPacket):
except Exception as exn:
pass
try:
- return SessionDeinitRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetAppConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetAppConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetCountRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetStateRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateDtTagRangingRoundsRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionSetHybridConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateControllerMulticastListRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionQueryMaxDataSizeRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionStartRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionStopRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetRangingCountRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidGetPowerStatsRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidSetCountryCodeRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- return UciResponse(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return ControlPacket.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciNotification(ControlPacket):
-
-
- def __post_init__(self):
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciNotification', bytes]:
- if fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- try:
- return DeviceStatusNtf.parse(fields.copy(), payload)
+ return SessionDeinitCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return GenericError.parse(fields.copy(), payload)
+ return SessionDeinitRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
@@ -1384,277 +1443,47 @@ class UciNotification(ControlPacket):
except Exception as exn:
pass
try:
- return SessionUpdateControllerMulticastListNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return DataCreditNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return DataTransferStatusNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionInfoNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return AndroidRangeDiagnosticsNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- return UciNotification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return ControlPacket.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class CoreCommand(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.CORE
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['CoreCommand', bytes]:
- if fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- try:
- return DeviceResetCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetDeviceInfoCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetCapsInfoCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SetConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return CoreQueryTimeStampCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- return CoreCommand(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class CoreResponse(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.CORE
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['CoreResponse', bytes]:
- if fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- try:
- return DeviceResetRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetDeviceInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetCapsInfoRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GetConfigRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return CoreQueryTimeStampRsp.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- return CoreResponse(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class CoreNotification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.CORE
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['CoreNotification', bytes]:
- if fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- try:
- return DeviceStatusNtf.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return GenericError.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- return CoreNotification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class SessionConfigCommand(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.SESSION_CONFIG
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionConfigCommand', bytes]:
- if fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- try:
- return SessionInitCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionDeinitCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
return SessionSetAppConfigCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetAppConfigCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetCountCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionGetStateCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateDtTagRangingRoundsCmd.parse(fields.copy(), payload)
- except Exception as exn:
- pass
- try:
- return SessionUpdateControllerMulticastListCmd.parse(fields.copy(), payload)
+ return SessionSetAppConfigRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionSetHybridConfigCmd.parse(fields.copy(), payload)
+ return SessionGetAppConfigCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionQueryMaxDataSizeCmd.parse(fields.copy(), payload)
+ return SessionGetAppConfigRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionConfigCommand(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class SessionConfigResponse(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.SESSION_CONFIG
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionConfigResponse', bytes]:
- if fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
- return SessionInitRsp_V2.parse(fields.copy(), payload)
+ return SessionGetCountCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionInitRsp.parse(fields.copy(), payload)
+ return SessionGetCountRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionDeinitRsp.parse(fields.copy(), payload)
+ return SessionGetStateCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionSetAppConfigRsp.parse(fields.copy(), payload)
+ return SessionGetStateRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetAppConfigRsp.parse(fields.copy(), payload)
+ return SessionUpdateDtAnchorRangingRoundsCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetCountRsp.parse(fields.copy(), payload)
+ return SessionUpdateDtAnchorRangingRoundsRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetStateRsp.parse(fields.copy(), payload)
+ return SessionUpdateDtTagRangingRoundsCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
@@ -1662,7 +1491,7 @@ class SessionConfigResponse(UciResponse):
except Exception as exn:
pass
try:
- return SessionSetHybridConfigRsp.parse(fields.copy(), payload)
+ return SessionUpdateControllerMulticastListCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
@@ -1670,189 +1499,114 @@ class SessionConfigResponse(UciResponse):
except Exception as exn:
pass
try:
- return SessionQueryMaxDataSizeRsp.parse(fields.copy(), payload)
+ return SessionUpdateControllerMulticastListNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionConfigResponse(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class SessionConfigNotification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.SESSION_CONFIG
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionConfigNotification', bytes]:
- if fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
- return SessionStatusNtf.parse(fields.copy(), payload)
+ return SessionQueryMaxDataSizeInRangingCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionUpdateControllerMulticastListNtf.parse(fields.copy(), payload)
+ return SessionQueryMaxDataSizeInRangingRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionConfigNotification(**fields), span
+ return SessionConfigPacket(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
+ _span.append((self.oid << 0))
+ _span.extend([0] * 2)
_span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
+ return ControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.payload)
+ return len(self.payload) + 3
@dataclass
-class SessionControlCommand(UciCommand):
- session_id: int = field(kw_only=True, default=0)
+class SessionControlPacket(ControlPacket):
+ oid: SessionControlOpcodeId = field(kw_only=True, default=SessionControlOpcodeId.START)
def __post_init__(self):
self.gid = GroupId.SESSION_CONTROL
- self.mt = MessageType.COMMAND
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionControlCommand', bytes]:
- if fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionControlPacket', bytes]:
+ if fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
- if len(span) < 4:
+ if len(span) < 3:
raise Exception('Invalid packet size')
- value_ = int.from_bytes(span[0:4], byteorder='little')
- fields['session_id'] = value_
- span = span[4:]
+ fields['oid'] = SessionControlOpcodeId.from_int((span[0] >> 0) & 0x3f)
+ value_ = int.from_bytes(span[1:3], byteorder='little')
+ span = span[3:]
payload = span
span = bytes([])
fields['payload'] = payload
try:
- return SessionStartCmd.parse(fields.copy(), payload)
+ return SessionDataCreditNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionStopCmd.parse(fields.copy(), payload)
+ return SessionDataTransferStatusNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetRangingCountCmd.parse(fields.copy(), payload)
+ return SessionStartCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionControlCommand(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- if self.session_id > 4294967295:
- print(f"Invalid value for field SessionControlCommand::session_id: {self.session_id} > 4294967295; the value will be truncated")
- self.session_id &= 4294967295
- _span.extend(int.to_bytes((self.session_id << 0), length=4, byteorder='little'))
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload) + 4
-
-@dataclass
-class SessionControlResponse(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.SESSION_CONTROL
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionControlResponse', bytes]:
- if fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
return SessionStartRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionStopRsp.parse(fields.copy(), payload)
+ return SessionInfoNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionGetRangingCountRsp.parse(fields.copy(), payload)
+ return SessionStopCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionControlResponse(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class SessionControlNotification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.SESSION_CONTROL
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionControlNotification', bytes]:
- if fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
- return DataCreditNtf.parse(fields.copy(), payload)
+ return SessionStopRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return DataTransferStatusNtf.parse(fields.copy(), payload)
+ return SessionGetRangingCountCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
- return SessionInfoNtf.parse(fields.copy(), payload)
+ return SessionGetRangingCountRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return SessionControlNotification(**fields), span
+ return SessionControlPacket(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
+ _span.append((self.oid << 0))
+ _span.extend([0] * 2)
_span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
+ return ControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.payload)
+ return len(self.payload) + 3
@dataclass
-class AndroidCommand(UciCommand):
-
+class AndroidPacket(ControlPacket):
+ oid: AndroidOpcodeId = field(kw_only=True, default=AndroidOpcodeId.GET_POWER_STATS)
def __post_init__(self):
self.gid = GroupId.VENDOR_ANDROID
- self.mt = MessageType.COMMAND
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['AndroidCommand', bytes]:
- if fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['AndroidPacket', bytes]:
+ if fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
+ if len(span) < 3:
+ raise Exception('Invalid packet size')
+ fields['oid'] = AndroidOpcodeId.from_int((span[0] >> 0) & 0x3f)
+ value_ = int.from_bytes(span[1:3], byteorder='little')
+ span = span[3:]
payload = span
span = bytes([])
fields['payload'] = payload
@@ -1861,194 +1615,144 @@ class AndroidCommand(UciCommand):
except Exception as exn:
pass
try:
- return AndroidSetCountryCodeCmd.parse(fields.copy(), payload)
+ return AndroidGetPowerStatsRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return AndroidCommand(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class AndroidResponse(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_ANDROID
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['AndroidResponse', bytes]:
- if fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
- return AndroidGetPowerStatsRsp.parse(fields.copy(), payload)
+ return AndroidSetCountryCodeCmd.parse(fields.copy(), payload)
except Exception as exn:
pass
try:
return AndroidSetCountryCodeRsp.parse(fields.copy(), payload)
except Exception as exn:
pass
- return AndroidResponse(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class AndroidNotification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_ANDROID
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['AndroidNotification', bytes]:
- if fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
try:
return AndroidRangeDiagnosticsNtf.parse(fields.copy(), payload)
except Exception as exn:
pass
- return AndroidNotification(**fields), span
+ return AndroidPacket(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
+ _span.append((self.oid << 0))
+ _span.extend([0] * 2)
_span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
+ return ControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.payload)
+ return len(self.payload) + 3
@dataclass
-class DeviceResetCmd(CoreCommand):
+class CoreDeviceResetCmd(CorePacket):
reset_config: ResetConfig = field(kw_only=True, default=ResetConfig.UWBS_RESET)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.DEVICE_RESET
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['DeviceResetCmd', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreDeviceResetCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.DEVICE_RESET or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
fields['reset_config'] = ResetConfig.from_int(span[0])
span = span[1:]
- return DeviceResetCmd(**fields), span
+ return CoreDeviceResetCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.reset_config << 0))
- return CoreCommand.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class DeviceResetRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class CoreDeviceResetRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.DEVICE_RESET
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['DeviceResetRsp', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreDeviceResetRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.DEVICE_RESET or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
- return DeviceResetRsp(**fields), span
+ return CoreDeviceResetRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class DeviceStatusNtf(CoreNotification):
+class CoreDeviceStatusNtf(CorePacket):
device_state: DeviceState = field(kw_only=True, default=DeviceState.DEVICE_STATE_READY)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.CORE
self.mt = MessageType.NOTIFICATION
+ self.oid = CoreOpcodeId.DEVICE_STATUS
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['DeviceStatusNtf', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.NOTIFICATION:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreDeviceStatusNtf', bytes]:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != CoreOpcodeId.DEVICE_STATUS or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
fields['device_state'] = DeviceState.from_int(span[0])
span = span[1:]
- return DeviceStatusNtf(**fields), span
+ return CoreDeviceStatusNtf(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.device_state << 0))
- return CoreNotification.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class GetDeviceInfoCmd(CoreCommand):
+class CoreGetDeviceInfoCmd(CorePacket):
def __post_init__(self):
- self.opcode = 2
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.GET_DEVICE_INFO
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetDeviceInfoCmd', bytes]:
- if fields['opcode'] != 0x2 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetDeviceInfoCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.GET_DEVICE_INFO or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
- return GetDeviceInfoCmd(**fields), span
+ return CoreGetDeviceInfoCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return CoreCommand.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 0
@dataclass
-class GetDeviceInfoRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class CoreGetDeviceInfoRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
uci_version: int = field(kw_only=True, default=0)
mac_version: int = field(kw_only=True, default=0)
phy_version: int = field(kw_only=True, default=0)
@@ -2056,17 +1760,17 @@ class GetDeviceInfoRsp(CoreResponse):
vendor_spec_info: bytearray = field(kw_only=True, default_factory=bytearray)
def __post_init__(self):
- self.opcode = 2
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.GET_DEVICE_INFO
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetDeviceInfoRsp', bytes]:
- if fields['opcode'] != 0x2 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetDeviceInfoRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.GET_DEVICE_INFO or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 10:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
value_ = int.from_bytes(span[1:3], byteorder='little')
fields['uci_version'] = value_
value_ = int.from_bytes(span[3:5], byteorder='little')
@@ -2081,56 +1785,56 @@ class GetDeviceInfoRsp(CoreResponse):
raise Exception('Invalid packet size')
fields['vendor_spec_info'] = list(span[:vendor_spec_info_count])
span = span[vendor_spec_info_count:]
- return GetDeviceInfoRsp(**fields), span
+ return CoreGetDeviceInfoRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
if self.uci_version > 65535:
- print(f"Invalid value for field GetDeviceInfoRsp::uci_version: {self.uci_version} > 65535; the value will be truncated")
+ print(f"Invalid value for field CoreGetDeviceInfoRsp::uci_version: {self.uci_version} > 65535; the value will be truncated")
self.uci_version &= 65535
_span.extend(int.to_bytes((self.uci_version << 0), length=2, byteorder='little'))
if self.mac_version > 65535:
- print(f"Invalid value for field GetDeviceInfoRsp::mac_version: {self.mac_version} > 65535; the value will be truncated")
+ print(f"Invalid value for field CoreGetDeviceInfoRsp::mac_version: {self.mac_version} > 65535; the value will be truncated")
self.mac_version &= 65535
_span.extend(int.to_bytes((self.mac_version << 0), length=2, byteorder='little'))
if self.phy_version > 65535:
- print(f"Invalid value for field GetDeviceInfoRsp::phy_version: {self.phy_version} > 65535; the value will be truncated")
+ print(f"Invalid value for field CoreGetDeviceInfoRsp::phy_version: {self.phy_version} > 65535; the value will be truncated")
self.phy_version &= 65535
_span.extend(int.to_bytes((self.phy_version << 0), length=2, byteorder='little'))
if self.uci_test_version > 65535:
- print(f"Invalid value for field GetDeviceInfoRsp::uci_test_version: {self.uci_test_version} > 65535; the value will be truncated")
+ print(f"Invalid value for field CoreGetDeviceInfoRsp::uci_test_version: {self.uci_test_version} > 65535; the value will be truncated")
self.uci_test_version &= 65535
_span.extend(int.to_bytes((self.uci_test_version << 0), length=2, byteorder='little'))
if len(self.vendor_spec_info) > 255:
- print(f"Invalid length for field GetDeviceInfoRsp::vendor_spec_info: {len(self.vendor_spec_info)} > 255; the array will be truncated")
+ print(f"Invalid length for field CoreGetDeviceInfoRsp::vendor_spec_info: {len(self.vendor_spec_info)} > 255; the array will be truncated")
del self.vendor_spec_info[255:]
_span.append((len(self.vendor_spec_info) << 0))
_span.extend(self.vendor_spec_info)
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return len(self.vendor_spec_info) * 1 + 10
@dataclass
-class GetCapsInfoCmd(CoreCommand):
+class CoreGetCapsInfoCmd(CorePacket):
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.GET_CAPS_INFO
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetCapsInfoCmd', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetCapsInfoCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.GET_CAPS_INFO or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
- return GetCapsInfoCmd(**fields), span
+ return CoreGetCapsInfoCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return CoreCommand.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -2173,22 +1877,22 @@ class CapTlv(Packet):
return len(self.v) * 1 + 2
@dataclass
-class GetCapsInfoRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class CoreGetCapsInfoRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
tlvs: List[CapTlv] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.GET_CAPS_INFO
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetCapsInfoRsp', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetCapsInfoRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.GET_CAPS_INFO or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
tlvs_count = span[1]
span = span[2:]
tlvs = []
@@ -2196,118 +1900,127 @@ class GetCapsInfoRsp(CoreResponse):
element, span = CapTlv.parse(span)
tlvs.append(element)
fields['tlvs'] = tlvs
- return GetCapsInfoRsp(**fields), span
+ return CoreGetCapsInfoRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
if len(self.tlvs) > 255:
- print(f"Invalid length for field GetCapsInfoRsp::tlvs: {len(self.tlvs)} > 255; the array will be truncated")
+ print(f"Invalid length for field CoreGetCapsInfoRsp::tlvs: {len(self.tlvs)} > 255; the array will be truncated")
del self.tlvs[255:]
_span.append((len(self.tlvs) << 0))
for _elt in self.tlvs:
_span.extend(_elt.serialize())
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return sum([elt.size for elt in self.tlvs]) + 2
+class ConfigParameterId(enum.IntEnum):
+ DEVICE_STATE = 0x0
+ LOW_POWER_MODE = 0x1
+
+ @staticmethod
+ def from_int(v: int) -> Union[int, 'ConfigParameterId']:
+ try:
+ return ConfigParameterId(v)
+ except ValueError as exn:
+ return v
+
+
@dataclass
-class DeviceConfigTlv(Packet):
- cfg_id: DeviceConfigId = field(kw_only=True, default=DeviceConfigId.DEVICE_STATE)
- v: bytearray = field(kw_only=True, default_factory=bytearray)
+class ConfigParameter(Packet):
+ id: ConfigParameterId = field(kw_only=True, default=ConfigParameterId.DEVICE_STATE)
+ value: bytearray = field(kw_only=True, default_factory=bytearray)
def __post_init__(self):
pass
@staticmethod
- def parse(span: bytes) -> Tuple['DeviceConfigTlv', bytes]:
+ def parse(span: bytes) -> Tuple['ConfigParameter', bytes]:
fields = {'payload': None}
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['cfg_id'] = DeviceConfigId.from_int(span[0])
- v_count = span[1]
+ fields['id'] = ConfigParameterId.from_int(span[0])
+ value_size = span[1]
span = span[2:]
- if len(span) < v_count:
+ if len(span) < value_size:
raise Exception('Invalid packet size')
- fields['v'] = list(span[:v_count])
- span = span[v_count:]
- return DeviceConfigTlv(**fields), span
+ fields['value'] = list(span[:value_size])
+ span = span[value_size:]
+ return ConfigParameter(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- _span.append((self.cfg_id << 0))
- if len(self.v) > 255:
- print(f"Invalid length for field DeviceConfigTlv::v: {len(self.v)} > 255; the array will be truncated")
- del self.v[255:]
- _span.append((len(self.v) << 0))
- _span.extend(self.v)
+ _span.append((self.id << 0))
+ _span.append(((len(self.value) * 1) << 0))
+ _span.extend(self.value)
return bytes(_span)
@property
def size(self) -> int:
- return len(self.v) * 1 + 2
+ return len(self.value) * 1 + 2
@dataclass
-class SetConfigCmd(CoreCommand):
- tlvs: List[DeviceConfigTlv] = field(kw_only=True, default_factory=list)
+class CoreSetConfigCmd(CorePacket):
+ parameters: List[ConfigParameter] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 4
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.SET_CONFIG
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SetConfigCmd', bytes]:
- if fields['opcode'] != 0x4 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreSetConfigCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.SET_CONFIG or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- tlvs_count = span[0]
+ parameters_count = span[0]
span = span[1:]
- tlvs = []
- for n in range(tlvs_count):
- element, span = DeviceConfigTlv.parse(span)
- tlvs.append(element)
- fields['tlvs'] = tlvs
- return SetConfigCmd(**fields), span
+ parameters = []
+ for n in range(parameters_count):
+ element, span = ConfigParameter.parse(span)
+ parameters.append(element)
+ fields['parameters'] = parameters
+ return CoreSetConfigCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- if len(self.tlvs) > 255:
- print(f"Invalid length for field SetConfigCmd::tlvs: {len(self.tlvs)} > 255; the array will be truncated")
- del self.tlvs[255:]
- _span.append((len(self.tlvs) << 0))
- for _elt in self.tlvs:
+ if len(self.parameters) > 255:
+ print(f"Invalid length for field CoreSetConfigCmd::parameters: {len(self.parameters)} > 255; the array will be truncated")
+ del self.parameters[255:]
+ _span.append((len(self.parameters) << 0))
+ for _elt in self.parameters:
_span.extend(_elt.serialize())
- return CoreCommand.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return sum([elt.size for elt in self.tlvs]) + 1
+ return sum([elt.size for elt in self.parameters]) + 1
@dataclass
-class DeviceConfigStatus(Packet):
- cfg_id: DeviceConfigId = field(kw_only=True, default=DeviceConfigId.DEVICE_STATE)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class ConfigParameterStatus(Packet):
+ id: ConfigParameterId = field(kw_only=True, default=ConfigParameterId.DEVICE_STATE)
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
pass
@staticmethod
- def parse(span: bytes) -> Tuple['DeviceConfigStatus', bytes]:
+ def parse(span: bytes) -> Tuple['ConfigParameterStatus', bytes]:
fields = {'payload': None}
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['cfg_id'] = DeviceConfigId.from_int(span[0])
- fields['status'] = StatusCode.from_int(span[1])
+ fields['id'] = ConfigParameterId.from_int(span[0])
+ fields['status'] = Status.from_int(span[1])
span = span[2:]
- return DeviceConfigStatus(**fields), span
+ return ConfigParameterStatus(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- _span.append((self.cfg_id << 0))
+ _span.append((self.id << 0))
_span.append((self.status << 0))
return bytes(_span)
@@ -2316,193 +2029,197 @@ class DeviceConfigStatus(Packet):
return 2
@dataclass
-class SetConfigRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
- cfg_status: List[DeviceConfigStatus] = field(kw_only=True, default_factory=list)
+class CoreSetConfigRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
+ parameters: List[ConfigParameterStatus] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 4
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.SET_CONFIG
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SetConfigRsp', bytes]:
- if fields['opcode'] != 0x4 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreSetConfigRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.SET_CONFIG or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
- cfg_status_count = span[1]
+ fields['status'] = Status.from_int(span[0])
+ parameters_count = span[1]
span = span[2:]
- if len(span) < cfg_status_count * 2:
+ if len(span) < parameters_count * 2:
raise Exception('Invalid packet size')
- cfg_status = []
- for n in range(cfg_status_count):
- cfg_status.append(DeviceConfigStatus.parse_all(span[n * 2:(n + 1) * 2]))
- fields['cfg_status'] = cfg_status
- span = span[cfg_status_count * 2:]
- return SetConfigRsp(**fields), span
+ parameters = []
+ for n in range(parameters_count):
+ parameters.append(ConfigParameterStatus.parse_all(span[n * 2:(n + 1) * 2]))
+ fields['parameters'] = parameters
+ span = span[parameters_count * 2:]
+ return CoreSetConfigRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- if len(self.cfg_status) > 255:
- print(f"Invalid length for field SetConfigRsp::cfg_status: {len(self.cfg_status)} > 255; the array will be truncated")
- del self.cfg_status[255:]
- _span.append((len(self.cfg_status) << 0))
- for _elt in self.cfg_status:
+ if len(self.parameters) > 255:
+ print(f"Invalid length for field CoreSetConfigRsp::parameters: {len(self.parameters)} > 255; the array will be truncated")
+ del self.parameters[255:]
+ _span.append((len(self.parameters) << 0))
+ for _elt in self.parameters:
_span.extend(_elt.serialize())
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return sum([elt.size for elt in self.cfg_status]) + 2
+ return sum([elt.size for elt in self.parameters]) + 2
@dataclass
-class GetConfigCmd(CoreCommand):
- cfg_id: bytearray = field(kw_only=True, default_factory=bytearray)
+class CoreGetConfigCmd(CorePacket):
+ parameter_ids: List[ConfigParameterId] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 5
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.GET_CONFIG
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetConfigCmd', bytes]:
- if fields['opcode'] != 0x5 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetConfigCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.GET_CONFIG or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- cfg_id_count = span[0]
+ parameter_ids_count = span[0]
span = span[1:]
- if len(span) < cfg_id_count:
+ if len(span) < parameter_ids_count:
raise Exception('Invalid packet size')
- fields['cfg_id'] = list(span[:cfg_id_count])
- span = span[cfg_id_count:]
- return GetConfigCmd(**fields), span
+ parameter_ids = []
+ for n in range(parameter_ids_count):
+ parameter_ids.append(ConfigParameterId(int.from_bytes(span[n:n + 1], byteorder='little')))
+ fields['parameter_ids'] = parameter_ids
+ span = span[parameter_ids_count:]
+ return CoreGetConfigCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- if len(self.cfg_id) > 255:
- print(f"Invalid length for field GetConfigCmd::cfg_id: {len(self.cfg_id)} > 255; the array will be truncated")
- del self.cfg_id[255:]
- _span.append((len(self.cfg_id) << 0))
- _span.extend(self.cfg_id)
- return CoreCommand.serialize(self, payload = bytes(_span))
+ if len(self.parameter_ids) > 255:
+ print(f"Invalid length for field CoreGetConfigCmd::parameter_ids: {len(self.parameter_ids)} > 255; the array will be truncated")
+ del self.parameter_ids[255:]
+ _span.append((len(self.parameter_ids) << 0))
+ for _elt in self.parameter_ids:
+ _span.append(_elt)
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return len(self.cfg_id) * 1 + 1
+ return len(self.parameter_ids) * 8 + 1
@dataclass
-class GetConfigRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
- tlvs: List[DeviceConfigTlv] = field(kw_only=True, default_factory=list)
+class CoreGetConfigRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
+ parameters: List[ConfigParameter] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 5
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.GET_CONFIG
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GetConfigRsp', bytes]:
- if fields['opcode'] != 0x5 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGetConfigRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.GET_CONFIG or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
- tlvs_count = span[1]
+ fields['status'] = Status.from_int(span[0])
+ parameters_count = span[1]
span = span[2:]
- tlvs = []
- for n in range(tlvs_count):
- element, span = DeviceConfigTlv.parse(span)
- tlvs.append(element)
- fields['tlvs'] = tlvs
- return GetConfigRsp(**fields), span
+ parameters = []
+ for n in range(parameters_count):
+ element, span = ConfigParameter.parse(span)
+ parameters.append(element)
+ fields['parameters'] = parameters
+ return CoreGetConfigRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- if len(self.tlvs) > 255:
- print(f"Invalid length for field GetConfigRsp::tlvs: {len(self.tlvs)} > 255; the array will be truncated")
- del self.tlvs[255:]
- _span.append((len(self.tlvs) << 0))
- for _elt in self.tlvs:
+ if len(self.parameters) > 255:
+ print(f"Invalid length for field CoreGetConfigRsp::parameters: {len(self.parameters)} > 255; the array will be truncated")
+ del self.parameters[255:]
+ _span.append((len(self.parameters) << 0))
+ for _elt in self.parameters:
_span.extend(_elt.serialize())
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return sum([elt.size for elt in self.tlvs]) + 2
+ return sum([elt.size for elt in self.parameters]) + 2
@dataclass
-class GenericError(CoreNotification):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class CoreGenericErrorNtf(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 7
- self.gid = GroupId.CORE
self.mt = MessageType.NOTIFICATION
+ self.oid = CoreOpcodeId.GENERIC_ERROR
+ self.gid = GroupId.CORE
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['GenericError', bytes]:
- if fields['opcode'] != 0x7 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.NOTIFICATION:
+ def parse(fields: dict, span: bytes) -> Tuple['CoreGenericErrorNtf', bytes]:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != CoreOpcodeId.GENERIC_ERROR or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
- return GenericError(**fields), span
+ return CoreGenericErrorNtf(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return CoreNotification.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class CoreQueryTimeStampCmd(CoreCommand):
+class CoreQueryTimeStampCmd(CorePacket):
def __post_init__(self):
- self.opcode = 8
- self.gid = GroupId.CORE
self.mt = MessageType.COMMAND
+ self.oid = CoreOpcodeId.QUERY_UWBS_TIMESTAMP
+ self.gid = GroupId.CORE
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['CoreQueryTimeStampCmd', bytes]:
- if fields['opcode'] != 0x8 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != CoreOpcodeId.QUERY_UWBS_TIMESTAMP or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
return CoreQueryTimeStampCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return CoreCommand.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 0
@dataclass
-class CoreQueryTimeStampRsp(CoreResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class CoreQueryTimeStampRsp(CorePacket):
+ status: Status = field(kw_only=True, default=Status.OK)
timeStamp: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 8
- self.gid = GroupId.CORE
self.mt = MessageType.RESPONSE
+ self.oid = CoreOpcodeId.QUERY_UWBS_TIMESTAMP
+ self.gid = GroupId.CORE
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['CoreQueryTimeStampRsp', bytes]:
- if fields['opcode'] != 0x8 or fields['gid'] != GroupId.CORE or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != CoreOpcodeId.QUERY_UWBS_TIMESTAMP or fields['gid'] != GroupId.CORE:
raise Exception("Invalid constraint field values")
if len(span) < 9:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
value_ = int.from_bytes(span[1:9], byteorder='little')
fields['timeStamp'] = value_
span = span[9:]
@@ -2515,25 +2232,25 @@ class CoreQueryTimeStampRsp(CoreResponse):
print(f"Invalid value for field CoreQueryTimeStampRsp::timeStamp: {self.timeStamp} > 18446744073709551615; the value will be truncated")
self.timeStamp &= 18446744073709551615
_span.extend(int.to_bytes((self.timeStamp << 0), length=8, byteorder='little'))
- return CoreResponse.serialize(self, payload = bytes(_span))
+ return CorePacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 9
@dataclass
-class SessionInitCmd(SessionConfigCommand):
+class SessionInitCmd(SessionConfigPacket):
session_id: int = field(kw_only=True, default=0)
session_type: SessionType = field(kw_only=True, default=SessionType.FIRA_RANGING_SESSION)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.INIT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionInitCmd', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.INIT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -2550,29 +2267,29 @@ class SessionInitCmd(SessionConfigCommand):
self.session_id &= 4294967295
_span.extend(int.to_bytes((self.session_id << 0), length=4, byteorder='little'))
_span.append((self.session_type << 0))
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 5
@dataclass
-class SessionInitRsp_V2(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionInitRsp_V2(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
session_handle: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.INIT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionInitRsp_V2', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.INIT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
value_ = int.from_bytes(span[1:5], byteorder='little')
fields['session_handle'] = value_
span = span[5:]
@@ -2585,52 +2302,52 @@ class SessionInitRsp_V2(SessionConfigResponse):
print(f"Invalid value for field SessionInitRsp_V2::session_handle: {self.session_handle} > 4294967295; the value will be truncated")
self.session_handle &= 4294967295
_span.extend(int.to_bytes((self.session_handle << 0), length=4, byteorder='little'))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 5
@dataclass
-class SessionInitRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionInitRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.INIT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionInitRsp', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.INIT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return SessionInitRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class SessionDeinitCmd(SessionConfigCommand):
+class SessionDeinitCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.DEINIT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionDeinitCmd', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.DEINIT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 4:
raise Exception('Invalid packet size')
@@ -2645,54 +2362,54 @@ class SessionDeinitCmd(SessionConfigCommand):
print(f"Invalid value for field SessionDeinitCmd::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 4
@dataclass
-class SessionDeinitRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionDeinitRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.DEINIT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionDeinitRsp', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.DEINIT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return SessionDeinitRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class SessionStatusNtf(SessionConfigNotification):
+class SessionStatusNtf(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
session_state: SessionState = field(kw_only=True, default=SessionState.SESSION_STATE_INIT)
reason_code: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 2
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionConfigOpcodeId.STATUS
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionStatusNtf', bytes]:
- if fields['opcode'] != 0x2 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionConfigOpcodeId.STATUS or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 6:
raise Exception('Invalid packet size')
@@ -2714,7 +2431,7 @@ class SessionStatusNtf(SessionConfigNotification):
print(f"Invalid value for field SessionStatusNtf::reason_code: {self.reason_code} > 255; the value will be truncated")
self.reason_code &= 255
_span.append((self.reason_code << 0))
- return SessionConfigNotification.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -2757,18 +2474,18 @@ class AppConfigTlv(Packet):
return len(self.v) * 1 + 2
@dataclass
-class SessionSetAppConfigCmd(SessionConfigCommand):
+class SessionSetAppConfigCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
tlvs: List[AppConfigTlv] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.SET_APP_CONFIG
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionSetAppConfigCmd', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.SET_APP_CONFIG or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -2795,7 +2512,7 @@ class SessionSetAppConfigCmd(SessionConfigCommand):
_span.append((len(self.tlvs) << 0))
for _elt in self.tlvs:
_span.extend(_elt.serialize())
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -2804,7 +2521,7 @@ class SessionSetAppConfigCmd(SessionConfigCommand):
@dataclass
class AppConfigStatus(Packet):
cfg_id: AppConfigTlvType = field(kw_only=True, default=AppConfigTlvType.DEVICE_TYPE)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
pass
@@ -2815,7 +2532,7 @@ class AppConfigStatus(Packet):
if len(span) < 2:
raise Exception('Invalid packet size')
fields['cfg_id'] = AppConfigTlvType.from_int(span[0])
- fields['status'] = StatusCode.from_int(span[1])
+ fields['status'] = Status.from_int(span[1])
span = span[2:]
return AppConfigStatus(**fields), span
@@ -2830,22 +2547,22 @@ class AppConfigStatus(Packet):
return 2
@dataclass
-class SessionSetAppConfigRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionSetAppConfigRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
cfg_status: List[AppConfigStatus] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.SET_APP_CONFIG
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionSetAppConfigRsp', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.SET_APP_CONFIG or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
cfg_status_count = span[1]
span = span[2:]
if len(span) < cfg_status_count * 2:
@@ -2866,25 +2583,25 @@ class SessionSetAppConfigRsp(SessionConfigResponse):
_span.append((len(self.cfg_status) << 0))
for _elt in self.cfg_status:
_span.extend(_elt.serialize())
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return sum([elt.size for elt in self.cfg_status]) + 2
@dataclass
-class SessionGetAppConfigCmd(SessionConfigCommand):
+class SessionGetAppConfigCmd(SessionConfigPacket):
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
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.GET_APP_CONFIG
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetAppConfigCmd', bytes]:
- if fields['opcode'] != 0x4 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.GET_APP_CONFIG or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -2894,7 +2611,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,30 +2628,31 @@ 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)
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ for _elt in self.app_cfg:
+ _span.append(_elt)
+ return SessionConfigPacket.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):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionGetAppConfigRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
tlvs: List[AppConfigTlv] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 4
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.GET_APP_CONFIG
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetAppConfigRsp', bytes]:
- if fields['opcode'] != 0x4 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.GET_APP_CONFIG or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
tlvs_count = span[1]
span = span[2:]
tlvs = []
@@ -2950,52 +2671,52 @@ class SessionGetAppConfigRsp(SessionConfigResponse):
_span.append((len(self.tlvs) << 0))
for _elt in self.tlvs:
_span.extend(_elt.serialize())
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return sum([elt.size for elt in self.tlvs]) + 2
@dataclass
-class SessionGetCountCmd(SessionConfigCommand):
+class SessionGetCountCmd(SessionConfigPacket):
def __post_init__(self):
- self.opcode = 5
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.GET_COUNT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetCountCmd', bytes]:
- if fields['opcode'] != 0x5 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.GET_COUNT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
return SessionGetCountCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 0
@dataclass
-class SessionGetCountRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionGetCountRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
session_count: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 5
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.GET_COUNT
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetCountRsp', bytes]:
- if fields['opcode'] != 0x5 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.GET_COUNT or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
fields['session_count'] = span[1]
span = span[2:]
return SessionGetCountRsp(**fields), span
@@ -3007,24 +2728,24 @@ class SessionGetCountRsp(SessionConfigResponse):
print(f"Invalid value for field SessionGetCountRsp::session_count: {self.session_count} > 255; the value will be truncated")
self.session_count &= 255
_span.append((self.session_count << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 2
@dataclass
-class SessionGetStateCmd(SessionConfigCommand):
+class SessionGetStateCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 6
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.GET_STATE
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetStateCmd', bytes]:
- if fields['opcode'] != 0x6 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.GET_STATE or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 4:
raise Exception('Invalid packet size')
@@ -3039,29 +2760,29 @@ class SessionGetStateCmd(SessionConfigCommand):
print(f"Invalid value for field SessionGetStateCmd::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 4
@dataclass
-class SessionGetStateRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionGetStateRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
session_state: SessionState = field(kw_only=True, default=SessionState.SESSION_STATE_INIT)
def __post_init__(self):
- self.opcode = 6
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.GET_STATE
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetStateRsp', bytes]:
- if fields['opcode'] != 0x6 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.GET_STATE or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
fields['session_state'] = SessionState.from_int(span[1])
span = span[2:]
return SessionGetStateRsp(**fields), span
@@ -3070,25 +2791,71 @@ class SessionGetStateRsp(SessionConfigResponse):
_span = bytearray()
_span.append((self.status << 0))
_span.append((self.session_state << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 2
@dataclass
-class SessionUpdateDtTagRangingRoundsCmd(SessionConfigCommand):
+class SessionUpdateDtAnchorRangingRoundsCmd(SessionConfigPacket):
+
+
+ def __post_init__(self):
+ self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.UPDATE_DT_ANCHOR_RANGING_ROUNDS
+ self.gid = GroupId.SESSION_CONFIG
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateDtAnchorRangingRoundsCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.UPDATE_DT_ANCHOR_RANGING_ROUNDS or fields['gid'] != GroupId.SESSION_CONFIG:
+ raise Exception("Invalid constraint field values")
+ return SessionUpdateDtAnchorRangingRoundsCmd(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+@dataclass
+class SessionUpdateDtAnchorRangingRoundsRsp(SessionConfigPacket):
+
+
+ def __post_init__(self):
+ self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.UPDATE_DT_ANCHOR_RANGING_ROUNDS
+ self.gid = GroupId.SESSION_CONFIG
+
+ @staticmethod
+ def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateDtAnchorRangingRoundsRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.UPDATE_DT_ANCHOR_RANGING_ROUNDS or fields['gid'] != GroupId.SESSION_CONFIG:
+ raise Exception("Invalid constraint field values")
+ return SessionUpdateDtAnchorRangingRoundsRsp(**fields), span
+
+ def serialize(self, payload: bytes = None) -> bytes:
+ _span = bytearray()
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
+
+ @property
+ def size(self) -> int:
+ return 0
+
+@dataclass
+class SessionUpdateDtTagRangingRoundsCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
ranging_round_indexes: bytearray = field(kw_only=True, default_factory=bytearray)
def __post_init__(self):
- self.opcode = 9
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.UPDATE_DT_TAG_RANGING_ROUNDS
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateDtTagRangingRoundsCmd', bytes]:
- if fields['opcode'] != 0x9 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.UPDATE_DT_TAG_RANGING_ROUNDS or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -3113,29 +2880,29 @@ class SessionUpdateDtTagRangingRoundsCmd(SessionConfigCommand):
del self.ranging_round_indexes[255:]
_span.append((len(self.ranging_round_indexes) << 0))
_span.extend(self.ranging_round_indexes)
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return len(self.ranging_round_indexes) * 1 + 5
@dataclass
-class SessionUpdateDtTagRangingRoundsRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionUpdateDtTagRangingRoundsRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
ranging_round_indexes: bytearray = field(kw_only=True, default_factory=bytearray)
def __post_init__(self):
- self.opcode = 9
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.UPDATE_DT_TAG_RANGING_ROUNDS
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateDtTagRangingRoundsRsp', bytes]:
- if fields['opcode'] != 0x9 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.UPDATE_DT_TAG_RANGING_ROUNDS or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
ranging_round_indexes_count = span[1]
span = span[2:]
if len(span) < ranging_round_indexes_count:
@@ -3152,7 +2919,7 @@ class SessionUpdateDtTagRangingRoundsRsp(SessionConfigResponse):
del self.ranging_round_indexes[255:]
_span.append((len(self.ranging_round_indexes) << 0))
_span.extend(self.ranging_round_indexes)
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -3279,7 +3046,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']:
@@ -3290,18 +3057,18 @@ class UpdateMulticastListAction(enum.IntEnum):
@dataclass
-class SessionUpdateControllerMulticastListCmd(SessionConfigCommand):
+class SessionUpdateControllerMulticastListCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
action: UpdateMulticastListAction = field(kw_only=True, default=UpdateMulticastListAction.ADD_CONTROLEE)
def __post_init__(self):
- self.opcode = 7
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateControllerMulticastListCmd', bytes]:
- if fields['opcode'] != 0x7 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -3322,139 +3089,13 @@ class SessionUpdateControllerMulticastListCmd(SessionConfigCommand):
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
_span.append((self.action << 0))
_span.extend(payload or self.payload or [])
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return len(self.payload) + 5
@dataclass
-class PhaseList(Packet):
- session_token: int = field(kw_only=True, default=0)
- start_slot_index: int = field(kw_only=True, default=0)
- end_slot_index: int = field(kw_only=True, default=0)
-
- def __post_init__(self):
- pass
-
- @staticmethod
- def parse(span: bytes) -> Tuple['PhaseList', bytes]:
- fields = {'payload': None}
- if len(span) < 8:
- raise Exception('Invalid packet size')
- value_ = int.from_bytes(span[0:4], byteorder='little')
- fields['session_token'] = value_
- value_ = int.from_bytes(span[4:6], byteorder='little')
- fields['start_slot_index'] = value_
- value_ = int.from_bytes(span[6:8], byteorder='little')
- fields['end_slot_index'] = value_
- span = span[8:]
- return PhaseList(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- if self.session_token > 4294967295:
- print(f"Invalid value for field PhaseList::session_token: {self.session_token} > 4294967295; the value will be truncated")
- self.session_token &= 4294967295
- _span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
- if self.start_slot_index > 65535:
- print(f"Invalid value for field PhaseList::start_slot_index: {self.start_slot_index} > 65535; the value will be truncated")
- self.start_slot_index &= 65535
- _span.extend(int.to_bytes((self.start_slot_index << 0), length=2, byteorder='little'))
- if self.end_slot_index > 65535:
- print(f"Invalid value for field PhaseList::end_slot_index: {self.end_slot_index} > 65535; the value will be truncated")
- self.end_slot_index &= 65535
- _span.extend(int.to_bytes((self.end_slot_index << 0), length=2, byteorder='little'))
- return bytes(_span)
-
- @property
- def size(self) -> int:
- return 8
-
-@dataclass
-class SessionSetHybridConfigCmd(SessionConfigCommand):
- session_token: int = field(kw_only=True, default=0)
- number_of_phases: int = field(kw_only=True, default=0)
- update_time: bytearray = field(kw_only=True, default_factory=bytearray)
- phase_list: List[PhaseList] = field(kw_only=True, default_factory=list)
-
- def __post_init__(self):
- self.opcode = 12
- self.gid = GroupId.SESSION_CONFIG
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionSetHybridConfigCmd', bytes]:
- if fields['opcode'] != 0xc or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- if len(span) < 5:
- raise Exception('Invalid packet size')
- value_ = int.from_bytes(span[0:4], byteorder='little')
- fields['session_token'] = value_
- fields['number_of_phases'] = span[4]
- span = span[5:]
- if len(span) < 8:
- raise Exception('Invalid packet size')
- fields['update_time'] = list(span[:8])
- span = span[8:]
- if len(span) % 8 != 0:
- raise Exception('Array size is not a multiple of the element size')
- phase_list_count = int(len(span) / 8)
- phase_list = []
- for n in range(phase_list_count):
- phase_list.append(PhaseList.parse_all(span[n * 8:(n + 1) * 8]))
- fields['phase_list'] = phase_list
- span = bytes()
- return SessionSetHybridConfigCmd(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- if self.session_token > 4294967295:
- print(f"Invalid value for field SessionSetHybridConfigCmd::session_token: {self.session_token} > 4294967295; the value will be truncated")
- self.session_token &= 4294967295
- _span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
- if self.number_of_phases > 255:
- print(f"Invalid value for field SessionSetHybridConfigCmd::number_of_phases: {self.number_of_phases} > 255; the value will be truncated")
- self.number_of_phases &= 255
- _span.append((self.number_of_phases << 0))
- _span.extend(self.update_time)
- for _elt in self.phase_list:
- _span.extend(_elt.serialize())
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return sum([elt.size for elt in self.phase_list]) + 13
-
-@dataclass
-class SessionSetHybridConfigRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
-
- def __post_init__(self):
- self.opcode = 12
- self.gid = GroupId.SESSION_CONFIG
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionSetHybridConfigRsp', bytes]:
- if fields['opcode'] != 0xc or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- if len(span) < 1:
- raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
- span = span[1:]
- return SessionSetHybridConfigRsp(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.append((self.status << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return 1
-
-@dataclass
class SessionUpdateControllerMulticastListCmdPayload(Packet):
controlees: List[Controlee] = field(kw_only=True, default_factory=list)
@@ -3566,28 +3207,28 @@ class SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload(Packet):
return sum([elt.size for elt in self.controlees]) + 1
@dataclass
-class SessionUpdateControllerMulticastListRsp(SessionConfigResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionUpdateControllerMulticastListRsp(SessionConfigPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 7
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateControllerMulticastListRsp', bytes]:
- if fields['opcode'] != 0x7 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return SessionUpdateControllerMulticastListRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -3597,7 +3238,7 @@ class SessionUpdateControllerMulticastListRsp(SessionConfigResponse):
class ControleeStatus(Packet):
mac_address: bytearray = field(kw_only=True, default_factory=bytearray)
subsession_id: int = field(kw_only=True, default=0)
- status: MulticastUpdateStatusCode = field(kw_only=True, default=MulticastUpdateStatusCode.STATUS_OK_MULTICAST_LIST_UPDATE)
+ status: MulticastUpdateStatus = field(kw_only=True, default=MulticastUpdateStatus.OK_MULTICAST_LIST_UPDATE)
def __post_init__(self):
pass
@@ -3613,7 +3254,7 @@ class ControleeStatus(Packet):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:4], byteorder='little')
fields['subsession_id'] = value_
- fields['status'] = MulticastUpdateStatusCode.from_int(span[4])
+ fields['status'] = MulticastUpdateStatus.from_int(span[4])
span = span[5:]
return ControleeStatus(**fields), span
@@ -3632,19 +3273,19 @@ class ControleeStatus(Packet):
return 7
@dataclass
-class SessionUpdateControllerMulticastListNtf(SessionConfigNotification):
+class SessionUpdateControllerMulticastListNtf(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
remaining_multicast_list_size: int = field(kw_only=True, default=0)
controlee_status: List[ControleeStatus] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 7
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionUpdateControllerMulticastListNtf', bytes]:
- if fields['opcode'] != 0x7 or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionConfigOpcodeId.UPDATE_CONTROLLER_MULTICAST_LIST or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 6:
raise Exception('Invalid packet size')
@@ -3678,25 +3319,25 @@ class SessionUpdateControllerMulticastListNtf(SessionConfigNotification):
_span.append((len(self.controlee_status) << 0))
for _elt in self.controlee_status:
_span.extend(_elt.serialize())
- return SessionConfigNotification.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return sum([elt.size for elt in self.controlee_status]) + 6
@dataclass
-class DataCreditNtf(SessionControlNotification):
+class SessionDataCreditNtf(SessionControlPacket):
session_token: int = field(kw_only=True, default=0)
credit_availability: CreditAvailability = field(kw_only=True, default=CreditAvailability.CREDIT_NOT_AVAILABLE)
def __post_init__(self):
- self.opcode = 4
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.DATA_CREDIT
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['DataCreditNtf', bytes]:
- if fields['opcode'] != 0x4 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionDataCreditNtf', bytes]:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.DATA_CREDIT or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
@@ -3704,36 +3345,36 @@ class DataCreditNtf(SessionControlNotification):
fields['session_token'] = value_
fields['credit_availability'] = CreditAvailability.from_int(span[4])
span = span[5:]
- return DataCreditNtf(**fields), span
+ return SessionDataCreditNtf(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
if self.session_token > 4294967295:
- print(f"Invalid value for field DataCreditNtf::session_token: {self.session_token} > 4294967295; the value will be truncated")
+ print(f"Invalid value for field SessionDataCreditNtf::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
_span.append((self.credit_availability << 0))
- return SessionControlNotification.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 5
@dataclass
-class DataTransferStatusNtf(SessionControlNotification):
+class SessionDataTransferStatusNtf(SessionControlPacket):
session_token: int = field(kw_only=True, default=0)
uci_sequence_number: int = field(kw_only=True, default=0)
status: DataTransferNtfStatusCode = field(kw_only=True, default=DataTransferNtfStatusCode.UCI_DATA_TRANSFER_STATUS_REPETITION_OK)
tx_count: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 5
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.DATA_TRANSFER_STATUS
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['DataTransferStatusNtf', bytes]:
- if fields['opcode'] != 0x5 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionDataTransferStatusNtf', bytes]:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.DATA_TRANSFER_STATUS or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 7:
raise Exception('Invalid packet size')
@@ -3743,74 +3384,74 @@ class DataTransferStatusNtf(SessionControlNotification):
fields['status'] = DataTransferNtfStatusCode.from_int(span[5])
fields['tx_count'] = span[6]
span = span[7:]
- return DataTransferStatusNtf(**fields), span
+ return SessionDataTransferStatusNtf(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
if self.session_token > 4294967295:
- print(f"Invalid value for field DataTransferStatusNtf::session_token: {self.session_token} > 4294967295; the value will be truncated")
+ print(f"Invalid value for field SessionDataTransferStatusNtf::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
if self.uci_sequence_number > 255:
- print(f"Invalid value for field DataTransferStatusNtf::uci_sequence_number: {self.uci_sequence_number} > 255; the value will be truncated")
+ print(f"Invalid value for field SessionDataTransferStatusNtf::uci_sequence_number: {self.uci_sequence_number} > 255; the value will be truncated")
self.uci_sequence_number &= 255
_span.append((self.uci_sequence_number << 0))
_span.append((self.status << 0))
if self.tx_count > 255:
- print(f"Invalid value for field DataTransferStatusNtf::tx_count: {self.tx_count} > 255; the value will be truncated")
+ print(f"Invalid value for field SessionDataTransferStatusNtf::tx_count: {self.tx_count} > 255; the value will be truncated")
self.tx_count &= 255
_span.append((self.tx_count << 0))
- return SessionControlNotification.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 7
@dataclass
-class SessionQueryMaxDataSizeCmd(SessionConfigCommand):
+class SessionQueryMaxDataSizeInRangingCmd(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 11
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.COMMAND
+ self.oid = SessionConfigOpcodeId.QUERY_DATA_SIZE_IN_RANGING
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionQueryMaxDataSizeCmd', bytes]:
- if fields['opcode'] != 0xb or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.COMMAND:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionQueryMaxDataSizeInRangingCmd', bytes]:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionConfigOpcodeId.QUERY_DATA_SIZE_IN_RANGING or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 4:
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:4], byteorder='little')
fields['session_token'] = value_
span = span[4:]
- return SessionQueryMaxDataSizeCmd(**fields), span
+ return SessionQueryMaxDataSizeInRangingCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
if self.session_token > 4294967295:
- print(f"Invalid value for field SessionQueryMaxDataSizeCmd::session_token: {self.session_token} > 4294967295; the value will be truncated")
+ print(f"Invalid value for field SessionQueryMaxDataSizeInRangingCmd::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
- return SessionConfigCommand.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 4
@dataclass
-class SessionQueryMaxDataSizeRsp(SessionConfigResponse):
+class SessionQueryMaxDataSizeInRangingRsp(SessionConfigPacket):
session_token: int = field(kw_only=True, default=0)
max_data_size: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 11
- self.gid = GroupId.SESSION_CONFIG
self.mt = MessageType.RESPONSE
+ self.oid = SessionConfigOpcodeId.QUERY_DATA_SIZE_IN_RANGING
+ self.gid = GroupId.SESSION_CONFIG
@staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['SessionQueryMaxDataSizeRsp', bytes]:
- if fields['opcode'] != 0xb or fields['gid'] != GroupId.SESSION_CONFIG or fields['mt'] != MessageType.RESPONSE:
+ def parse(fields: dict, span: bytes) -> Tuple['SessionQueryMaxDataSizeInRangingRsp', bytes]:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionConfigOpcodeId.QUERY_DATA_SIZE_IN_RANGING or fields['gid'] != GroupId.SESSION_CONFIG:
raise Exception("Invalid constraint field values")
if len(span) < 6:
raise Exception('Invalid packet size')
@@ -3819,70 +3460,79 @@ class SessionQueryMaxDataSizeRsp(SessionConfigResponse):
value_ = int.from_bytes(span[4:6], byteorder='little')
fields['max_data_size'] = value_
span = span[6:]
- return SessionQueryMaxDataSizeRsp(**fields), span
+ return SessionQueryMaxDataSizeInRangingRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
if self.session_token > 4294967295:
- print(f"Invalid value for field SessionQueryMaxDataSizeRsp::session_token: {self.session_token} > 4294967295; the value will be truncated")
+ print(f"Invalid value for field SessionQueryMaxDataSizeInRangingRsp::session_token: {self.session_token} > 4294967295; the value will be truncated")
self.session_token &= 4294967295
_span.extend(int.to_bytes((self.session_token << 0), length=4, byteorder='little'))
if self.max_data_size > 65535:
- print(f"Invalid value for field SessionQueryMaxDataSizeRsp::max_data_size: {self.max_data_size} > 65535; the value will be truncated")
+ print(f"Invalid value for field SessionQueryMaxDataSizeInRangingRsp::max_data_size: {self.max_data_size} > 65535; the value will be truncated")
self.max_data_size &= 65535
_span.extend(int.to_bytes((self.max_data_size << 0), length=2, byteorder='little'))
- return SessionConfigResponse.serialize(self, payload = bytes(_span))
+ return SessionConfigPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 6
@dataclass
-class SessionStartCmd(SessionControlCommand):
-
+class SessionStartCmd(SessionControlPacket):
+ session_id: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.COMMAND
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionStartCmd', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
+ if len(span) < 4:
+ raise Exception('Invalid packet size')
+ value_ = int.from_bytes(span[0:4], byteorder='little')
+ fields['session_id'] = value_
+ span = span[4:]
return SessionStartCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return SessionControlCommand.serialize(self, payload = bytes(_span))
+ if self.session_id > 4294967295:
+ print(f"Invalid value for field SessionStartCmd::session_id: {self.session_id} > 4294967295; the value will be truncated")
+ self.session_id &= 4294967295
+ _span.extend(int.to_bytes((self.session_id << 0), length=4, byteorder='little'))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return 0
+ return 4
@dataclass
-class SessionStartRsp(SessionControlResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionStartRsp(SessionControlPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.RESPONSE
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionStartRsp', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return SessionStartRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return SessionControlResponse.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -3891,7 +3541,7 @@ class SessionStartRsp(SessionControlResponse):
@dataclass
class ShortAddressTwoWayRangingMeasurement(Packet):
mac_address: int = field(kw_only=True, default=0)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
nlos: int = field(kw_only=True, default=0)
distance: int = field(kw_only=True, default=0)
aoa_azimuth: int = field(kw_only=True, default=0)
@@ -3915,7 +3565,7 @@ class ShortAddressTwoWayRangingMeasurement(Packet):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:2], byteorder='little')
fields['mac_address'] = value_
- fields['status'] = StatusCode.from_int(span[2])
+ fields['status'] = Status.from_int(span[2])
fields['nlos'] = span[3]
value_ = int.from_bytes(span[4:6], byteorder='little')
fields['distance'] = value_
@@ -4004,7 +3654,7 @@ class ShortAddressTwoWayRangingMeasurement(Packet):
@dataclass
class ExtendedAddressTwoWayRangingMeasurement(Packet):
mac_address: int = field(kw_only=True, default=0)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
nlos: int = field(kw_only=True, default=0)
distance: int = field(kw_only=True, default=0)
aoa_azimuth: int = field(kw_only=True, default=0)
@@ -4028,7 +3678,7 @@ class ExtendedAddressTwoWayRangingMeasurement(Packet):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:8], byteorder='little')
fields['mac_address'] = value_
- fields['status'] = StatusCode.from_int(span[8])
+ fields['status'] = Status.from_int(span[8])
fields['nlos'] = span[9]
value_ = int.from_bytes(span[10:12], byteorder='little')
fields['distance'] = value_
@@ -4115,7 +3765,7 @@ class ExtendedAddressTwoWayRangingMeasurement(Packet):
@dataclass
class ShortAddressOwrAoaRangingMeasurement(Packet):
mac_address: int = field(kw_only=True, default=0)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
nlos: int = field(kw_only=True, default=0)
frame_sequence_number: int = field(kw_only=True, default=0)
block_index: int = field(kw_only=True, default=0)
@@ -4134,7 +3784,7 @@ class ShortAddressOwrAoaRangingMeasurement(Packet):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:2], byteorder='little')
fields['mac_address'] = value_
- fields['status'] = StatusCode.from_int(span[2])
+ fields['status'] = Status.from_int(span[2])
fields['nlos'] = span[3]
fields['frame_sequence_number'] = span[4]
value_ = int.from_bytes(span[5:7], byteorder='little')
@@ -4192,7 +3842,7 @@ class ShortAddressOwrAoaRangingMeasurement(Packet):
@dataclass
class ExtendedAddressOwrAoaRangingMeasurement(Packet):
mac_address: int = field(kw_only=True, default=0)
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
nlos: int = field(kw_only=True, default=0)
frame_sequence_number: int = field(kw_only=True, default=0)
block_index: int = field(kw_only=True, default=0)
@@ -4211,7 +3861,7 @@ class ExtendedAddressOwrAoaRangingMeasurement(Packet):
raise Exception('Invalid packet size')
value_ = int.from_bytes(span[0:8], byteorder='little')
fields['mac_address'] = value_
- fields['status'] = StatusCode.from_int(span[8])
+ fields['status'] = Status.from_int(span[8])
fields['nlos'] = span[9]
fields['frame_sequence_number'] = span[10]
value_ = int.from_bytes(span[11:13], byteorder='little')
@@ -4281,7 +3931,7 @@ class RangingMeasurementType(enum.IntEnum):
@dataclass
-class SessionInfoNtf(SessionControlNotification):
+class SessionInfoNtf(SessionControlPacket):
sequence_number: int = field(kw_only=True, default=0)
session_token: int = field(kw_only=True, default=0)
rcr_indicator: int = field(kw_only=True, default=0)
@@ -4290,13 +3940,13 @@ class SessionInfoNtf(SessionControlNotification):
mac_address_indicator: MacAddressIndicator = field(kw_only=True, default=MacAddressIndicator.SHORT_ADDRESS)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionInfoNtf', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 24:
raise Exception('Invalid packet size')
@@ -4363,7 +4013,7 @@ class SessionInfoNtf(SessionControlNotification):
_span.append((self.mac_address_indicator << 0))
_span.extend([0] * 8)
_span.extend(payload or self.payload or [])
- return SessionControlNotification.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -4377,13 +4027,13 @@ class ShortMacTwoWaySessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.TWO_WAY
self.mac_address_indicator = MacAddressIndicator.SHORT_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ShortMacTwoWaySessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.TWO_WAY or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.TWO_WAY or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4426,13 +4076,13 @@ class ExtendedMacTwoWaySessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.TWO_WAY
self.mac_address_indicator = MacAddressIndicator.EXTENDED_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ExtendedMacTwoWaySessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.TWO_WAY or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.TWO_WAY or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4475,13 +4125,13 @@ class ShortMacDlTDoASessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.DL_TDOA
self.mac_address_indicator = MacAddressIndicator.SHORT_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ShortMacDlTDoASessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.DL_TDOA or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.DL_TDOA or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4512,13 +4162,13 @@ class ExtendedMacDlTDoASessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.DL_TDOA
self.mac_address_indicator = MacAddressIndicator.EXTENDED_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ExtendedMacDlTDoASessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.DL_TDOA or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.DL_TDOA or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4549,13 +4199,13 @@ class ShortMacOwrAoaSessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.OWR_AOA
self.mac_address_indicator = MacAddressIndicator.SHORT_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ShortMacOwrAoaSessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.OWR_AOA or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.OWR_AOA or fields['mac_address_indicator'] != MacAddressIndicator.SHORT_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4598,13 +4248,13 @@ class ExtendedMacOwrAoaSessionInfoNtf(SessionInfoNtf):
def __post_init__(self):
self.ranging_measurement_type = RangingMeasurementType.OWR_AOA
self.mac_address_indicator = MacAddressIndicator.EXTENDED_ADDRESS
- self.opcode = 0
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.NOTIFICATION
+ self.oid = SessionControlOpcodeId.START
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['ExtendedMacOwrAoaSessionInfoNtf', bytes]:
- if fields['ranging_measurement_type'] != RangingMeasurementType.OWR_AOA or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['opcode'] != 0x0 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['ranging_measurement_type'] != RangingMeasurementType.OWR_AOA or fields['mac_address_indicator'] != MacAddressIndicator.EXTENDED_ADDRESS or fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != SessionControlOpcodeId.START or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
@@ -4640,96 +4290,114 @@ class ExtendedMacOwrAoaSessionInfoNtf(SessionInfoNtf):
)
@dataclass
-class SessionStopCmd(SessionControlCommand):
-
+class SessionStopCmd(SessionControlPacket):
+ session_id: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.COMMAND
+ self.oid = SessionControlOpcodeId.STOP
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionStopCmd', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionControlOpcodeId.STOP or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
+ if len(span) < 4:
+ raise Exception('Invalid packet size')
+ value_ = int.from_bytes(span[0:4], byteorder='little')
+ fields['session_id'] = value_
+ span = span[4:]
return SessionStopCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return SessionControlCommand.serialize(self, payload = bytes(_span))
+ if self.session_id > 4294967295:
+ print(f"Invalid value for field SessionStopCmd::session_id: {self.session_id} > 4294967295; the value will be truncated")
+ self.session_id &= 4294967295
+ _span.extend(int.to_bytes((self.session_id << 0), length=4, byteorder='little'))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return 0
+ return 4
@dataclass
-class SessionStopRsp(SessionControlResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionStopRsp(SessionControlPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.RESPONSE
+ self.oid = SessionControlOpcodeId.STOP
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionStopRsp', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionControlOpcodeId.STOP or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return SessionStopRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return SessionControlResponse.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 1
@dataclass
-class SessionGetRangingCountCmd(SessionControlCommand):
-
+class SessionGetRangingCountCmd(SessionControlPacket):
+ session_id: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.COMMAND
+ self.oid = SessionControlOpcodeId.GET_RANGING_COUNT
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetRangingCountCmd', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != SessionControlOpcodeId.GET_RANGING_COUNT or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
+ if len(span) < 4:
+ raise Exception('Invalid packet size')
+ value_ = int.from_bytes(span[0:4], byteorder='little')
+ fields['session_id'] = value_
+ span = span[4:]
return SessionGetRangingCountCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return SessionControlCommand.serialize(self, payload = bytes(_span))
+ if self.session_id > 4294967295:
+ print(f"Invalid value for field SessionGetRangingCountCmd::session_id: {self.session_id} > 4294967295; the value will be truncated")
+ self.session_id &= 4294967295
+ _span.extend(int.to_bytes((self.session_id << 0), length=4, byteorder='little'))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
- return 0
+ return 4
@dataclass
-class SessionGetRangingCountRsp(SessionControlResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class SessionGetRangingCountRsp(SessionControlPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
count: int = field(kw_only=True, default=0)
def __post_init__(self):
- self.opcode = 3
- self.gid = GroupId.SESSION_CONTROL
self.mt = MessageType.RESPONSE
+ self.oid = SessionControlOpcodeId.GET_RANGING_COUNT
+ self.gid = GroupId.SESSION_CONTROL
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['SessionGetRangingCountRsp', bytes]:
- if fields['opcode'] != 0x3 or fields['gid'] != GroupId.SESSION_CONTROL or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != SessionControlOpcodeId.GET_RANGING_COUNT or fields['gid'] != GroupId.SESSION_CONTROL:
raise Exception("Invalid constraint field values")
if len(span) < 5:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
value_ = int.from_bytes(span[1:5], byteorder='little')
fields['count'] = value_
span = span[5:]
@@ -4742,30 +4410,30 @@ class SessionGetRangingCountRsp(SessionControlResponse):
print(f"Invalid value for field SessionGetRangingCountRsp::count: {self.count} > 4294967295; the value will be truncated")
self.count &= 4294967295
_span.extend(int.to_bytes((self.count << 0), length=4, byteorder='little'))
- return SessionControlResponse.serialize(self, payload = bytes(_span))
+ return SessionControlPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 5
@dataclass
-class AndroidGetPowerStatsCmd(AndroidCommand):
+class AndroidGetPowerStatsCmd(AndroidPacket):
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.VENDOR_ANDROID
self.mt = MessageType.COMMAND
+ self.oid = AndroidOpcodeId.GET_POWER_STATS
+ self.gid = GroupId.VENDOR_ANDROID
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['AndroidGetPowerStatsCmd', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != AndroidOpcodeId.GET_POWER_STATS or fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
return AndroidGetPowerStatsCmd(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
- return AndroidCommand.serialize(self, payload = bytes(_span))
+ return AndroidPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
@@ -4773,7 +4441,7 @@ class AndroidGetPowerStatsCmd(AndroidCommand):
@dataclass
class PowerStats(Packet):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+ status: Status = field(kw_only=True, default=Status.OK)
idle_time_ms: int = field(kw_only=True, default=0)
tx_time_ms: int = field(kw_only=True, default=0)
rx_time_ms: int = field(kw_only=True, default=0)
@@ -4787,7 +4455,7 @@ class PowerStats(Packet):
fields = {'payload': None}
if len(span) < 17:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
value_ = int.from_bytes(span[1:5], byteorder='little')
fields['idle_time_ms'] = value_
value_ = int.from_bytes(span[5:9], byteorder='little')
@@ -4825,17 +4493,17 @@ class PowerStats(Packet):
return 17
@dataclass
-class AndroidGetPowerStatsRsp(AndroidResponse):
+class AndroidGetPowerStatsRsp(AndroidPacket):
stats: PowerStats = field(kw_only=True, default_factory=PowerStats)
def __post_init__(self):
- self.opcode = 0
- self.gid = GroupId.VENDOR_ANDROID
self.mt = MessageType.RESPONSE
+ self.oid = AndroidOpcodeId.GET_POWER_STATS
+ self.gid = GroupId.VENDOR_ANDROID
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['AndroidGetPowerStatsRsp', bytes]:
- if fields['opcode'] != 0x0 or fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != AndroidOpcodeId.GET_POWER_STATS or fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
if len(span) < 17:
raise Exception('Invalid packet size')
@@ -4846,24 +4514,24 @@ class AndroidGetPowerStatsRsp(AndroidResponse):
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.extend(self.stats.serialize())
- return AndroidResponse.serialize(self, payload = bytes(_span))
+ return AndroidPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 17
@dataclass
-class AndroidSetCountryCodeCmd(AndroidCommand):
+class AndroidSetCountryCodeCmd(AndroidPacket):
country_code: bytearray = field(kw_only=True, default_factory=bytearray)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.VENDOR_ANDROID
self.mt = MessageType.COMMAND
+ self.oid = AndroidOpcodeId.SET_COUNTRY_CODE
+ self.gid = GroupId.VENDOR_ANDROID
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['AndroidSetCountryCodeCmd', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.COMMAND:
+ if fields['mt'] != MessageType.COMMAND or fields['oid'] != AndroidOpcodeId.SET_COUNTRY_CODE or fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
if len(span) < 2:
raise Exception('Invalid packet size')
@@ -4874,40 +4542,53 @@ class AndroidSetCountryCodeCmd(AndroidCommand):
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.extend(self.country_code)
- return AndroidCommand.serialize(self, payload = bytes(_span))
+ return AndroidPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return 2
@dataclass
-class AndroidSetCountryCodeRsp(AndroidResponse):
- status: StatusCode = field(kw_only=True, default=StatusCode.UCI_STATUS_OK)
+class AndroidSetCountryCodeRsp(AndroidPacket):
+ status: Status = field(kw_only=True, default=Status.OK)
def __post_init__(self):
- self.opcode = 1
- self.gid = GroupId.VENDOR_ANDROID
self.mt = MessageType.RESPONSE
+ self.oid = AndroidOpcodeId.SET_COUNTRY_CODE
+ self.gid = GroupId.VENDOR_ANDROID
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['AndroidSetCountryCodeRsp', bytes]:
- if fields['opcode'] != 0x1 or fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.RESPONSE:
+ if fields['mt'] != MessageType.RESPONSE or fields['oid'] != AndroidOpcodeId.SET_COUNTRY_CODE or fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
if len(span) < 1:
raise Exception('Invalid packet size')
- fields['status'] = StatusCode.from_int(span[0])
+ fields['status'] = Status.from_int(span[0])
span = span[1:]
return AndroidSetCountryCodeRsp(**fields), span
def serialize(self, payload: bytes = None) -> bytes:
_span = bytearray()
_span.append((self.status << 0))
- return AndroidResponse.serialize(self, payload = bytes(_span))
+ return AndroidPacket.serialize(self, payload = bytes(_span))
@property
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)
@@ -5277,19 +4958,19 @@ class FrameReport(Packet):
return sum([elt.size for elt in self.frame_report_tlvs]) + 4
@dataclass
-class AndroidRangeDiagnosticsNtf(AndroidNotification):
+class AndroidRangeDiagnosticsNtf(AndroidPacket):
session_token: int = field(kw_only=True, default=0)
sequence_number: int = field(kw_only=True, default=0)
frame_reports: List[FrameReport] = field(kw_only=True, default_factory=list)
def __post_init__(self):
- self.opcode = 2
- self.gid = GroupId.VENDOR_ANDROID
self.mt = MessageType.NOTIFICATION
+ self.oid = AndroidOpcodeId.FIRA_RANGE_DIAGNOSTICS
+ self.gid = GroupId.VENDOR_ANDROID
@staticmethod
def parse(fields: dict, span: bytes) -> Tuple['AndroidRangeDiagnosticsNtf', bytes]:
- if fields['opcode'] != 0x2 or fields['gid'] != GroupId.VENDOR_ANDROID or fields['mt'] != MessageType.NOTIFICATION:
+ if fields['mt'] != MessageType.NOTIFICATION or fields['oid'] != AndroidOpcodeId.FIRA_RANGE_DIAGNOSTICS or fields['gid'] != GroupId.VENDOR_ANDROID:
raise Exception("Invalid constraint field values")
if len(span) < 9:
raise Exception('Invalid packet size')
@@ -5322,424 +5003,8 @@ class AndroidRangeDiagnosticsNtf(AndroidNotification):
_span.append((len(self.frame_reports) << 0))
for _elt in self.frame_reports:
_span.extend(_elt.serialize())
- return AndroidNotification.serialize(self, payload = bytes(_span))
+ return AndroidPacket.serialize(self, payload = bytes(_span))
@property
def size(self) -> int:
return sum([elt.size for elt in self.frame_reports]) + 9
-
-@dataclass
-class UciVendor_9_Command(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_9
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_9_Command', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_9 or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_9_Command(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_A_Command(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_A
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_A_Command', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_A or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_A_Command(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_B_Command(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_B
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_B_Command', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_B or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_B_Command(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_E_Command(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_E
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_E_Command', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_E or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_E_Command(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_F_Command(UciCommand):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_F
- self.mt = MessageType.COMMAND
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_F_Command', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_F or fields['mt'] != MessageType.COMMAND:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_F_Command(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciCommand.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_9_Response(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_9
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_9_Response', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_9 or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_9_Response(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_A_Response(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_A
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_A_Response', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_A or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_A_Response(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_B_Response(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_B
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_B_Response', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_B or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_B_Response(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_E_Response(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_E
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_E_Response', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_E or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_E_Response(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_F_Response(UciResponse):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_F
- self.mt = MessageType.RESPONSE
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_F_Response', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_F or fields['mt'] != MessageType.RESPONSE:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_F_Response(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciResponse.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_9_Notification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_9
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_9_Notification', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_9 or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_9_Notification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_A_Notification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_A
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_A_Notification', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_A or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_A_Notification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_B_Notification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_B
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_B_Notification', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_B or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_B_Notification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_E_Notification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_E
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_E_Notification', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_E or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_E_Notification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class UciVendor_F_Notification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.VENDOR_RESERVED_F
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['UciVendor_F_Notification', bytes]:
- if fields['gid'] != GroupId.VENDOR_RESERVED_F or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return UciVendor_F_Notification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
-
-@dataclass
-class TestNotification(UciNotification):
-
-
- def __post_init__(self):
- self.gid = GroupId.TEST
- self.mt = MessageType.NOTIFICATION
-
- @staticmethod
- def parse(fields: dict, span: bytes) -> Tuple['TestNotification', bytes]:
- if fields['gid'] != GroupId.TEST or fields['mt'] != MessageType.NOTIFICATION:
- raise Exception("Invalid constraint field values")
- payload = span
- span = bytes([])
- fields['payload'] = payload
- return TestNotification(**fields), span
-
- def serialize(self, payload: bytes = None) -> bytes:
- _span = bytearray()
- _span.extend(payload or self.payload or [])
- return UciNotification.serialize(self, payload = bytes(_span))
-
- @property
- def size(self) -> int:
- return len(self.payload)
diff --git a/src/app_config.rs b/src/app_config.rs
new file mode 100644
index 0000000..40ac595
--- /dev/null
+++ b/src/app_config.rs
@@ -0,0 +1,517 @@
+use crate::packets::uci;
+use crate::MacAddress;
+
+/// [UCI] 8.3 Application Configuration Parameters.
+/// Sub-session Key provided for Provisioned STS for Responder specific Key mode
+/// (STS_CONFIG equal to 0x04).
+#[derive(Clone, PartialEq, Eq)]
+pub enum SubSessionKey {
+ None,
+ Short([u8; 16]),
+ Extended([u8; 32]),
+}
+
+/// [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: SubSessionKey,
+ 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: SubSessionKey::None,
+ 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 = match value.len() {
+ 16 => SubSessionKey::Short(value.try_into().unwrap()),
+ 32 => SubSessionKey::Extended(value.try_into().unwrap()),
+ _ => anyhow::bail!("invalid sub-session key size {}", value.len()),
+ }
+ }
+ 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(match self.sub_session_key {
+ SubSessionKey::None => vec![],
+ SubSessionKey::Short(key) => key.to_vec(),
+ SubSessionKey::Extended(key) => key.to_vec(),
+ }),
+ 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/device.rs b/src/device.rs
index 48d2bd2..eec1c7f 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -12,27 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crate::packets::uci::*;
+use crate::packets::uci::{self, *};
use crate::MacAddress;
use crate::PicaCommand;
use std::collections::HashMap;
-use std::iter::Extend;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::time;
-use super::session::{Session, MAX_SESSION};
+use super::app_config::SubSessionKey;
+use super::session::Session;
use super::UciPacket;
pub const MAX_DEVICE: usize = 4;
+pub const MAX_SESSION: usize = 255;
const UCI_VERSION: u16 = 0x0002; // Version 2.0
const MAC_VERSION: u16 = 0x3001; // Version 1.3.0
const PHY_VERSION: u16 = 0x3001; // Version 1.3.0
const TEST_VERSION: u16 = 0x1001; // Version 1.1
+/// cf. [UCI] 8.3 Table 29
+pub const MAX_NUMBER_OF_CONTROLEES: usize = 8;
+
// Capabilities are vendor defined
// Android compliant: FIRA-287 UCI_Generic_Specification controlee capabilities_r4
// Android parses capabilities, according to these definitions:
@@ -72,15 +76,36 @@ pub const DEFAULT_CAPS_INFO: &[(CapTlvType, &[u8])] = &[
),
];
+/// [UCI] 8.2 Device Configuration Parameters
+pub struct DeviceConfig {
+ device_state: DeviceState,
+ // This config is used to enable/disable the low power mode.
+ // 0x00 = Disable low power mode
+ // 0x01 = Enable low power mode (default)
+ low_power_mode: bool,
+}
+
+// [UCI] 6.3.1 Setting the Configuration
+// All device configuration parameters within the UWBS are set to
+// default values at Table 44 [..].
+impl Default for DeviceConfig {
+ fn default() -> Self {
+ DeviceConfig {
+ device_state: DeviceState::DeviceStateError,
+ low_power_mode: true,
+ }
+ }
+}
+
pub struct Device {
pub handle: usize,
pub mac_address: MacAddress,
+ config: DeviceConfig,
/// [UCI] 5. UWBS Device State Machine
state: DeviceState,
sessions: HashMap<u32, Session>,
pub tx: mpsc::UnboundedSender<UciPacket>,
pica_tx: mpsc::Sender<PicaCommand>,
- config: HashMap<DeviceConfigId, Vec<u8>>,
country_code: [u8; 2],
pub n_active_sessions: usize,
@@ -96,11 +121,11 @@ impl Device {
Device {
handle,
mac_address,
+ config: Default::default(),
state: DeviceState::DeviceStateError, // Will be overwitten
sessions: Default::default(),
tx,
pica_tx,
- config: HashMap::new(),
country_code: Default::default(),
n_active_sessions: 0,
}
@@ -117,7 +142,7 @@ impl Device {
let tx = self.tx.clone();
tokio::spawn(async move {
time::sleep(Duration::from_millis(5)).await;
- tx.send(DeviceStatusNtfBuilder { device_state }.build().into())
+ tx.send(CoreDeviceStatusNtfBuilder { device_state }.build().into())
.unwrap()
});
}
@@ -175,13 +200,13 @@ impl Device {
// The fira norm specify to send a response, then reset, then
// send a notification once the reset is done
- fn command_device_reset(&mut self, cmd: DeviceResetCmd) -> DeviceResetRsp {
+ fn core_device_reset(&mut self, cmd: CoreDeviceResetCmd) -> CoreDeviceResetRsp {
let reset_config = cmd.get_reset_config();
log::debug!("[{}] DeviceReset", self.handle);
log::debug!(" reset_config={:?}", reset_config);
let status = match reset_config {
- ResetConfig::UwbsReset => StatusCode::UciStatusOk,
+ ResetConfig::UwbsReset => uci::Status::Ok,
};
*self = Device::new(
self.handle,
@@ -191,15 +216,15 @@ impl Device {
);
self.init();
- DeviceResetRspBuilder { status }.build()
+ CoreDeviceResetRspBuilder { status }.build()
}
- fn command_get_device_info(&self, _cmd: GetDeviceInfoCmd) -> GetDeviceInfoRsp {
+ fn core_get_device_info(&self, _cmd: CoreGetDeviceInfoCmd) -> CoreGetDeviceInfoRsp {
// TODO: Implement a fancy build time state machine instead of crash at runtime
log::debug!("[{}] GetDeviceInfo", self.handle);
assert_eq!(self.state, DeviceState::DeviceStateReady);
- GetDeviceInfoRspBuilder {
- status: StatusCode::UciStatusOk,
+ CoreGetDeviceInfoRspBuilder {
+ status: uci::Status::Ok,
uci_version: UCI_VERSION,
mac_version: MAC_VERSION,
phy_version: PHY_VERSION,
@@ -209,7 +234,7 @@ impl Device {
.build()
}
- pub fn command_get_caps_info(&self, _cmd: GetCapsInfoCmd) -> GetCapsInfoRsp {
+ pub fn core_get_caps_info(&self, _cmd: CoreGetCapsInfoCmd) -> CoreGetCapsInfoRsp {
log::debug!("[{}] GetCapsInfo", self.handle);
let caps = DEFAULT_CAPS_INFO
@@ -220,86 +245,101 @@ impl Device {
})
.collect();
- GetCapsInfoRspBuilder {
- status: StatusCode::UciStatusOk,
+ CoreGetCapsInfoRspBuilder {
+ status: uci::Status::Ok,
tlvs: caps,
}
.build()
}
- pub fn command_set_config(&mut self, cmd: SetConfigCmd) -> SetConfigRsp {
+ pub fn core_set_config(&mut self, cmd: CoreSetConfigCmd) -> CoreSetConfigRsp {
log::debug!("[{}] SetConfig", self.handle);
assert_eq!(self.state, DeviceState::DeviceStateReady); // UCI 6.3
- let (valid_parameters, invalid_config_status) = cmd.get_tlvs().iter().fold(
- (HashMap::new(), Vec::new()),
- |(mut valid_parameters, invalid_config_status), param| {
- // TODO: DeviceState is a read only parameter
- valid_parameters.insert(param.cfg_id, param.v.clone());
+ // [UCI] 6.3.1 Setting the Configuration
+ // The UWBS shall respond with CORE_SET_CONFIG_RSP setting the Status
+ // field of STATUS_INVALID_PARAM and including one or more invalid
+ // Parameter ID(s) If the Host tries to set a parameter that is not
+ // available in the UWBS. All other configuration parameters should
+ // have been set to the new values within the UWBS.
+ let mut invalid_parameters = vec![];
+ for parameter in cmd.get_parameters() {
+ match parameter.id {
+ uci::ConfigParameterId::DeviceState => {
+ invalid_parameters.push(uci::ConfigParameterStatus {
+ id: parameter.id,
+ status: uci::Status::ReadOnly,
+ })
+ }
+ uci::ConfigParameterId::LowPowerMode => {
+ self.config.low_power_mode = parameter.value.first().copied().unwrap_or(1) != 0;
+ }
+ uci::ConfigParameterId::Rfu(id) => {
+ log::warn!("unknown config parameter id 0x{:02x}", *id);
+ invalid_parameters.push(uci::ConfigParameterStatus {
+ id: parameter.id,
+ status: uci::Status::InvalidParam,
+ })
+ }
+ }
+ }
- (valid_parameters, invalid_config_status)
+ CoreSetConfigRspBuilder {
+ status: if invalid_parameters.is_empty() {
+ uci::Status::Ok
+ } else {
+ uci::Status::InvalidParam
},
- );
-
- let (status, parameters) = if invalid_config_status.is_empty() {
- self.config.extend(valid_parameters);
- (StatusCode::UciStatusOk, Vec::new())
- } else {
- (StatusCode::UciStatusInvalidParam, invalid_config_status)
- };
-
- SetConfigRspBuilder {
- cfg_status: parameters,
- status,
+ parameters: invalid_parameters,
}
.build()
}
- pub fn command_get_config(&self, cmd: GetConfigCmd) -> GetConfigRsp {
+ pub fn core_get_config(&self, cmd: CoreGetConfigCmd) -> CoreGetConfigRsp {
log::debug!("[{}] GetConfig", self.handle);
- // TODO: do this config shall be set on device reset
- let ids = cmd.get_cfg_id();
- let (valid_parameters, invalid_parameters) = ids.iter().fold(
- (Vec::new(), Vec::new()),
- |(mut valid_parameters, mut invalid_parameters), id| {
- // UCI Core Section 6.3.2 Table 8
- // UCI Core Section 6.3.2 - Return the Configuration
- // If the status code is ok, return the params
- // If there is at least one invalid param, return the list of invalid params
- // If the ID is not present in our config, return the Type with length = 0
- match DeviceConfigId::try_from(*id) {
- Ok(cfg_id) => match self.config.get(&cfg_id) {
- Some(value) => valid_parameters.push(DeviceConfigTlv {
- cfg_id,
- v: value.clone(),
- }),
- None => invalid_parameters.push(DeviceConfigTlv {
- cfg_id,
- v: Vec::new(),
- }),
- },
- Err(_) => log::error!("Failed to parse config id: {:?}", id),
- }
-
- (valid_parameters, invalid_parameters)
- },
- );
+ // [UCI] 6.3.2 Retrieve the Configuration
+ // If the Host tries to retrieve any Parameter(s) that are not available
+ // in the UWBS, the UWBS shall respond with a CORE_GET_CONFIG_RSP with
+ // a Status field of STATUS_INVALID_PARAM, containing each unavailable
+ // Device Configuration Parameter Type with Length field is zero. In
+ // this case, the CORE_GET_CONFIG_RSP shall not include any parameter(s)
+ // that are available in the UWBS.
+ let mut valid_parameters = vec![];
+ let mut invalid_parameters = vec![];
+ for id in cmd.get_parameter_ids() {
+ match id {
+ ConfigParameterId::DeviceState => valid_parameters.push(ConfigParameter {
+ id: *id,
+ value: vec![self.config.device_state.into()],
+ }),
+ ConfigParameterId::LowPowerMode => valid_parameters.push(ConfigParameter {
+ id: *id,
+ value: vec![self.config.low_power_mode.into()],
+ }),
+ ConfigParameterId::Rfu(_) => invalid_parameters.push(ConfigParameter {
+ id: *id,
+ value: vec![],
+ }),
+ }
+ }
- let (status, parameters) = if invalid_parameters.is_empty() {
- (StatusCode::UciStatusOk, valid_parameters)
+ if invalid_parameters.is_empty() {
+ CoreGetConfigRspBuilder {
+ status: uci::Status::Ok,
+ parameters: valid_parameters,
+ }
+ .build()
} else {
- (StatusCode::UciStatusInvalidParam, invalid_parameters)
- };
-
- GetConfigRspBuilder {
- status,
- tlvs: parameters,
+ CoreGetConfigRspBuilder {
+ status: uci::Status::InvalidParam,
+ parameters: invalid_parameters,
+ }
+ .build()
}
- .build()
}
- fn command_session_init(&mut self, cmd: SessionInitCmd) -> SessionInitRsp {
+ fn session_init(&mut self, cmd: SessionInitCmd) -> SessionInitRsp {
let session_id = cmd.get_session_id();
let session_type = cmd.get_session_type();
@@ -308,23 +348,17 @@ impl Device {
log::debug!(" session_type={:?}", session_type);
let status = if self.sessions.len() >= MAX_SESSION {
- StatusCode::UciStatusMaxSessionsExceeded
+ uci::Status::ErrorMaxSessionsExceeded
} else {
match self.sessions.insert(
session_id,
- Session::new(
- session_id,
- session_type,
- self.handle,
- self.tx.clone(),
- self.pica_tx.clone(),
- ),
+ Session::new(session_id, session_type, self.handle, self.tx.clone()),
) {
- Some(_) => StatusCode::UciStatusSessionDuplicate,
+ Some(_) => uci::Status::ErrorSessionDuplicate,
None => {
// Should not fail
self.session_mut(session_id).unwrap().init();
- StatusCode::UciStatusOk
+ uci::Status::Ok
}
}
};
@@ -332,7 +366,7 @@ impl Device {
SessionInitRspBuilder { status }.build()
}
- fn command_session_deinit(&mut self, cmd: SessionDeinitCmd) -> SessionDeinitRsp {
+ fn session_deinit(&mut self, cmd: SessionDeinitCmd) -> SessionDeinitRsp {
let session_id = cmd.get_session_token();
log::debug!("[{}] Session deinit", self.handle);
log::debug!(" session_id=0x{:x}", session_id);
@@ -346,24 +380,499 @@ impl Device {
}
}
self.sessions.remove(&session_id);
- StatusCode::UciStatusOk
+ uci::Status::Ok
}
- None => StatusCode::UciStatusSessionNotExist,
+ None => uci::Status::ErrorSessionNotExist,
};
SessionDeinitRspBuilder { status }.build()
}
- fn command_session_get_count(&self, _cmd: SessionGetCountCmd) -> SessionGetCountRsp {
+ fn session_get_count(&self, _cmd: SessionGetCountCmd) -> SessionGetCountRsp {
log::debug!("[{}] Session get count", self.handle);
SessionGetCountRspBuilder {
- status: StatusCode::UciStatusOk,
+ status: uci::Status::Ok,
session_count: self.sessions.len() as u8,
}
.build()
}
- fn command_set_country_code(
+ fn session_set_app_config(&mut self, cmd: SessionSetAppConfigCmd) -> SessionSetAppConfigRsp {
+ let session_handle = cmd.get_session_token();
+
+ log::debug!(
+ "[{}:0x{:x}] Session Set App Config",
+ self.handle,
+ session_handle
+ );
+
+ let Some(session) = self.sessions.get_mut(&session_handle) else {
+ return SessionSetAppConfigRspBuilder {
+ cfg_status: Vec::new(),
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ assert!(
+ session.session_type == SessionType::FiraRangingSession
+ || session.session_type == SessionType::FiraRangingAndInBandDataSession
+ );
+
+ if session.state == SessionState::SessionStateActive {
+ const IMMUTABLE_PARAMETERS: &[AppConfigTlvType] = &[AppConfigTlvType::AoaResultReq];
+ if cmd
+ .get_tlvs()
+ .iter()
+ .any(|cfg| IMMUTABLE_PARAMETERS.contains(&cfg.cfg_id))
+ {
+ return SessionSetAppConfigRspBuilder {
+ status: uci::Status::ErrorSessionActive,
+ cfg_status: vec![],
+ }
+ .build();
+ }
+ }
+
+ let (status, invalid_parameters) = if session.state != SessionState::SessionStateInit
+ && session.state != SessionState::SessionStateActive
+ {
+ (uci::Status::Rejected, Vec::new())
+ } else {
+ let mut app_config = session.app_config.clone();
+ 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::Status::InvalidParam,
+ }),
+ }
+ }
+
+ // [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.handle,
+ session_handle
+ );
+ return SessionSetAppConfigRspBuilder {
+ status: uci::Status::Rejected,
+ cfg_status: vec![],
+ }
+ .build();
+ }
+
+ if invalid_parameters.is_empty() {
+ session.app_config = app_config;
+ if session.state == SessionState::SessionStateInit {
+ session.set_state(
+ SessionState::SessionStateIdle,
+ ReasonCode::StateChangeWithSessionManagementCommands,
+ );
+ }
+ (uci::Status::Ok, invalid_parameters)
+ } else {
+ (uci::Status::InvalidParam, invalid_parameters)
+ }
+ };
+
+ SessionSetAppConfigRspBuilder {
+ status,
+ cfg_status: invalid_parameters,
+ }
+ .build()
+ }
+
+ fn session_get_app_config(&self, cmd: SessionGetAppConfigCmd) -> SessionGetAppConfigRsp {
+ let session_handle = cmd.get_session_token();
+
+ log::debug!(
+ "[{}:0x{:x}] Session Get App Config",
+ self.handle,
+ session_handle
+ );
+
+ let Some(session) = self.sessions.get(&session_handle) else {
+ return SessionGetAppConfigRspBuilder {
+ tlvs: vec![],
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ let (status, valid_parameters) = {
+ let mut valid_parameters = vec![];
+ let mut invalid_parameters = vec![];
+ for id in cmd.get_app_cfg() {
+ match session.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() {
+ (uci::Status::Ok, valid_parameters)
+ } else {
+ (uci::Status::Failed, Vec::new())
+ }
+ };
+
+ SessionGetAppConfigRspBuilder {
+ status,
+ tlvs: valid_parameters,
+ }
+ .build()
+ }
+
+ fn session_get_state(&self, cmd: SessionGetStateCmd) -> SessionGetStateRsp {
+ let session_handle = cmd.get_session_token();
+
+ log::debug!("[{}:0x{:x}] Session Get State", self.handle, session_handle);
+
+ let Some(session) = self.sessions.get(&session_handle) else {
+ return SessionGetStateRspBuilder {
+ session_state: SessionState::SessionStateInit,
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ SessionGetStateRspBuilder {
+ status: uci::Status::Ok,
+ session_state: session.state,
+ }
+ .build()
+ }
+
+ fn session_update_controller_multicast_list(
+ &mut self,
+ cmd: SessionUpdateControllerMulticastListCmd,
+ ) -> SessionUpdateControllerMulticastListRsp {
+ let session_handle = cmd.get_session_token();
+
+ log::debug!(
+ "[{}:0x{:x}] Session Update Controller Multicast List",
+ self.handle,
+ session_handle
+ );
+
+ let Some(session) = self.sessions.get_mut(&session_handle) else {
+ return SessionUpdateControllerMulticastListRspBuilder {
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ if (session.state != SessionState::SessionStateActive
+ && session.state != SessionState::SessionStateIdle)
+ || session.app_config.device_type != Some(DeviceType::Controller)
+ || session.app_config.multi_node_mode != Some(MultiNodeMode::OneToMany)
+ {
+ return SessionUpdateControllerMulticastListRspBuilder {
+ status: uci::Status::Rejected,
+ }
+ .build();
+ }
+ let action = cmd.get_action();
+ let mut dst_addresses = session.app_config.dst_mac_address.clone();
+ let new_controlees: Vec<Controlee> = match action {
+ UpdateMulticastListAction::AddControlee
+ | UpdateMulticastListAction::RemoveControlee => {
+ if let Ok(packet) =
+ SessionUpdateControllerMulticastListCmdPayload::parse(cmd.get_payload())
+ {
+ packet
+ .controlees
+ .iter()
+ .map(|controlee| controlee.into())
+ .collect()
+ } else {
+ return SessionUpdateControllerMulticastListRspBuilder {
+ status: uci::Status::SyntaxError,
+ }
+ .build();
+ }
+ }
+ UpdateMulticastListAction::AddControleeWithShortSubSessionKey => {
+ if let Ok(packet) =
+ SessionUpdateControllerMulticastListCmd_2_0_16_Byte_Payload::parse(
+ cmd.get_payload(),
+ )
+ {
+ packet
+ .controlees
+ .iter()
+ .map(|controlee| controlee.into())
+ .collect()
+ } else {
+ return SessionUpdateControllerMulticastListRspBuilder {
+ status: uci::Status::SyntaxError,
+ }
+ .build();
+ }
+ }
+ UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey => {
+ if let Ok(packet) =
+ SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload::parse(
+ cmd.get_payload(),
+ )
+ {
+ packet
+ .controlees
+ .iter()
+ .map(|controlee| controlee.into())
+ .collect()
+ } else {
+ return SessionUpdateControllerMulticastListRspBuilder {
+ status: uci::Status::SyntaxError,
+ }
+ .build();
+ }
+ }
+ };
+ let mut controlee_status = Vec::new();
+ let mut status = uci::Status::Ok;
+
+ match action {
+ UpdateMulticastListAction::AddControlee
+ | UpdateMulticastListAction::AddControleeWithShortSubSessionKey
+ | UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey => {
+ new_controlees.iter().for_each(|controlee| {
+ let mut update_status = MulticastUpdateStatus::OkMulticastListUpdate;
+ if !dst_addresses.contains(&controlee.short_address) {
+ if dst_addresses.len() == MAX_NUMBER_OF_CONTROLEES {
+ status = uci::Status::ErrorMulticastListFull;
+ update_status = MulticastUpdateStatus::ErrorMulticastListFull;
+ } else if (action
+ == UpdateMulticastListAction::AddControleeWithShortSubSessionKey
+ || action
+ == UpdateMulticastListAction::AddControleeWithExtendedSubSessionKey)
+ && session.app_config.sts_config
+ != 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
+ // with Status set to STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE for each
+ // Controlee in the Controlee List.
+ status = uci::Status::Failed;
+ update_status = MulticastUpdateStatus::ErrorSubSessionKeyNotApplicable;
+ } else {
+ dst_addresses.push(controlee.short_address);
+ };
+ }
+ controlee_status.push(ControleeStatus {
+ mac_address: match controlee.short_address {
+ MacAddress::Short(address) => address,
+ MacAddress::Extended(_) => panic!("Extended address is not supported!"),
+ },
+ status: update_status,
+ });
+ });
+ }
+ UpdateMulticastListAction::RemoveControlee => {
+ new_controlees.iter().for_each(|controlee: &Controlee| {
+ let pica_tx = self.pica_tx.clone();
+ let address = controlee.short_address;
+ let attempt_count = session.app_config.in_band_termination_attempt_count;
+ let mut update_status = MulticastUpdateStatus::OkMulticastListUpdate;
+ if !dst_addresses.contains(&address) {
+ status = uci::Status::Failed;
+ update_status = MulticastUpdateStatus::ErrorKeyFetchFail;
+ } else {
+ dst_addresses.retain(|value| *value != address);
+ // If IN_BAND_TERMINATION_ATTEMPT_COUNT is not equal to 0x00, then the
+ // UWBS shall transmit the RCM with the “Stop Ranging” bit set to ‘1’
+ // for IN_BAND_TERMINATION_ATTEMPT_COUNT times to the corresponding
+ // Controlee.
+ if attempt_count != 0 {
+ tokio::spawn(async move {
+ for _ in 0..attempt_count {
+ pica_tx
+ .send(PicaCommand::StopRanging(address, session_handle))
+ .await
+ .unwrap()
+ }
+ });
+ }
+ }
+ controlee_status.push(ControleeStatus {
+ mac_address: match address {
+ MacAddress::Short(addr) => addr,
+ MacAddress::Extended(_) => panic!("Extended address is not supported!"),
+ },
+ status: update_status,
+ });
+ });
+ }
+ }
+ session.app_config.number_of_controlees = dst_addresses.len() as u8;
+ session.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 session.app_config.dst_mac_address.is_empty() {
+ session.set_state(
+ SessionState::SessionStateIdle,
+ ReasonCode::ErrorInvalidNumOfControlees,
+ )
+ }
+ let tx = self.tx.clone();
+ tokio::spawn(async move {
+ // Sleep for 5ms to make sure the notification is not being
+ // sent before the response.
+ // TODO(#84) remove the sleep.
+ time::sleep(Duration::from_millis(5)).await;
+ tx.send(
+ SessionUpdateControllerMulticastListNtfBuilder {
+ controlee_status,
+ session_token: session_handle,
+ }
+ .build()
+ .into(),
+ )
+ .unwrap()
+ });
+ SessionUpdateControllerMulticastListRspBuilder { status }.build()
+ }
+
+ fn session_start(&mut self, cmd: SessionStartCmd) -> SessionStartRsp {
+ let session_id = cmd.get_session_id();
+
+ log::debug!("[{}:0x{:x}] Session Start", self.handle, session_id);
+
+ let Some(session) = self.sessions.get_mut(&session_id) else {
+ return SessionStartRspBuilder {
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ if session.state != SessionState::SessionStateIdle {
+ return SessionStartRspBuilder {
+ status: uci::Status::ErrorSessionNotConfigured,
+ }
+ .build();
+ }
+
+ assert!(session.ranging_task.is_none());
+
+ let ranging_interval =
+ time::Duration::from_millis(session.app_config.ranging_duration as u64);
+
+ let tx = self.pica_tx.clone();
+ let handle = self.handle;
+ session.ranging_task = Some(tokio::spawn(async move {
+ loop {
+ time::sleep(ranging_interval).await;
+ tx.send(PicaCommand::Ranging(handle, session_id))
+ .await
+ .unwrap();
+ }
+ }));
+
+ session.set_state(
+ SessionState::SessionStateActive,
+ ReasonCode::StateChangeWithSessionManagementCommands,
+ );
+
+ self.n_active_sessions += 1;
+ self.set_state(DeviceState::DeviceStateActive);
+
+ SessionStartRspBuilder {
+ status: uci::Status::Ok,
+ }
+ .build()
+ }
+
+ fn session_stop(&mut self, cmd: SessionStopCmd) -> SessionStopRsp {
+ let session_id = cmd.get_session_id();
+
+ log::debug!("[{}:0x{:x}] Session Stop", self.handle, session_id);
+
+ let Some(session) = self.sessions.get_mut(&session_id) else {
+ return SessionStopRspBuilder {
+ status: uci::Status::ErrorSessionNotExist,
+ }
+ .build();
+ };
+
+ if session.state != SessionState::SessionStateActive {
+ return SessionStopRspBuilder {
+ status: uci::Status::ErrorSessionActive,
+ }
+ .build();
+ }
+
+ session.stop_ranging_task();
+ session.set_state(
+ SessionState::SessionStateIdle,
+ ReasonCode::StateChangeWithSessionManagementCommands,
+ );
+
+ self.n_active_sessions -= 1;
+ if self.n_active_sessions == 0 {
+ self.set_state(DeviceState::DeviceStateReady);
+ }
+
+ SessionStopRspBuilder {
+ status: uci::Status::Ok,
+ }
+ .build()
+ }
+
+ fn session_get_ranging_count(
+ &self,
+ cmd: SessionGetRangingCountCmd,
+ ) -> SessionGetRangingCountRsp {
+ let session_id = cmd.get_session_id();
+
+ log::debug!(
+ "[{}:0x{:x}] Session Get Ranging Count",
+ self.handle,
+ session_id
+ );
+
+ let Some(session) = self.sessions.get(&session_id) else {
+ return SessionGetRangingCountRspBuilder {
+ status: uci::Status::ErrorSessionNotExist,
+ count: 0,
+ }
+ .build();
+ };
+
+ SessionGetRangingCountRspBuilder {
+ status: uci::Status::Ok,
+ count: session.sequence_number,
+ }
+ .build()
+ }
+
+ fn android_set_country_code(
&mut self,
cmd: AndroidSetCountryCodeCmd,
) -> AndroidSetCountryCodeRsp {
@@ -373,12 +882,12 @@ impl Device {
self.country_code = country_code;
AndroidSetCountryCodeRspBuilder {
- status: StatusCode::UciStatusOk,
+ status: uci::Status::Ok,
}
.build()
}
- fn command_get_power_stats(
+ fn android_get_power_stats(
&mut self,
_cmd: AndroidGetPowerStatsCmd,
) -> AndroidGetPowerStatsRsp {
@@ -387,7 +896,7 @@ impl Device {
// TODO
AndroidGetPowerStatsRspBuilder {
stats: PowerStats {
- status: StatusCode::UciStatusOk,
+ status: uci::Status::Ok,
idle_time_ms: 0,
tx_time_ms: 0,
rx_time_ms: 0,
@@ -397,7 +906,7 @@ impl Device {
.build()
}
- pub fn data_message_snd(&mut self, data: DataPacket) -> SessionControlNotification {
+ pub fn data_message_snd(&mut self, data: DataPacket) -> ControlPacket {
log::debug!("[{}] data_message_send", self.handle);
match data.specialize() {
DataPacketChild::DataMessageSnd(data_msg_snd) => {
@@ -405,7 +914,7 @@ impl Device {
if let Some(session) = self.session_mut(session_token) {
session.data_message_snd(data_msg_snd)
} else {
- DataTransferStatusNtfBuilder {
+ SessionDataTransferStatusNtfBuilder {
session_token,
status: DataTransferNtfStatusCode::UciDataTransferStatusErrorRejected,
tx_count: 1, // TODO: support for retries?
@@ -418,7 +927,7 @@ impl Device {
DataPacketChild::DataMessageRcv(data_msg_rcv) => {
// This function should not be passed anything besides DataMessageSnd
let session_token = data_msg_rcv.get_session_handle();
- DataTransferStatusNtfBuilder {
+ SessionDataTransferStatusNtfBuilder {
session_token,
status: DataTransferNtfStatusCode::UciDataTransferStatusInvalidFormat,
tx_count: 1, // TODO: support for retries?
@@ -433,187 +942,73 @@ impl Device {
}
}
- fn receive_command(&mut self, cmd: UciCommand) -> UciResponse {
+ fn receive_command(&mut self, cmd: ControlPacket) -> ControlPacket {
+ use AndroidPacketChild::*;
+ use ControlPacketChild::*;
+ use CorePacketChild::*;
+ use SessionConfigPacketChild::*;
+ use SessionControlPacketChild::*;
+
match cmd.specialize() {
- // Handle commands for this device
- UciCommandChild::CoreCommand(core_command) => match core_command.specialize() {
- CoreCommandChild::DeviceResetCmd(cmd) => self.command_device_reset(cmd).into(),
- CoreCommandChild::GetDeviceInfoCmd(cmd) => self.command_get_device_info(cmd).into(),
- CoreCommandChild::GetCapsInfoCmd(cmd) => self.command_get_caps_info(cmd).into(),
- CoreCommandChild::SetConfigCmd(cmd) => self.command_set_config(cmd).into(),
- CoreCommandChild::GetConfigCmd(cmd) => self.command_get_config(cmd).into(),
- _ => panic!("Unsupported core command"),
+ CorePacket(cmd) => match cmd.specialize() {
+ CoreDeviceResetCmd(cmd) => self.core_device_reset(cmd).into(),
+ CoreGetDeviceInfoCmd(cmd) => self.core_get_device_info(cmd).into(),
+ CoreGetCapsInfoCmd(cmd) => self.core_get_caps_info(cmd).into(),
+ CoreSetConfigCmd(cmd) => self.core_set_config(cmd).into(),
+ CoreGetConfigCmd(cmd) => self.core_get_config(cmd).into(),
+ _ => unimplemented!("Unsupported Core oid {:?}", cmd.get_oid()),
},
- // Handle commands for session management
- UciCommandChild::SessionConfigCommand(session_command) => {
- match session_command.specialize() {
- SessionConfigCommandChild::SessionInitCmd(cmd) => {
- return self.command_session_init(cmd).into();
- }
- SessionConfigCommandChild::SessionDeinitCmd(cmd) => {
- return self.command_session_deinit(cmd).into();
- }
- SessionConfigCommandChild::SessionGetCountCmd(cmd) => {
- return self.command_session_get_count(cmd).into();
- }
- _ => {}
- }
-
- // Common code for retrieving the session_id in the command
- let session_id = match session_command.specialize() {
- SessionConfigCommandChild::SessionSetAppConfigCmd(cmd) => {
- cmd.get_session_token()
- }
- SessionConfigCommandChild::SessionGetAppConfigCmd(cmd) => {
- cmd.get_session_token()
- }
- SessionConfigCommandChild::SessionGetStateCmd(cmd) => cmd.get_session_token(),
- SessionConfigCommandChild::SessionUpdateControllerMulticastListCmd(cmd) => {
- cmd.get_session_token()
- }
- _ => panic!("Unsupported session command type"),
- };
-
- if let Some(session) = self.session_mut(session_id) {
- // There is a session matching the session_id in the command
- // Pass the command through
- match session_command.specialize() {
- SessionConfigCommandChild::SessionSetAppConfigCmd(_)
- | SessionConfigCommandChild::SessionGetAppConfigCmd(_)
- | SessionConfigCommandChild::SessionGetStateCmd(_)
- | SessionConfigCommandChild::SessionUpdateControllerMulticastListCmd(_) => {
- session.session_command(session_command).into()
- }
- _ => panic!("Unsupported session command"),
- }
- } else {
- // There is no session matching the session_id in the command
- let status = StatusCode::UciStatusSessionNotExist;
- match session_command.specialize() {
- SessionConfigCommandChild::SessionSetAppConfigCmd(_) => {
- SessionSetAppConfigRspBuilder {
- cfg_status: Vec::new(),
- status,
- }
- .build()
- .into()
- }
- SessionConfigCommandChild::SessionGetAppConfigCmd(_) => {
- SessionGetAppConfigRspBuilder {
- status,
- tlvs: Vec::new(),
- }
- .build()
- .into()
- }
- SessionConfigCommandChild::SessionGetStateCmd(_) => {
- SessionGetStateRspBuilder {
- status,
- session_state: SessionState::SessionStateDeinit,
- }
- .build()
- .into()
- }
- SessionConfigCommandChild::SessionUpdateControllerMulticastListCmd(_) => {
- SessionUpdateControllerMulticastListRspBuilder { status }
- .build()
- .into()
- }
- _ => panic!("Unsupported session command"),
- }
- }
- }
- UciCommandChild::SessionControlCommand(ranging_command) => {
- let session_id = ranging_command.get_session_id();
- if let Some(session) = self.session_mut(session_id) {
- // Forward to the proper session
- let response = session.ranging_command(ranging_command);
- match response.specialize() {
- SessionControlResponseChild::SessionStartRsp(rsp)
- if rsp.get_status() == StatusCode::UciStatusOk =>
- {
- self.n_active_sessions += 1;
- self.set_state(DeviceState::DeviceStateActive);
- }
- SessionControlResponseChild::SessionStopRsp(rsp)
- if rsp.get_status() == StatusCode::UciStatusOk =>
- {
- assert!(self.n_active_sessions > 0);
- self.n_active_sessions -= 1;
- if self.n_active_sessions == 0 {
- self.set_state(DeviceState::DeviceStateReady);
- }
- }
- _ => {}
- }
- response.into()
- } else {
- let status = StatusCode::UciStatusSessionNotExist;
- match ranging_command.specialize() {
- SessionControlCommandChild::SessionStartCmd(_) => {
- SessionStartRspBuilder { status }.build().into()
- }
- SessionControlCommandChild::SessionStopCmd(_) => {
- SessionStopRspBuilder { status }.build().into()
- }
- SessionControlCommandChild::SessionGetRangingCountCmd(_) => {
- SessionGetRangingCountRspBuilder { status, count: 0 }
- .build()
- .into()
- }
- _ => panic!("Unsupported ranging command"),
- }
+ SessionConfigPacket(cmd) => match cmd.specialize() {
+ SessionInitCmd(cmd) => self.session_init(cmd).into(),
+ SessionDeinitCmd(cmd) => self.session_deinit(cmd).into(),
+ SessionGetCountCmd(cmd) => self.session_get_count(cmd).into(),
+ SessionSetAppConfigCmd(cmd) => self.session_set_app_config(cmd).into(),
+ SessionGetAppConfigCmd(cmd) => self.session_get_app_config(cmd).into(),
+ SessionGetStateCmd(cmd) => self.session_get_state(cmd).into(),
+ SessionUpdateControllerMulticastListCmd(cmd) => {
+ self.session_update_controller_multicast_list(cmd).into()
}
+ _ => unimplemented!("Unsupported Session Config oid {:?}", cmd.get_oid()),
+ },
+ SessionControlPacket(cmd) => match cmd.specialize() {
+ SessionStartCmd(cmd) => self.session_start(cmd).into(),
+ SessionStopCmd(cmd) => self.session_stop(cmd).into(),
+ SessionGetRangingCountCmd(cmd) => self.session_get_ranging_count(cmd).into(),
+ _ => unimplemented!("Unsupported Session Control oid {:?}", cmd.get_oid()),
+ },
+ AndroidPacket(cmd) => match cmd.specialize() {
+ AndroidSetCountryCodeCmd(cmd) => self.android_set_country_code(cmd).into(),
+ AndroidGetPowerStatsCmd(cmd) => self.android_get_power_stats(cmd).into(),
+ _ => unimplemented!("Unsupported Android oid {:?}", cmd.get_oid()),
+ },
+ ControlPacketChild::Payload(_)
+ if matches!(
+ cmd.get_mt(),
+ uci::MessageType::Response | uci::MessageType::Notification
+ ) =>
+ {
+ unreachable!("Unhandled control messsage with type {:?}", cmd.get_mt());
}
-
- UciCommandChild::AndroidCommand(android_command) => {
- match android_command.specialize() {
- AndroidCommandChild::AndroidSetCountryCodeCmd(cmd) => {
- self.command_set_country_code(cmd).into()
- }
- AndroidCommandChild::AndroidGetPowerStatsCmd(cmd) => {
- self.command_get_power_stats(cmd).into()
- }
- _ => panic!("Unsupported Android command"),
+ ControlPacketChild::Payload(payload) => {
+ // [UCI] 4.3.2 Exception Handling for Control Messages
+ // The UWBS shall respond to an unknown Command (unknown GID
+ // or OID) with a Response having the same GID and OID field
+ // values as the Command, followed by a Status field with the
+ // value of STATUS_UNKNOWN_GID/STATUS_UNKNOWN_OID respectively
+ // and no additional fields.
+ log::error!("Unsupported gid {:?}", cmd.get_gid());
+ ControlPacketBuilder {
+ mt: uci::MessageType::Response,
+ gid: cmd.get_gid(),
+ payload: Some(
+ vec![payload[0], payload[1], 0x1, uci::Status::UnknownGid.into()].into(),
+ ),
}
+ .build()
}
- UciCommandChild::UciVendor_9_Command(vendor_command) => UciVendor_9_ResponseBuilder {
- opcode: vendor_command.get_opcode(),
- payload: Some(vec![u8::from(StatusCode::UciStatusRejected)].into()),
- }
- .build()
- .into(),
- UciCommandChild::UciVendor_A_Command(vendor_command) => UciVendor_A_ResponseBuilder {
- opcode: vendor_command.get_opcode(),
- payload: Some(vec![u8::from(StatusCode::UciStatusRejected)].into()),
- }
- .build()
- .into(),
- UciCommandChild::UciVendor_B_Command(vendor_command) => UciVendor_B_ResponseBuilder {
- opcode: vendor_command.get_opcode(),
- payload: Some(vec![u8::from(StatusCode::UciStatusRejected)].into()),
- }
- .build()
- .into(),
- UciCommandChild::UciVendor_E_Command(vendor_command) => UciVendor_E_ResponseBuilder {
- opcode: vendor_command.get_opcode(),
- payload: Some(vec![u8::from(StatusCode::UciStatusRejected)].into()),
- }
- .build()
- .into(),
- UciCommandChild::UciVendor_F_Command(vendor_command) => UciVendor_F_ResponseBuilder {
- opcode: vendor_command.get_opcode(),
- payload: Some(vec![u8::from(StatusCode::UciStatusRejected)].into()),
- }
- .build()
- .into(),
- // TODO: Handle properly without panic
- _ => UciResponseBuilder {
- gid: GroupId::Core,
- opcode: 0,
- payload: None,
+ ControlPacketChild::None => {
+ unreachable!()
}
- .build(),
}
}
@@ -642,9 +1037,9 @@ impl Device {
let opcode_id = packet[1] & 0x3f;
let status = if GroupId::try_from(group_id).is_ok() {
- StatusCode::UciStatusUnknownOid
+ uci::Status::UnknownOid
} else {
- StatusCode::UciStatusUnknownGid
+ uci::Status::UnknownGid
};
// The PDL generated code cannot be used to generate
// responses with invalid group identifiers.
@@ -660,7 +1055,7 @@ impl Device {
// Parsing success, ignore non command packets.
Ok(cmd) => {
- let response = self.receive_command(cmd.try_into().unwrap());
+ let response = self.receive_command(cmd);
self.send_control(response)
}
}
@@ -672,3 +1067,41 @@ impl Device {
}
}
}
+
+struct Controlee {
+ short_address: MacAddress,
+ #[allow(dead_code)]
+ sub_session_id: u32,
+ #[allow(dead_code)]
+ session_key: SubSessionKey,
+}
+
+impl From<&uci::Controlee> for Controlee {
+ fn from(value: &uci::Controlee) -> Self {
+ Controlee {
+ short_address: MacAddress::Short(value.short_address),
+ sub_session_id: value.subsession_id,
+ session_key: SubSessionKey::None,
+ }
+ }
+}
+
+impl From<&uci::Controlee_V2_0_16_Byte_Version> for Controlee {
+ fn from(value: &uci::Controlee_V2_0_16_Byte_Version) -> Self {
+ Controlee {
+ short_address: MacAddress::Short(value.short_address),
+ sub_session_id: value.subsession_id,
+ session_key: SubSessionKey::Short(value.subsession_key),
+ }
+ }
+}
+
+impl From<&uci::Controlee_V2_0_32_Byte_Version> for Controlee {
+ fn from(value: &uci::Controlee_V2_0_32_Byte_Version) -> Self {
+ Controlee {
+ short_address: MacAddress::Short(value.short_address),
+ sub_session_id: value.subsession_id,
+ session_key: SubSessionKey::Extended(value.subsession_key),
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2927d95..17ad1c2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,19 +24,18 @@ use tokio::sync::{broadcast, mpsc, oneshot};
pub mod packets;
mod pcapng;
-use packets::uci::StatusCode as UciStatusCode;
-use packets::uci::*;
+use packets::uci::{self, *};
mod device;
-use device::{Device, MAX_DEVICE};
+use device::{Device, MAX_DEVICE, MAX_SESSION};
mod session;
-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>>;
@@ -162,7 +161,7 @@ fn make_measurement(
if let MacAddress::Short(address) = mac_address {
ShortAddressTwoWayRangingMeasurement {
mac_address: u16::from_le_bytes(*address),
- status: UciStatusCode::UciStatusOk,
+ status: uci::Status::Ok,
nlos: 0, // in Line Of Sight
distance: local.range,
aoa_azimuth: local.azimuth as u16,
@@ -412,7 +411,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 +436,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)
@@ -467,15 +467,15 @@ impl Pica {
data_sequence_number: 0x01,
pbf: PacketBoundaryFlag::Complete,
session_handle: session_id,
- source_address: device.mac_address.into(),
- status: UciStatusCode::UciStatusOk,
+ source_address: session.app_config.device_mac_address.unwrap().into(),
+ status: uci::Status::Ok,
}
.build()
.into(),
)
.unwrap();
}
- if session.is_ranging_data_ntf_enabled() != RangeDataNtfConfig::Disable {
+ if session.is_session_info_ntf_enabled() {
device
.tx
.send(
@@ -554,7 +554,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..6c93981 100644
--- a/src/mac_address.rs
+++ b/src/mac_address.rs
@@ -43,15 +43,36 @@ impl MacAddress {
}
}
+impl From<&MacAddress> for u64 {
+ fn from(mac_address: &MacAddress) -> Self {
+ match mac_address {
+ MacAddress::Short(addr) => u16::from_le_bytes(*addr) as u64,
+ MacAddress::Extended(addr) => u64::from_le_bytes(*addr),
+ }
+ }
+}
+
impl From<MacAddress> for u64 {
fn from(mac_address: MacAddress) -> Self {
+ u64::from(&mac_address)
+ }
+}
+
+impl From<&MacAddress> for Vec<u8> {
+ fn from(mac_address: &MacAddress) -> Self {
match mac_address {
- MacAddress::Short(addr) => u16::from_le_bytes(addr) as u64,
- MacAddress::Extended(addr) => u64::from_le_bytes(addr),
+ 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 eb4e063..2ee656a 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -17,711 +17,15 @@
//! - [UCI] FiRa Consortium UWB Command Interface Generic Technical specification
use crate::packets::uci::{self, *};
-use crate::{MacAddress, PicaCommand};
+use crate::{AppConfig, MacAddress};
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,
- #[allow(dead_code)]
- session_key: SubSessionKey,
-}
-
-impl From<&uci::Controlee> for Controlee {
- fn from(value: &uci::Controlee) -> Self {
- Controlee {
- short_address: MacAddress::Short(value.short_address),
- sub_session_id: value.subsession_id,
- session_key: SubSessionKey::None,
- }
- }
-}
-
-impl From<&uci::Controlee_V2_0_16_Byte_Version> for Controlee {
- fn from(value: &uci::Controlee_V2_0_16_Byte_Version) -> Self {
- Controlee {
- short_address: MacAddress::Short(value.short_address),
- sub_session_id: value.subsession_id,
- session_key: SubSessionKey::Short(value.subsession_key),
- }
- }
-}
-
-impl From<&uci::Controlee_V2_0_32_Byte_Version> for Controlee {
- fn from(value: &uci::Controlee_V2_0_32_Byte_Version) -> Self {
- Controlee {
- short_address: MacAddress::Short(value.short_address),
- sub_session_id: value.subsession_id,
- session_key: SubSessionKey::Extended(value.subsession_key),
- }
- }
-}
-
pub struct Session {
/// cf. [UCI] 7.1
pub state: SessionState,
@@ -730,12 +34,11 @@ pub struct Session {
device_handle: usize,
data: BytesMut,
- session_type: SessionType,
+ pub session_type: SessionType,
pub sequence_number: u32,
pub app_config: AppConfig,
- ranging_task: Option<JoinHandle<()>>,
+ pub ranging_task: Option<JoinHandle<()>>,
tx: mpsc::UnboundedSender<UciPacket>,
- pica_tx: mpsc::Sender<PicaCommand>,
}
impl Session {
@@ -744,7 +47,6 @@ impl Session {
session_type: SessionType,
device_handle: usize,
tx: mpsc::UnboundedSender<UciPacket>,
- pica_tx: mpsc::Sender<PicaCommand>,
) -> Self {
Self {
state: SessionState::SessionStateDeinit,
@@ -756,7 +58,6 @@ impl Session {
app_config: AppConfig::default(),
ranging_task: None,
tx,
- pica_tx,
}
}
@@ -785,12 +86,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 {
@@ -816,407 +123,20 @@ impl Session {
);
}
- fn command_set_app_config(&mut self, cmd: SessionSetAppConfigCmd) -> SessionSetAppConfigRsp {
- // TODO properly handle these asserts
- log::debug!(
- "[{}:0x{:x}] Session Set App Config",
- self.device_handle,
- self.id
- );
- assert_eq!(self.id, cmd.get_session_token());
- assert!(
- self.session_type.eq(&SessionType::FiraRangingSession)
- || self
- .session_type
- .eq(&SessionType::FiraRangingAndInBandDataSession)
- );
-
- if self.state == SessionState::SessionStateActive {
- const IMMUTABLE_PARAMETERS: &[AppConfigTlvType] = &[AppConfigTlvType::AoaResultReq];
- if cmd
- .get_tlvs()
- .iter()
- .any(|cfg| IMMUTABLE_PARAMETERS.contains(&cfg.cfg_id))
- {
- return SessionSetAppConfigRspBuilder {
- status: StatusCode::UciStatusSessionActive,
- cfg_status: vec![],
- }
- .build();
- }
- }
-
- let (status, invalid_parameters) = if self.state != SessionState::SessionStateInit
- && self.state != SessionState::SessionStateActive
- {
- (StatusCode::UciStatusRejected, Vec::new())
- } else {
- let mut app_config = self.app_config.clone();
- let invalid_parameters = app_config.extend(cmd.get_tlvs());
- if invalid_parameters.is_empty() {
- self.app_config = app_config;
- if self.state == SessionState::SessionStateInit {
- self.set_state(
- SessionState::SessionStateIdle,
- ReasonCode::StateChangeWithSessionManagementCommands,
- );
- }
- (StatusCode::UciStatusOk, invalid_parameters)
- } else {
- (StatusCode::UciStatusInvalidParam, invalid_parameters)
- }
- };
-
- SessionSetAppConfigRspBuilder {
- status,
- cfg_status: invalid_parameters,
- }
- .build()
- }
-
- fn command_get_app_config(&self, cmd: SessionGetAppConfigCmd) -> SessionGetAppConfigRsp {
- log::debug!(
- "[{}:0x{:x}] Session Get App Config",
- self.device_handle,
- self.id
- );
- 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)
- },
- );
- if invalid_parameters.is_empty() {
- (StatusCode::UciStatusOk, valid_parameters)
- } else {
- (StatusCode::UciStatusFailed, Vec::new())
- }
- };
- SessionGetAppConfigRspBuilder {
- status,
- tlvs: valid_parameters,
- }
- .build()
- }
-
- fn command_get_state(&self, cmd: SessionGetStateCmd) -> SessionGetStateRsp {
- log::debug!("[{}:0x{:x}] Session Get State", self.device_handle, self.id);
- assert_eq!(self.id, cmd.get_session_token());
- SessionGetStateRspBuilder {
- status: StatusCode::UciStatusOk,
- session_state: self.state,
- }
- .build()
- }
-
- fn command_update_controller_multicast_list(
- &mut self,
- cmd: SessionUpdateControllerMulticastListCmd,
- ) -> SessionUpdateControllerMulticastListRsp {
- log::debug!(
- "[{}:0x{:x}] Session Update Controller Multicast List",
- self.device_handle,
- self.id
- );
- 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)
- {
- 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 new_controlees: Vec<Controlee> = match action {
- UpdateMulticastListAction::Add | UpdateMulticastListAction::Delete => {
- if let Ok(packet) =
- SessionUpdateControllerMulticastListCmdPayload::parse(cmd.get_payload())
- {
- packet
- .controlees
- .iter()
- .map(|controlee| controlee.into())
- .collect()
- } else {
- return SessionUpdateControllerMulticastListRspBuilder {
- status: StatusCode::UciStatusSyntaxError,
- }
- .build();
- }
- }
- UpdateMulticastListAction::AddWithShortSubSessionKey => {
- if let Ok(packet) =
- SessionUpdateControllerMulticastListCmd_2_0_16_Byte_Payload::parse(
- cmd.get_payload(),
- )
- {
- packet
- .controlees
- .iter()
- .map(|controlee| controlee.into())
- .collect()
- } else {
- return SessionUpdateControllerMulticastListRspBuilder {
- status: StatusCode::UciStatusSyntaxError,
- }
- .build();
- }
- }
- UpdateMulticastListAction::AddwithExtendedSubSessionKey => {
- if let Ok(packet) =
- SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload::parse(
- cmd.get_payload(),
- )
- {
- packet
- .controlees
- .iter()
- .map(|controlee| controlee.into())
- .collect()
- } else {
- return SessionUpdateControllerMulticastListRspBuilder {
- status: StatusCode::UciStatusSyntaxError,
- }
- .build();
- }
- }
- };
- let mut controlee_status = Vec::new();
-
- let session_id = self.id;
- let mut status = StatusCode::UciStatusOk;
-
- match action {
- UpdateMulticastListAction::Add
- | UpdateMulticastListAction::AddWithShortSubSessionKey
- | UpdateMulticastListAction::AddwithExtendedSubSessionKey => {
- 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)
- && self.app_config.sts_config
- != StsConfig::ProvisionedForControleeIndividualKey
- {
- // If Action is 0x02 or 0x03 for STS_CONFIG values other than
- // 0x04, the UWBS shall return SESSION_UPDATE_CONTROLLER_MULTICAST_LIST_NTF
- // with Status set to STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE for each
- // Controlee in the Controlee List.
- status = StatusCode::UciStatusFailed;
- update_status =
- MulticastUpdateStatusCode::StatusErrorSubSessionKeyNotApplicable;
- } else {
- dst_addresses.push(controlee.short_address);
- };
- }
- controlee_status.push(ControleeStatus {
- mac_address: match controlee.short_address {
- MacAddress::Short(address) => address,
- MacAddress::Extended(_) => panic!("Extended address is not supported!"),
- },
- subsession_id: controlee.sub_session_id,
- status: update_status,
- });
- });
- }
- UpdateMulticastListAction::Delete => {
- new_controlees.iter().for_each(|controlee: &Controlee| {
- let pica_tx = self.pica_tx.clone();
- let address = controlee.short_address;
- let attempt_count = self.app_config.in_band_termination_attempt_count;
- let mut update_status = MulticastUpdateStatusCode::StatusOkMulticastListUpdate;
- if !dst_addresses.contains(&address) {
- status = StatusCode::UciStatusAddressNotFound;
- update_status = MulticastUpdateStatusCode::StatusErrorKeyFetchFail;
- } else {
- dst_addresses.retain(|value| *value != address);
- // If IN_BAND_TERMINATION_ATTEMPT_COUNT is not equal to 0x00, then the
- // UWBS shall transmit the RCM with the “Stop Ranging” bit set to ‘1’
- // for IN_BAND_TERMINATION_ATTEMPT_COUNT times to the corresponding
- // Controlee.
- if attempt_count != 0 {
- tokio::spawn(async move {
- for _ in 0..attempt_count {
- pica_tx
- .send(PicaCommand::StopRanging(address, session_id))
- .await
- .unwrap()
- }
- });
- }
- }
- controlee_status.push(ControleeStatus {
- mac_address: match address {
- MacAddress::Short(addr) => addr,
- MacAddress::Extended(_) => panic!("Extended address is not supported!"),
- },
- subsession_id: controlee.sub_session_id,
- status: update_status,
- });
- });
- }
- }
- self.app_config.number_of_controlees = dst_addresses.len();
- self.app_config.dst_mac_addresses = 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() {
- self.set_state(
- SessionState::SessionStateIdle,
- ReasonCode::ErrorInvalidNumOfControlees,
- )
- }
- let tx = self.tx.clone();
- tokio::spawn(async move {
- tx.send(
- SessionUpdateControllerMulticastListNtfBuilder {
- controlee_status,
- remaining_multicast_list_size: dst_addresses.len() as u8,
- session_token: session_id,
- }
- .build()
- .into(),
- )
- .unwrap()
- });
- SessionUpdateControllerMulticastListRspBuilder { status }.build()
- }
-
- fn command_range_start(&mut self, cmd: SessionStartCmd) -> SessionStartRsp {
- log::debug!("[{}:0x{:x}] Range Start", self.device_handle, self.id);
- assert_eq!(self.id, cmd.get_session_id());
-
- let status = if self.state != SessionState::SessionStateIdle {
- StatusCode::UciStatusSessionNotConfigured
- } else {
- assert!(self.ranging_task.is_none());
- assert_eq!(self.state, SessionState::SessionStateIdle);
-
- let session_id = self.id;
- let ranging_interval = self.app_config.ranging_interval;
- let device_handle = self.device_handle;
- let tx = self.pica_tx.clone();
- self.ranging_task = Some(tokio::spawn(async move {
- loop {
- time::sleep(ranging_interval).await;
- tx.send(PicaCommand::Ranging(device_handle, session_id))
- .await
- .unwrap();
- }
- }));
- self.set_state(
- SessionState::SessionStateActive,
- ReasonCode::StateChangeWithSessionManagementCommands,
- );
- StatusCode::UciStatusOk
- };
- SessionStartRspBuilder { status }.build()
- }
-
pub fn stop_ranging_task(&mut self) {
if let Some(handle) = &self.ranging_task {
handle.abort();
self.ranging_task = None;
}
}
- fn command_range_stop(&mut self, cmd: SessionStopCmd) -> SessionStopRsp {
- log::debug!("[{}:0x{:x}] Range Stop", self.device_handle, self.id);
- assert_eq!(self.id, cmd.get_session_id());
-
- let status = if self.state != SessionState::SessionStateActive {
- StatusCode::UciStatusSessionActive
- } else {
- self.stop_ranging_task();
- self.set_state(
- SessionState::SessionStateIdle,
- ReasonCode::StateChangeWithSessionManagementCommands,
- );
- StatusCode::UciStatusOk
- };
- SessionStopRspBuilder { status }.build()
- }
-
- fn command_get_ranging_count(
- &self,
- cmd: SessionGetRangingCountCmd,
- ) -> SessionGetRangingCountRsp {
- log::debug!(
- "[{}:0x{:x}] Range Get Ranging Count",
- self.device_handle,
- self.id
- );
- assert_eq!(self.id, cmd.get_session_id());
-
- SessionGetRangingCountRspBuilder {
- status: StatusCode::UciStatusOk,
- count: self.sequence_number,
- }
- .build()
- }
-
- pub fn session_command(&mut self, cmd: SessionConfigCommand) -> SessionConfigResponse {
- match cmd.specialize() {
- SessionConfigCommandChild::SessionSetAppConfigCmd(cmd) => {
- self.command_set_app_config(cmd).into()
- }
- SessionConfigCommandChild::SessionGetAppConfigCmd(cmd) => {
- self.command_get_app_config(cmd).into()
- }
- SessionConfigCommandChild::SessionGetStateCmd(cmd) => {
- self.command_get_state(cmd).into()
- }
- SessionConfigCommandChild::SessionUpdateControllerMulticastListCmd(cmd) => {
- self.command_update_controller_multicast_list(cmd).into()
- }
- _ => panic!("Unsupported session command"),
- }
- }
-
- pub fn ranging_command(&mut self, cmd: SessionControlCommand) -> SessionControlResponse {
- match cmd.specialize() {
- SessionControlCommandChild::SessionStartCmd(cmd) => {
- self.command_range_start(cmd).into()
- }
- SessionControlCommandChild::SessionStopCmd(cmd) => self.command_range_stop(cmd).into(),
- SessionControlCommandChild::SessionGetRangingCountCmd(cmd) => {
- self.command_get_ranging_count(cmd).into()
- }
- _ => panic!("Unsupported ranging command"),
- }
- }
- pub fn data_message_snd(&mut self, data: DataMessageSnd) -> SessionControlNotification {
+ pub fn data_message_snd(&mut self, data: DataMessageSnd) -> ControlPacket {
log::debug!("[{}] data_message_snd", self.device_handle);
let session_token = data.get_session_handle();
let uci_sequence_number = data.get_data_sequence_number() as u8;
if self.session_type != SessionType::FiraRangingAndInBandDataSession {
- return DataTransferStatusNtfBuilder {
+ return SessionDataTransferStatusNtfBuilder {
session_token,
status: DataTransferNtfStatusCode::UciDataTransferStatusSessionTypeNotSupported,
tx_count: 1, // TODO: support for retries?
@@ -1230,7 +150,7 @@ impl Session {
self.data.extend_from_slice(data.get_application_data());
- DataCreditNtfBuilder {
+ SessionDataCreditNtfBuilder {
credit_availability: CreditAvailability::CreditAvailable,
session_token,
}
diff --git a/src/uci_packets.pdl b/src/uci_packets.pdl
index 07b19b6..05ba3f3 100644
--- a/src/uci_packets.pdl
+++ b/src/uci_packets.pdl
@@ -15,154 +15,126 @@
little_endian_packets
enum PacketBoundaryFlag : 1 {
- COMPLETE = 0x00,
- NOT_COMPLETE = 0x01,
+ COMPLETE = 0,
+ NOT_COMPLETE = 1,
+}
+
+enum MessageType : 3 {
+ DATA = 0x0,
+ COMMAND = 0x1,
+ RESPONSE = 0x2,
+ NOTIFICATION = 0x3,
}
enum GroupId : 4 {
- CORE = 0x00,
- SESSION_CONFIG = 0x01,
- SESSION_CONTROL = 0x02,
- DATA_CONTROL = 0x03,
- TEST = 0x0d,
- VENDOR_RESERVED_9 = 0x09,
- VENDOR_RESERVED_A = 0x0a,
- VENDOR_RESERVED_B = 0x0b,
- VENDOR_ANDROID = 0x0c,
- VENDOR_RESERVED_E = 0x0e,
- VENDOR_RESERVED_F = 0x0f,
-}
-
-enum DataPacketFormat: 4 {
+ CORE = 0x0,
+ SESSION_CONFIG = 0x1,
+ SESSION_CONTROL = 0x2,
+ DATA_CONTROL = 0x3,
+ VENDOR_RESERVED_9 = 0x9,
+ VENDOR_RESERVED_A = 0xa,
+ VENDOR_RESERVED_B = 0xb,
+ VENDOR_ANDROID = 0xc,
+ TEST = 0xd,
+ VENDOR_RESERVED_E = 0xe,
+ VENDOR_RESERVED_F = 0xf,
+}
+
+enum DataPacketFormat : 4 {
DATA_SND = 0x01,
DATA_RCV = 0x02,
}
-// Define a merged enum across GroupId & DataPacketFormat as they are at the same bits in
-// |UciPacketHal|.
-enum GroupIdOrDataPacketFormat : 4 {
- CORE = 0x00,
- SESSION_CONFIG_OR_DATA_SND = 0x01,
- SESSION_CONTROL_OR_DATA_RCV = 0x02,
- DATA_CONTROL = 0x03,
- TEST = 0x0d,
- VENDOR_RESERVED_9 = 0x09,
- VENDOR_RESERVED_A = 0x0a,
- VENDOR_RESERVED_B = 0x0b,
- VENDOR_ANDROID = 0x0c,
- VENDOR_RESERVED_E = 0x0e,
- VENDOR_RESERVED_F = 0x0f,
-}
-
-enum CoreOpCode : 6 {
- CORE_DEVICE_RESET = 0x00,
- CORE_DEVICE_STATUS_NTF = 0x01,
- CORE_DEVICE_INFO = 0x02,
- CORE_GET_CAPS_INFO = 0x03,
- CORE_SET_CONFIG = 0x04,
- CORE_GET_CONFIG = 0x05,
- CORE_DEVICE_SUSPEND = 0x06,
- CORE_GENERIC_ERROR_NTF = 0x07,
- CORE_QUERY_UWBS_TIMESTAMP = 0x08,
-}
-
-enum SessionConfigOpCode : 6 {
- SESSION_INIT = 0x00,
- SESSION_DEINIT = 0x01,
- SESSION_STATUS_NTF = 0x02,
- SESSION_SET_APP_CONFIG = 0x03,
- SESSION_GET_APP_CONFIG = 0x04,
- SESSION_GET_COUNT = 0x05,
- SESSION_GET_STATE = 0x06,
- SESSION_UPDATE_CONTROLLER_MULTICAST_LIST = 0x07,
- SESSION_UPDATE_ACTIVE_ROUNDS_ANCHOR = 0x08,
- SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG = 0x09,
- SESSION_SET_INITIATOR_DT_ANCHOR_RR_RDM_LIST = 0x0a,
- SESSION_QUERY_DATA_SIZE_IN_RANGING = 0x0b,
- SESSION_SET_HUS_CONFIG = 0x0c,
-}
-
-enum SessionControlOpCode : 6 {
- SESSION_START = 0x00,
- SESSION_STOP = 0x01,
- SESSION_RESERVED = 0x02,
- SESSION_GET_RANGING_COUNT = 0x03,
- SESSION_DATA_CREDIT_NTF = 0x04,
- SESSION_DATA_TRANSFER_STATUS_NTF = 0x05,
-}
-
-enum AppDataOpCode : 6 {
- APP_DATA_TX = 0x00,
- APP_DATA_RX = 0x01,
-}
-
-// Android vendor commands
-enum AndroidOpCode : 6 {
- ANDROID_GET_POWER_STATS = 0x0,
- ANDROID_SET_COUNTRY_CODE = 0x1,
- ANDROID_FIRA_RANGE_DIAGNOSTICS = 0x2,
-}
-
-enum StatusCode : 8 {
+enum CoreOpcodeId : 6 {
+ DEVICE_RESET = 0x00,
+ DEVICE_STATUS = 0x01,
+ GET_DEVICE_INFO = 0x02,
+ GET_CAPS_INFO = 0x03,
+ SET_CONFIG = 0x04,
+ GET_CONFIG = 0x05,
+ GENERIC_ERROR = 0x07,
+ QUERY_UWBS_TIMESTAMP = 0x08,
+}
+
+enum SessionConfigOpcodeId : 6 {
+ INIT = 0x00,
+ DEINIT = 0x01,
+ STATUS = 0x02,
+ SET_APP_CONFIG = 0x03,
+ GET_APP_CONFIG = 0x04,
+ GET_COUNT = 0x05,
+ GET_STATE = 0x06,
+ UPDATE_CONTROLLER_MULTICAST_LIST = 0x07,
+ UPDATE_DT_ANCHOR_RANGING_ROUNDS = 0x08,
+ UPDATE_DT_TAG_RANGING_ROUNDS = 0x09,
+ QUERY_DATA_SIZE_IN_RANGING = 0x0b,
+}
+
+enum SessionControlOpcodeId : 6 {
+ START = 0x00, // INFO_NTF
+ STOP = 0x01,
+ GET_RANGING_COUNT = 0x03,
+ DATA_CREDIT = 0x04,
+ DATA_TRANSFER_STATUS = 0x05,
+}
+
+enum AndroidOpcodeId : 6 {
+ GET_POWER_STATS = 0x00,
+ SET_COUNTRY_CODE = 0x01,
+ FIRA_RANGE_DIAGNOSTICS = 0x02,
+}
+
+/// [UCI] 8.5 Status Codes
+enum Status : 8 {
// Generic Status Codes
- UCI_STATUS_OK = 0x00,
- UCI_STATUS_REJECTED = 0x01,
- UCI_STATUS_FAILED = 0x02,
- UCI_STATUS_SYNTAX_ERROR = 0x03,
- UCI_STATUS_INVALID_PARAM = 0x04,
- UCI_STATUS_INVALID_RANGE = 0x05,
- UCI_STATUS_INVALID_MSG_SIZE = 0x06,
- UCI_STATUS_UNKNOWN_GID = 0x07,
- UCI_STATUS_UNKNOWN_OID = 0x08,
- UCI_STATUS_READ_ONLY = 0x09,
- UCI_STATUS_COMMAND_RETRY = 0x0A,
- UCI_STATUS_UNKNOWN = 0x0B,
- UCI_STATUS_NOT_APPLICABLE = 0x0C,
- RFU_STATUS_CODE_RANGE_1 = 0x0D..0x10,
+ OK = 0x00,
+ REJECTED = 0x01,
+ FAILED = 0x02,
+ SYNTAX_ERROR = 0x03,
+ INVALID_PARAM = 0x04,
+ INVALID_RANGE = 0x05,
+ INVALID_MESSAGE_SIZE = 0x06,
+ UNKNOWN_GID = 0x07,
+ UNKNOWN_OID = 0x08,
+ READ_ONLY = 0x09,
+ UCI_MESSAGE_RETRY = 0x0A,
+ UNKNOWN = 0x0B,
+ NOT_APPLICABLE = 0x0C,
// UWB Session Specific Status Codes
- UCI_STATUS_SESSION_NOT_EXIST = 0x11,
- UCI_STATUS_SESSION_DUPLICATE = 0x12,
- UCI_STATUS_SESSION_ACTIVE = 0x13,
- UCI_STATUS_MAX_SESSIONS_EXCEEDED = 0x14,
- UCI_STATUS_SESSION_NOT_CONFIGURED = 0x15,
- UCI_STATUS_ACTIVE_SESSIONS_ONGOING = 0x16,
- UCI_STATUS_MULTICAST_LIST_FULL = 0x17,
- UCI_STATUS_ADDRESS_NOT_FOUND = 0x18,
- UCI_STATUS_ADDRESS_ALREADY_PRESENT = 0x19,
- UCI_STATUS_ERROR_UWB_INITIATION_TIME_TOO_OLD = 0x1A,
- UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT = 0x1B,
- RFU_STATUS_CODE_RANGE_2 = 0x1C..0x1F,
+ ERROR_SESSION_NOT_EXIST = 0x11,
+ ERROR_SESSION_DUPLICATE = 0x12,
+ ERROR_SESSION_ACTIVE = 0x13,
+ ERROR_MAX_SESSIONS_EXCEEDED = 0x14,
+ ERROR_SESSION_NOT_CONFIGURED = 0x15,
+ ERROR_ACTIVE_SESSIONS_ONGOING = 0x16,
+ ERROR_MULTICAST_LIST_FULL = 0x17,
+ ERROR_UWB_INITIATION_TIME_TOO_OLD = 0x1A,
+ OK_NEGATIVE_DISTANCE_REPORT = 0x1B,
// UWB Ranging Session Specific Status Codes
- UCI_STATUS_RANGING_TX_FAILED = 0x20,
- UCI_STATUS_RANGING_RX_TIMEOUT = 0x21,
- UCI_STATUS_RANGING_RX_PHY_DEC_FAILED = 0x22,
- UCI_STATUS_RANGING_RX_PHY_TOA_FAILED = 0x23,
- UCI_STATUS_RANGING_RX_PHY_STS_FAILED = 0x24,
- UCI_STATUS_RANGING_RX_MAC_DEC_FAILED = 0x25,
- UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED = 0x26,
- UCI_STATUS_RANGING_RX_MAC_IE_MISSING = 0x27,
- UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED = 0x28,
- UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 0x29,
- UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 0x2A,
- RFU_STATUS_CODE_RANGE_3 = 0x2B..0x2F,
-
- // UWB Data Session Specific Status Codes
- UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED = 0x30,
- UCI_STATUS_DATA_RX_CRC_ERROR = 0x31,
- RFU_STATUS_CODE_RANGE_4 = 0x32..0x4F,
+ RANGING_TX_FAILED = 0x20,
+ RANGING_RX_TIMEOUT = 0x21,
+ RANGING_RX_PHY_DEC_FAILED = 0x22,
+ RANGING_RX_PHY_TOA_FAILED = 0x23,
+ RANGING_RX_PHY_STS_FAILED = 0x24,
+ RANGING_RX_MAC_DEC_FAILED = 0x25,
+ RANGING_RX_MAC_IE_DEC_FAILED = 0x26,
+ RANGING_RX_MAC_IE_MISSING = 0x27,
+ ERROR_ROUND_INDEX_NOT_ACTIVATED = 0x28,
+ ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 0x29,
+ ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 0x2A,
// Vendor Specific Status Codes
- VENDOR_SPECIFIC_STATUS_CODE_RANGE_1 = 0x50..0xFE {
- UCI_STATUS_ERROR_CCC_SE_BUSY = 0x50,
- UCI_STATUS_ERROR_CCC_LIFECYCLE = 0x51,
- UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x52,
- UCI_STATUS_REGULATION_UWB_OFF = 0x53,
+ VENDOR_SPECIFIC = 0x50..0xFF {
+ ERROR_CCC_SE_BUSY = 0x50,
+ ERROR_CCC_LIFECYCLE = 0x51,
+ ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x52,
+ REGULATION_UWB_OFF = 0x53,
},
- // For internal usage, we will use 0xFF as default.
- VENDOR_SPECIFIC_STATUS_CODE_2 = 0xFF,
+ // All others reserved for future use
+ RFU = ..,
}
// This needs a separate StatusCode as the Status code values in the DATA_RCV packet have
@@ -194,18 +166,14 @@ enum ResetConfig : 8 {
UWBS_RESET = 0x00,
}
-enum DeviceConfigId : 8 {
- DEVICE_STATE = 0x00,
- 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 +182,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 +196,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 +217,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 +227,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 +238,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 +252,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 +265,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 {
@@ -441,15 +580,17 @@ enum ReasonCode : 8 {
VENDOR_SPECIFIC_REASON_CODE_2 = 0xFF,
}
-enum MulticastUpdateStatusCode : 8 {
- STATUS_OK_MULTICAST_LIST_UPDATE = 0x00,
- STATUS_ERROR_MULTICAST_LIST_FULL = 0x01,
- STATUS_ERROR_KEY_FETCH_FAIL = 0x02,
- STATUS_ERROR_SUB_SESSION_ID_NOT_FOUND = 0x03,
- STATUS_ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x05,
- STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x06,
- STATUS_ERROR_SESSION_KEY_NOT_FOUND = 0x07,
- STATUS_ERROR_ADDRESS_ALREADY_PRESENT = 0x08,
+/// [UCI] Table 40: Multicast list update status codes
+enum MulticastUpdateStatus : 8 {
+ OK_MULTICAST_LIST_UPDATE = 0x00,
+ ERROR_MULTICAST_LIST_FULL = 0x01,
+ ERROR_KEY_FETCH_FAIL = 0x02,
+ ERROR_SUB_SESSION_ID_NOT_FOUND = 0x03,
+ ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x04,
+ ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x05,
+ ERROR_SESSION_KEY_NOT_FOUND = 0x06,
+ ERROR_ADDRESS_NOT_FOUND = 0x07,
+ ERROR_ADDRESS_ALREADY_PRESENT = 0x08,
}
enum MacAddressIndicator : 8 {
@@ -468,15 +609,6 @@ enum SessionType: 8 {
DEVICE_TEST_MODE = 0xD0,
}
-enum MessageType: 3 {
- DATA = 0x00,
- COMMAND = 0x01,
- RESPONSE = 0x02,
- NOTIFICATION = 0x03,
- RESERVED_FOR_TESTING_1 = 0x04,
- RESERVED_FOR_TESTING_2 = 0x05,
-}
-
// Used to parse message type
packet CommonPacketHeader {
_reserved_ : 4,
@@ -509,9 +641,6 @@ packet ControlPacket {
gid : GroupId,
_reserved_ : 1,
mt : MessageType,
- opcode: 6,
- _reserved_: 2,
- _reserved_: 16,
_payload_,
}
@@ -534,109 +663,76 @@ packet DataMessageSnd : DataPacket (dpf = DATA_SND, mt = DATA) {
packet DataMessageRcv : DataPacket (dpf = DATA_RCV, mt = DATA) {
session_handle: 32,
- status : StatusCode,
+ status: Status,
source_address: 64,
data_sequence_number: 16,
_size_(application_data): 16,
application_data: 8[]
}
-// TODO(b/202760099): Handle fragmentation of packets if the size exceed max allowed.
-packet UciCommand : ControlPacket (mt = COMMAND) {
- _payload_,
-}
-
-packet UciResponse : ControlPacket (mt = RESPONSE) {
- _payload_,
-}
-
-packet UciNotification : ControlPacket (mt = NOTIFICATION) {
- _payload_,
-}
-
-packet CoreCommand : UciCommand (gid = CORE) {
- _body_,
-}
-
-packet CoreResponse : UciResponse (gid = CORE) {
- _body_,
-}
-
-packet CoreNotification : UciNotification (gid = CORE) {
- _body_,
-}
-
-packet SessionConfigCommand : UciCommand (gid = SESSION_CONFIG) {
- _body_,
-}
-
-packet SessionConfigResponse : UciResponse (gid = SESSION_CONFIG) {
- _body_,
-}
-
-packet SessionConfigNotification : UciNotification (gid = SESSION_CONFIG) {
- _body_,
-}
-
-packet SessionControlCommand : UciCommand (gid = SESSION_CONTROL) {
- session_id: 32,
- _body_,
-}
-
-packet SessionControlResponse : UciResponse (gid = SESSION_CONTROL) {
- _body_,
+packet CorePacket : ControlPacket (gid = CORE) {
+ oid : CoreOpcodeId,
+ _reserved_ : 2,
+ _reserved_ : 16,
+ _payload_,
}
-packet SessionControlNotification : UciNotification (gid = SESSION_CONTROL) {
- _body_,
+packet SessionConfigPacket : ControlPacket (gid = SESSION_CONFIG) {
+ oid : SessionConfigOpcodeId,
+ _reserved_ : 2,
+ _reserved_ : 16,
+ _payload_,
}
-packet AndroidCommand : UciCommand (gid = VENDOR_ANDROID) {
- _body_,
+packet SessionControlPacket : ControlPacket (gid = SESSION_CONTROL) {
+ oid : SessionControlOpcodeId,
+ _reserved_ : 2,
+ _reserved_ : 16,
+ _payload_,
}
-packet AndroidResponse : UciResponse (gid = VENDOR_ANDROID) {
- _body_,
+packet AndroidPacket : ControlPacket (gid = VENDOR_ANDROID) {
+ oid : AndroidOpcodeId,
+ _reserved_ : 2,
+ _reserved_ : 16,
+ _payload_,
}
-packet AndroidNotification : UciNotification (gid = VENDOR_ANDROID) {
- _body_,
-}
+// ---------------------------- Core group ---------------------------------- //
-// TODO: b/202760099: Use the correspnding opcode enum instead of the raw value in the |opcode| field.
-packet DeviceResetCmd : CoreCommand (opcode = 0x0) { //CORE_DEVICE_RESET
+packet CoreDeviceResetCmd : CorePacket (mt = COMMAND, oid = DEVICE_RESET) {
reset_config: ResetConfig,
}
-test DeviceResetCmd {
+test CoreDeviceResetCmd {
"\x20\x00\x00\x01\x00\x00\x00\x00",
}
-packet DeviceResetRsp : CoreResponse (opcode = 0x0) { //CORE_DEVICE_RESET
- status: StatusCode,
+packet CoreDeviceResetRsp : CorePacket (mt = RESPONSE, oid = DEVICE_RESET) {
+ status: Status,
}
-test DeviceResetRsp {
+test CoreDeviceResetRsp {
"\x40\x00\x00\x01\x00\x00\x00\x00",
}
-packet DeviceStatusNtf : CoreNotification (opcode = 0x1) { //CORE_DEVICE_STATUS_NTF
+packet CoreDeviceStatusNtf : CorePacket (mt = NOTIFICATION, oid = DEVICE_STATUS) {
device_state: DeviceState,
}
-test DeviceStatusNtf {
+test CoreDeviceStatusNtf {
"\x60\x01\x00\x01\x00\x00\x00\x01",
}
-packet GetDeviceInfoCmd : CoreCommand (opcode = 0x2) { //CORE_DEVICE_INFO
+packet CoreGetDeviceInfoCmd : CorePacket (mt = COMMAND, oid = GET_DEVICE_INFO) {
}
-test GetDeviceInfoCmd {
+test CoreGetDeviceInfoCmd {
"\x20\x02\x00\x00\x00\x00\x00",
}
-packet GetDeviceInfoRsp : CoreResponse (opcode = 0x2) { //CORE_DEVICE_INFO
- status: StatusCode,
+packet CoreGetDeviceInfoRsp : CorePacket (mt = RESPONSE, oid = GET_DEVICE_INFO) {
+ status: Status,
uci_version: 16,
mac_version: 16,
phy_version: 16,
@@ -645,14 +741,14 @@ packet GetDeviceInfoRsp : CoreResponse (opcode = 0x2) { //CORE_DEVICE_INFO
vendor_spec_info: 8[],
}
-test GetDeviceInfoRsp {
+test CoreGetDeviceInfoRsp {
"\x40\x02\x00\x0b\x00\x00\x00\x01\x01\x00\x02\x00\x03\x00\x04\x00\x01\x0a",
}
-packet GetCapsInfoCmd : CoreCommand (opcode = 0x3) { //CORE_GET_CAPS_INFO
+packet CoreGetCapsInfoCmd : CorePacket (mt = COMMAND, oid = GET_CAPS_INFO) {
}
-test GetCapsInfoCmd {
+test CoreGetCapsInfoCmd {
"\x20\x03\x00\x00\x00\x00\x00",
}
@@ -663,84 +759,91 @@ struct CapTlv {
}
-packet GetCapsInfoRsp : CoreResponse (opcode = 0x3) { //CORE_GET_CAPS_INFO
- status: StatusCode,
+packet CoreGetCapsInfoRsp : CorePacket (mt = RESPONSE, oid = GET_CAPS_INFO) {
+ status: Status,
_count_(tlvs): 8,
tlvs: CapTlv[],
}
-test GetCapsInfoRsp {
+test CoreGetCapsInfoRsp {
"\x40\x03\x00\x05\x00\x00\x00\x00\x01\x00\x01\x01",
}
-struct DeviceConfigTlv {
- cfg_id: DeviceConfigId,
- _count_(v): 8,
- v: 8[],
+// [UCI] Table 44: Device Configuration Parameters
+enum ConfigParameterId : 8 {
+ DEVICE_STATE = 0x00,
+ LOW_POWER_MODE = 0x01,
+ RFU = ..,
}
-packet SetConfigCmd : CoreCommand (opcode = 0x4) { //CORE_SET_CONFIG
- _count_(tlvs): 8,
- tlvs: DeviceConfigTlv[],
+struct ConfigParameter {
+ id: ConfigParameterId,
+ _size_(value): 8,
+ value: 8[],
}
-test SetConfigCmd {
+packet CoreSetConfigCmd : CorePacket (mt = COMMAND, oid = SET_CONFIG) {
+ _count_(parameters): 8,
+ parameters: ConfigParameter[],
+}
+
+test CoreSetConfigCmd {
"\x20\x04\x00\x03\x00\x00\x00\x01\x01\x00",
}
-struct DeviceConfigStatus {
- cfg_id: DeviceConfigId,
- status: StatusCode,
+struct ConfigParameterStatus {
+ id: ConfigParameterId,
+ status: Status,
}
-packet SetConfigRsp : CoreResponse (opcode = 0x4) { //CORE_SET_CONFIG
- status: StatusCode,
- _count_(cfg_status): 8,
- cfg_status: DeviceConfigStatus[],
+packet CoreSetConfigRsp : CorePacket (mt = RESPONSE, oid = SET_CONFIG) {
+ status: Status,
+ _count_(parameters): 8,
+ parameters: ConfigParameterStatus[],
}
-test SetConfigRsp {
+test CoreSetConfigRsp {
"\x40\x04\x00\x04\x00\x00\x00\x01\x01\x01\x01",
"\x40\x04\x00\x04\x00\x00\x00\x01\x01\x01\x0B",
}
-packet GetConfigCmd : CoreCommand (opcode = 0x5) { //CORE_GET_CONFIG
- _count_(cfg_id): 8,
- cfg_id: 8[], // DeviceConfigId (Infra does not allow array of enums)
+packet CoreGetConfigCmd : CorePacket (mt = COMMAND, oid = GET_CONFIG) {
+ _count_(parameter_ids): 8,
+ parameter_ids: ConfigParameterId[],
}
-test GetConfigCmd {
+test CoreGetConfigCmd {
"\x20\x05\x00\x02\x00\x00\x00\x01\x01",
}
-packet GetConfigRsp : CoreResponse (opcode = 0x5) { //CORE_GET_CONFIG
- status: StatusCode,
- _count_(tlvs): 8,
- tlvs: DeviceConfigTlv[]
+packet CoreGetConfigRsp : CorePacket (mt = RESPONSE, oid = GET_CONFIG) {
+ status: Status,
+ _count_(parameters): 8,
+ parameters: ConfigParameter[]
}
-test GetConfigRsp {
+test CoreGetConfigRsp {
"\x40\x05\x00\x05\x00\x00\x00\x01\x01\x00\x01\x01",
}
-packet GenericError : CoreNotification (opcode = 0x7) { //CORE_GENERIC_ERROR_NTF
- status: StatusCode,
+packet CoreGenericErrorNtf : CorePacket (mt = NOTIFICATION, oid = GENERIC_ERROR) {
+ status: Status,
}
-test GenericError {
+test CoreGenericErrorNtf {
"\x60\x07\x00\x01\x00\x00\x00\x01",
}
-packet CoreQueryTimeStampCmd : CoreCommand (opcode = 0x8) { //CORE_QUERY_UWBS_TIMESTAMP
+packet CoreQueryTimeStampCmd : CorePacket (mt = COMMAND, oid = QUERY_UWBS_TIMESTAMP) {
}
test CoreQueryTimeStampCmd {
"\x20\x08\x00\\x00",
}
-packet CoreQueryTimeStampRsp : CoreResponse (opcode = 0x8) { //CORE_QUERY_UWBS_TIMESTAMP
- status: StatusCode,
+packet CoreQueryTimeStampRsp : CorePacket (mt = RESPONSE, oid = QUERY_UWBS_TIMESTAMP) {
+ status: Status,
timeStamp: 64,
}
@@ -748,7 +851,9 @@ test CoreQueryTimeStampRsp {
"\x40\x08\x00\x09\x00\x00\x00\x01\x01\x00\x01\x01\x01",
}
-packet SessionInitCmd : SessionConfigCommand (opcode = 0x0) { //SESSION_INIT
+// ---------------------- Session Config group ------------------------------ //
+
+packet SessionInitCmd : SessionConfigPacket (mt = COMMAND, oid = INIT) {
session_id: 32,
session_type: SessionType,
}
@@ -759,8 +864,8 @@ test SessionInitCmd {
// FIRA version 2 introduces a new version of SESSION_INIT_RSP which
// includes UWBS generated session handle.
-packet SessionInitRsp_V2 : SessionConfigResponse (opcode = 0x0) { //SESSION_INIT
- status: StatusCode,
+packet SessionInitRsp_V2 : SessionConfigPacket (mt = RESPONSE, oid = INIT) {
+ status: Status,
session_handle: 32,
}
@@ -768,15 +873,15 @@ test SessionInitRsp_V2 {
"\x41\x00\x00\x01\x00\x00\x00\x11\x00\x00\x00\x01",
}
-packet SessionInitRsp : SessionConfigResponse (opcode = 0x0) { //SESSION_INIT
- status: StatusCode,
+packet SessionInitRsp : SessionConfigPacket (mt = RESPONSE, oid = INIT) {
+ status: Status,
}
test SessionInitRsp {
"\x41\x00\x00\x01\x00\x00\x00\x11",
}
-packet SessionDeinitCmd : SessionConfigCommand (opcode = 0x1) { //SESSION_DEINIT
+packet SessionDeinitCmd : SessionConfigPacket (mt = COMMAND, oid = DEINIT) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
}
@@ -784,15 +889,15 @@ test SessionDeinitCmd {
"\x21\x01\x00\x04\x00\x00\x00\x01\x02\x03\x04",
}
-packet SessionDeinitRsp : SessionConfigResponse (opcode = 0x1) { //SESSION_DEINIT
- status: StatusCode,
+packet SessionDeinitRsp : SessionConfigPacket (mt = RESPONSE, oid = DEINIT) {
+ status: Status,
}
test SessionDeinitRsp {
"\x41\x01\x00\x01\x00\x00\x00\x00",
}
-packet SessionStatusNtf : SessionConfigNotification (opcode = 0x2) { //SESSION_STATUS_NTF
+packet SessionStatusNtf : SessionConfigPacket (mt = NOTIFICATION, oid = STATUS) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
session_state: SessionState,
// TODO(b/272775225): Switch back to the enum type ReasonCode, once PDL supports defining a
@@ -811,7 +916,7 @@ struct AppConfigTlv {
v: 8[],
}
-packet SessionSetAppConfigCmd : SessionConfigCommand (opcode = 0x3) { //SESSION_SET_APP_CONFIG
+packet SessionSetAppConfigCmd : SessionConfigPacket (mt = COMMAND, oid = SET_APP_CONFIG) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
_count_(tlvs): 8,
tlvs: AppConfigTlv[]
@@ -823,11 +928,11 @@ test SessionSetAppConfigCmd {
struct AppConfigStatus {
cfg_id: AppConfigTlvType,
- status: StatusCode,
+ status: Status,
}
-packet SessionSetAppConfigRsp : SessionConfigResponse (opcode = 0x3) { //SESSION_SET_APP_CONFIG
- status: StatusCode,
+packet SessionSetAppConfigRsp : SessionConfigPacket (mt = RESPONSE, oid = SET_APP_CONFIG) {
+ status: Status,
_count_(cfg_status): 8,
cfg_status: AppConfigStatus[],
}
@@ -836,18 +941,18 @@ test SessionSetAppConfigRsp {
"\x41\x03\x00\x04\x00\x00\x00\x01\x01\x01\x00",
}
-packet SessionGetAppConfigCmd : SessionConfigCommand (opcode = 0x4) { //SESSION_GET_APP_CONFIG
+packet SessionGetAppConfigCmd : SessionConfigPacket (mt = COMMAND, oid = 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 {
"\x21\x04\x00\x05\x00\x00\x00\x01\x02\x03\x04\x00",
}
-packet SessionGetAppConfigRsp : SessionConfigResponse (opcode = 0x4) { //SESSION_GET_APP_CONFIG
- status: StatusCode,
+packet SessionGetAppConfigRsp : SessionConfigPacket (mt = RESPONSE, oid = GET_APP_CONFIG) {
+ status: Status,
_count_(tlvs): 8,
tlvs: AppConfigTlv[],
}
@@ -856,15 +961,15 @@ test SessionGetAppConfigRsp {
"\x41\x04\x00\x02\x00\x00\x00\x01\x00",
}
-packet SessionGetCountCmd : SessionConfigCommand (opcode = 0x5) { //SESSION_GET_COUNT
+packet SessionGetCountCmd : SessionConfigPacket (mt = COMMAND, oid = GET_COUNT) {
}
test SessionGetCountCmd {
"\x21\x05\x00\x00\x00\x00\x00",
}
-packet SessionGetCountRsp : SessionConfigResponse (opcode = 0x5) { //SESSION_GET_COUNT
- status: StatusCode,
+packet SessionGetCountRsp : SessionConfigPacket (mt = RESPONSE, oid = GET_COUNT) {
+ status: Status,
session_count: 8,
}
@@ -872,7 +977,7 @@ test SessionGetCountRsp {
"\x41\x05\x00\x02\x00\x00\x00\x00\x01",
}
-packet SessionGetStateCmd : SessionConfigCommand (opcode = 0x6) { //SESSION_GET_STATE
+packet SessionGetStateCmd : SessionConfigPacket (mt = COMMAND, oid = GET_STATE) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
}
@@ -880,8 +985,8 @@ test SessionGetStateCmd {
"\x21\x06\x00\x04\x00\x00\x00\x00\x01\x02\x03",
}
-packet SessionGetStateRsp : SessionConfigResponse (opcode = 0x6) { //SESSION_GET_STATE
- status: StatusCode,
+packet SessionGetStateRsp : SessionConfigPacket (mt = RESPONSE, oid = GET_STATE) {
+ status: Status,
session_state: SessionState,
}
@@ -889,7 +994,15 @@ test SessionGetStateRsp {
"\x41\x06\x00\x02\x00\x00\x00\x00\x01",
}
-packet SessionUpdateDtTagRangingRoundsCmd : SessionConfigCommand (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
+packet SessionUpdateDtAnchorRangingRoundsCmd : SessionConfigPacket (mt = COMMAND, oid = UPDATE_DT_ANCHOR_RANGING_ROUNDS) {
+ // TODO
+}
+
+packet SessionUpdateDtAnchorRangingRoundsRsp : SessionConfigPacket (mt = RESPONSE, oid = UPDATE_DT_ANCHOR_RANGING_ROUNDS) {
+ // TODO
+}
+
+packet SessionUpdateDtTagRangingRoundsCmd : SessionConfigPacket (mt = COMMAND, oid = UPDATE_DT_TAG_RANGING_ROUNDS) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
_count_(ranging_round_indexes): 8,
ranging_round_indexes: 8[],
@@ -899,8 +1012,8 @@ test SessionUpdateDtTagRangingRoundsCmd {
"\x21\x09\x00\x0a\x00\x00\x00\x03\x03\x0f\x0c\x05\x08\x00\x00\x00\x00",
}
-packet SessionUpdateDtTagRangingRoundsRsp : SessionConfigResponse (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
- status: StatusCode,
+packet SessionUpdateDtTagRangingRoundsRsp : SessionConfigPacket (mt = RESPONSE, oid = UPDATE_DT_TAG_RANGING_ROUNDS) {
+ status: Status,
_count_(ranging_round_indexes): 8,
ranging_round_indexes: 8[],
}
@@ -926,36 +1039,20 @@ 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
+packet SessionUpdateControllerMulticastListCmd : SessionConfigPacket (mt = COMMAND, oid = UPDATE_CONTROLLER_MULTICAST_LIST) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
action: UpdateMulticastListAction,
_payload_,
}
-struct PhaseList {
- session_token: 32,
- start_slot_index: 16,
- end_slot_index: 16,
-}
-
-packet SessionSetHybridConfigCmd : SessionConfigCommand (opcode = 0x0c) { //SESSION_SET_HUS_CONFIG
- session_token: 32,
- number_of_phases: 8,
- update_time: 8[8],
- phase_list: PhaseList[],
-}
-
-packet SessionSetHybridConfigRsp : SessionConfigResponse (opcode = 0x0c) { //SESSION_SET_HUS_CONFIG
- status: StatusCode,
-}
-
struct SessionUpdateControllerMulticastListCmdPayload {
_count_(controlees): 8,
controlees: Controlee[],
@@ -971,8 +1068,8 @@ struct SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload {
controlees: Controlee_V2_0_32_Byte_Version[],
}
-packet SessionUpdateControllerMulticastListRsp : SessionConfigResponse (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
- status: StatusCode,
+packet SessionUpdateControllerMulticastListRsp : SessionConfigPacket (mt = RESPONSE, oid = UPDATE_CONTROLLER_MULTICAST_LIST) {
+ status: Status,
}
test SessionUpdateControllerMulticastListRsp {
@@ -981,13 +1078,11 @@ test SessionUpdateControllerMulticastListRsp {
struct ControleeStatus {
mac_address: 8[2],
- subsession_id: 32,
- status: MulticastUpdateStatusCode,
+ status: MulticastUpdateStatus,
}
-packet SessionUpdateControllerMulticastListNtf : SessionConfigNotification (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
+packet SessionUpdateControllerMulticastListNtf : SessionConfigPacket (mt = NOTIFICATION, oid = UPDATE_CONTROLLER_MULTICAST_LIST) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
- remaining_multicast_list_size: 8,
_count_(controlee_status): 8,
controlee_status: ControleeStatus[],
}
@@ -996,52 +1091,55 @@ test SessionUpdateControllerMulticastListNtf {
"\x61\x07\x00\x06\x00\x00\x00\x00\x01\x02\x03\x04\x00",
}
-packet DataCreditNtf : SessionControlNotification (opcode = 0x04) { // SESSION_DATA_CREDIT_NTF
+// ---------------------- Session Control group ----------------------------- //
+
+packet SessionDataCreditNtf : SessionControlPacket (mt = NOTIFICATION, oid = DATA_CREDIT) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
credit_availability: CreditAvailability,
}
-test DataCreditNtf {
+test SessionDataCreditNtf {
"\x62\x04\x00\x05\x00\x00\x00\x00\x00\x00\x01\x01",
}
-packet DataTransferStatusNtf : SessionControlNotification (opcode = 0x05) { // SESSION_DATA_TRANSFER_STATUS_NTF
+packet SessionDataTransferStatusNtf : SessionControlPacket (mt = NOTIFICATION, oid = DATA_TRANSFER_STATUS) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
uci_sequence_number: 8,
status: DataTransferNtfStatusCode,
tx_count: 8,
}
-test DataTransferStatusNtf {
+test SessionDataTransferStatusNtf {
"\x62\x05\x00\x06\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00",
}
-packet SessionQueryMaxDataSizeCmd : SessionConfigCommand (opcode = 0xB) { //QUERY_MAX_DATA_SIZE
+packet SessionQueryMaxDataSizeInRangingCmd : SessionConfigPacket (mt = COMMAND, oid = QUERY_DATA_SIZE_IN_RANGING) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
}
-test SessionQueryMaxDataSizeCmd {
+test SessionQueryMaxDataSizeInRangingCmd {
"\x21\x0B\x00\x04\x00\x00\x00\x00",
}
-packet SessionQueryMaxDataSizeRsp : SessionConfigResponse (opcode = 0xB) { //QUER_MAX_DATA_SIZE
+packet SessionQueryMaxDataSizeInRangingRsp : SessionConfigPacket (mt = RESPONSE, oid = QUERY_DATA_SIZE_IN_RANGING) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
max_data_size: 16,
}
-test SessionQueryMaxDataSizeRsp {
+test SessionQueryMaxDataSizeInRangingRsp {
"\x41\x0B\x00\x06\x00\x00\x00\x00\x0E7\0x07",
}
-packet SessionStartCmd : SessionControlCommand (opcode = 0x0) { //RANGE_START
+packet SessionStartCmd : SessionControlPacket (mt = COMMAND, oid = START) {
+ session_id: 32,
}
test SessionStartCmd {
"\x22\x00\x00\x04\x00\x00\x00\x00\x01\x02\x03",
}
-packet SessionStartRsp : SessionControlResponse (opcode = 0x0) { //RANGE_START
- status: StatusCode,
+packet SessionStartRsp : SessionControlPacket (mt = RESPONSE, oid = START) {
+ status: Status,
}
test SessionStartRsp {
@@ -1050,7 +1148,7 @@ test SessionStartRsp {
struct ShortAddressTwoWayRangingMeasurement {
mac_address: 16,
- status: StatusCode,
+ status: Status,
nlos: 8,
distance: 16,
aoa_azimuth: 16,
@@ -1072,7 +1170,7 @@ struct ShortAddressTwoWayRangingMeasurement {
struct ExtendedAddressTwoWayRangingMeasurement {
mac_address: 64,
- status: StatusCode,
+ status: Status,
nlos: 8,
distance: 16,
aoa_azimuth: 16,
@@ -1090,7 +1188,7 @@ struct ExtendedAddressTwoWayRangingMeasurement {
struct ShortAddressOwrAoaRangingMeasurement {
mac_address: 16,
- status: StatusCode,
+ status: Status,
nlos: 8,
frame_sequence_number: 8,
block_index: 16,
@@ -1102,7 +1200,7 @@ struct ShortAddressOwrAoaRangingMeasurement {
struct ExtendedAddressOwrAoaRangingMeasurement {
mac_address: 64,
- status: StatusCode,
+ status: Status,
nlos: 8,
frame_sequence_number: 8,
block_index: 16,
@@ -1119,7 +1217,7 @@ enum RangingMeasurementType : 8 {
OWR_AOA = 0x03,
}
-packet SessionInfoNtf : SessionControlNotification (opcode = 0x0) { // SESSION_INFO
+packet SessionInfoNtf : SessionControlPacket (mt = NOTIFICATION, oid = START) {
sequence_number: 32,
session_token: 32, // Session ID or Session Handle (based on UWBS version)
rcr_indicator: 8,
@@ -1191,30 +1289,32 @@ test ExtendedMacOwrAoaSessionInfoNtf {
"\x62\x00\x00\x2c\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xbb\xcc\xdd\x01\x02\x03\x04\x00\x00\x01\x01\x00\x03\x04\x60\x05\x06\x50",
}
-packet SessionStopCmd : SessionControlCommand (opcode = 0x1) { // SESSION_STOP
+packet SessionStopCmd : SessionControlPacket (mt = COMMAND, oid = STOP) {
+ session_id: 32,
}
test SessionStopCmd {
"\x22\x01\x00\x04\x00\x00\x00\x00\x02\x03\x04",
}
-packet SessionStopRsp : SessionControlResponse (opcode = 0x1) { // SESSION_STOP
- status: StatusCode,
+packet SessionStopRsp : SessionControlPacket (mt = RESPONSE, oid = STOP) {
+ status: Status,
}
test SessionStopRsp {
"\x42\x01\x00\x01\x00\x00\x00\x00",
}
-packet SessionGetRangingCountCmd : SessionControlCommand (opcode = 0x3) { // SESSION_GET_RANGING_COUNT
+packet SessionGetRangingCountCmd : SessionControlPacket (mt = COMMAND, oid = GET_RANGING_COUNT) {
+ session_id: 32,
}
test SessionGetRangingCountCmd {
"\x22\x03\x00\x04\x00\x00\x00\x00\x02\x03\x04",
}
-packet SessionGetRangingCountRsp : SessionControlResponse (opcode = 0x3) { // SESSION_GET_RANGING_COUNT
- status: StatusCode,
+packet SessionGetRangingCountRsp : SessionControlPacket (mt = RESPONSE, oid = GET_RANGING_COUNT) {
+ status: Status,
count: 32,
}
@@ -1222,7 +1322,9 @@ test SessionGetRangingCountRsp {
"\x42\x03\x00\x05\x00\x00\x00\x00\x02\x03\x04\x05",
}
-packet AndroidGetPowerStatsCmd: AndroidCommand (opcode = 0x0) { //ANDROID_GET_POWER_STATS
+// -------------------------- Android group --------------------------------- //
+
+packet AndroidGetPowerStatsCmd : AndroidPacket (mt = COMMAND, oid = GET_POWER_STATS) {
}
test AndroidGetPowerStatsCmd {
@@ -1230,14 +1332,14 @@ test AndroidGetPowerStatsCmd {
}
struct PowerStats {
- status: StatusCode,
+ status: Status,
idle_time_ms: 32,
tx_time_ms: 32,
rx_time_ms: 32,
total_wake_count:32,
}
-packet AndroidGetPowerStatsRsp : AndroidResponse (opcode = 0x0) { //ANDROID_GET_POWER_STATS
+packet AndroidGetPowerStatsRsp : AndroidPacket (mt = RESPONSE, oid = GET_POWER_STATS) {
stats: PowerStats,
}
@@ -1245,7 +1347,7 @@ test AndroidGetPowerStatsRsp {
"\x4c\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
}
-packet AndroidSetCountryCodeCmd: AndroidCommand (opcode = 0x1) { //ANDROID_SET_COUNTRY_CODE
+packet AndroidSetCountryCodeCmd: AndroidPacket (mt = COMMAND, oid = SET_COUNTRY_CODE) {
country_code : 8[2],
}
@@ -1254,14 +1356,20 @@ test AndroidSetCountryCodeCmd {
"\x2c\x01\x00\x02\x00\x00\x00\x55\x53",
}
-packet AndroidSetCountryCodeRsp : AndroidResponse (opcode = 0x1) { //ANDROID_SET_COUNTRY_CODE
- status: StatusCode,
+packet AndroidSetCountryCodeRsp : AndroidPacket (mt = RESPONSE, oid = SET_COUNTRY_CODE) {
+ status: Status,
}
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,
@@ -1324,7 +1432,7 @@ struct FrameReport {
frame_report_tlvs: FrameReportTlv[],
}
-packet AndroidRangeDiagnosticsNtf : AndroidNotification (opcode = 0x2) { //FIRA_RANGE_DIAGNOSTICS
+packet AndroidRangeDiagnosticsNtf : AndroidPacket (mt = NOTIFICATION, oid = FIRA_RANGE_DIAGNOSTICS) {
session_token: 32, // Session ID or Session Handle (based on UWBS version)
sequence_number: 32,
_count_(frame_reports): 8,
@@ -1335,67 +1443,3 @@ test AndroidRangeDiagnosticsNtf {
"\x6c\x02\x00\x11\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x01\x00\x01\x02\x01\x00\x01\x00\x00",
"\x6c\x02\x00\x34\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x01\x00\x01\x02\x03\x01\x08\x00\x01\x02\x01\x02\x01\x02\x01\x01\x02\x15\x00\x01\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x02\x04\x00\x01\x02\x03\x04\x00\x01\x00\x00",
}
-
-packet UciVendor_9_Command : UciCommand (gid = VENDOR_RESERVED_9) {
- _payload_,
-}
-
-packet UciVendor_A_Command : UciCommand (gid = VENDOR_RESERVED_A) {
- _payload_,
-}
-
-packet UciVendor_B_Command : UciCommand (gid = VENDOR_RESERVED_B) {
- _payload_,
-}
-
-packet UciVendor_E_Command : UciCommand (gid = VENDOR_RESERVED_E) {
- _payload_,
-}
-
-packet UciVendor_F_Command : UciCommand (gid = VENDOR_RESERVED_F) {
- _payload_,
-}
-
-packet UciVendor_9_Response : UciResponse (gid = VENDOR_RESERVED_9) {
- _payload_,
-}
-
-packet UciVendor_A_Response : UciResponse (gid = VENDOR_RESERVED_A) {
- _payload_,
-}
-
-packet UciVendor_B_Response : UciResponse (gid = VENDOR_RESERVED_B) {
- _payload_,
-}
-
-packet UciVendor_E_Response : UciResponse (gid = VENDOR_RESERVED_E) {
- _payload_,
-}
-
-packet UciVendor_F_Response : UciResponse (gid = VENDOR_RESERVED_F) {
- _payload_,
-}
-
-packet UciVendor_9_Notification : UciNotification (gid = VENDOR_RESERVED_9) {
- _payload_,
-}
-
-packet UciVendor_A_Notification : UciNotification (gid = VENDOR_RESERVED_A) {
- _payload_,
-}
-
-packet UciVendor_B_Notification : UciNotification (gid = VENDOR_RESERVED_B) {
- _payload_,
-}
-
-packet UciVendor_E_Notification : UciNotification (gid = VENDOR_RESERVED_E) {
- _payload_,
-}
-
-packet UciVendor_F_Notification : UciNotification (gid = VENDOR_RESERVED_F) {
- _payload_,
-}
-
-packet TestNotification : UciNotification (gid = TEST) {
- _payload_,
-} \ No newline at end of file
diff --git a/tests/data_transfer.py b/tests/data_transfer.py
index 241a6b9..6d4fb8c 100755
--- a/tests/data_transfer.py
+++ b/tests/data_transfer.py
@@ -35,7 +35,7 @@ async def controller(host: Host, peer: Host, file: Path):
)
)
- await host.expect_control(uci.SessionInitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionInitRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -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
@@ -80,7 +93,7 @@ async def controller(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.SessionSetAppConfigRsp(status=uci.StatusCode.UCI_STATUS_OK, cfg_status=[])
+ uci.SessionSetAppConfigRsp(status=uci.Status.OK, cfg_status=[])
)
await host.expect_control(
@@ -96,7 +109,7 @@ async def controller(host: Host, peer: Host, file: Path):
# START SESSION CMD
host.send_control(uci.SessionStartCmd(session_id=0))
- await host.expect_control(uci.SessionStartRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStartRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -107,7 +120,7 @@ async def controller(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
)
event = await host.expect_control(uci.ShortMacTwoWaySessionInfoNtf, timeout=2.0)
@@ -119,7 +132,7 @@ async def controller(host: Host, peer: Host, file: Path):
# STOP SESSION
host.send_control(uci.SessionStopCmd(session_id=0))
- await host.expect_control(uci.SessionStopRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStopRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -130,13 +143,13 @@ async def controller(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
# DEINIT
host.send_control(uci.SessionDeinitCmd(session_token=0))
- await host.expect_control(uci.SessionDeinitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionDeinitRsp(status=uci.Status.OK))
async def controlee(host: Host, peer: Host, file: Path):
@@ -149,7 +162,7 @@ async def controlee(host: Host, peer: Host, file: Path):
)
)
- await host.expect_control(uci.SessionInitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionInitRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -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
@@ -194,7 +220,7 @@ async def controlee(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.SessionSetAppConfigRsp(status=uci.StatusCode.UCI_STATUS_OK, cfg_status=[])
+ uci.SessionSetAppConfigRsp(status=uci.Status.OK, cfg_status=[])
)
await host.expect_control(
@@ -207,7 +233,7 @@ async def controlee(host: Host, peer: Host, file: Path):
host.send_control(uci.SessionStartCmd(session_id=0))
- await host.expect_control(uci.SessionStartRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStartRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -218,7 +244,7 @@ async def controlee(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
)
with file.open("rb") as f:
@@ -226,8 +252,8 @@ async def controlee(host: Host, peer: Host, file: Path):
event = await host.expect_data(
uci.DataMessageRcv(
session_handle=0,
- status=uci.StatusCode.UCI_STATUS_OK,
- source_address=int.from_bytes(peer.mac_address, "big"),
+ status=uci.Status.OK,
+ source_address=int.from_bytes(peer.mac_address, "little"),
data_sequence_number=0x01,
application_data=application_data,
),
@@ -240,7 +266,7 @@ async def controlee(host: Host, peer: Host, file: Path):
host.send_control(uci.SessionStopCmd(session_id=0))
- await host.expect_control(uci.SessionStopRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStopRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -251,12 +277,12 @@ async def controlee(host: Host, peer: Host, file: Path):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
host.send_control(uci.SessionDeinitCmd(session_token=0))
- await host.expect_control(uci.SessionDeinitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionDeinitRsp(status=uci.Status.OK))
async def data_transfer(
@@ -296,7 +322,7 @@ async def data_transfer(
seq_num = 0
event = await host.expect_control(
- uci.DataCreditNtf(
+ uci.SessionDataCreditNtf(
session_token=int(session_id),
credit_availability=uci.CreditAvailability.CREDIT_AVAILABLE,
)
@@ -312,7 +338,7 @@ async def data_transfer(
)
)
event = await host.expect_control(
- uci.DataCreditNtf(
+ uci.SessionDataCreditNtf(
session_token=int(session_id),
credit_availability=uci.CreditAvailability.CREDIT_AVAILABLE,
)
@@ -325,8 +351,8 @@ async def data_transfer(
async def run(address: str, uci_port: int, file: Path):
try:
- host0 = await Host.connect(address, uci_port, bytes([0, 0]))
- host1 = await Host.connect(address, uci_port, bytes([0, 1]))
+ host0 = await Host.connect(address, uci_port, bytes([0x34, 0x12]))
+ host1 = await Host.connect(address, uci_port, bytes([0x78, 0x56]))
except Exception as e:
raise Exception(
f"Failed to connect to Pica server at address {address}:{uci_port}\n"
diff --git a/tests/helper.py b/tests/helper.py
index bbce7ad..f5d9db5 100644
--- a/tests/helper.py
+++ b/tests/helper.py
@@ -18,13 +18,13 @@ from pica.packets import uci
async def init(host: Host):
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
- host.send_control(uci.DeviceResetCmd(reset_config=uci.ResetConfig.UWBS_RESET))
+ host.send_control(uci.CoreDeviceResetCmd(reset_config=uci.ResetConfig.UWBS_RESET))
- await host.expect_control(uci.DeviceResetRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.CoreDeviceResetRsp(status=uci.Status.OK))
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
diff --git a/tests/ranging.py b/tests/ranging.py
index 7af8224..165c5e3 100755
--- a/tests/ranging.py
+++ b/tests/ranging.py
@@ -32,7 +32,7 @@ async def controller(host: Host, peer: Host):
)
)
- await host.expect_control(uci.SessionInitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionInitRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -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
@@ -77,7 +90,7 @@ async def controller(host: Host, peer: Host):
)
await host.expect_control(
- uci.SessionSetAppConfigRsp(status=uci.StatusCode.UCI_STATUS_OK, cfg_status=[])
+ uci.SessionSetAppConfigRsp(status=uci.Status.OK, cfg_status=[])
)
await host.expect_control(
@@ -90,7 +103,7 @@ async def controller(host: Host, peer: Host):
host.send_control(uci.SessionStartCmd(session_id=0))
- await host.expect_control(uci.SessionStartRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStartRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -101,7 +114,7 @@ async def controller(host: Host, peer: Host):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
)
for _ in range(1, 3):
@@ -110,7 +123,7 @@ async def controller(host: Host, peer: Host):
host.send_control(uci.SessionStopCmd(session_id=0))
- await host.expect_control(uci.SessionStopRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStopRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -121,12 +134,12 @@ async def controller(host: Host, peer: Host):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
host.send_control(uci.SessionDeinitCmd(session_token=0))
- await host.expect_control(uci.SessionDeinitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionDeinitRsp(status=uci.Status.OK))
async def controlee(host: Host, peer: Host):
@@ -138,7 +151,7 @@ async def controlee(host: Host, peer: Host):
)
)
- await host.expect_control(uci.SessionInitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionInitRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -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
@@ -183,7 +209,7 @@ async def controlee(host: Host, peer: Host):
)
await host.expect_control(
- uci.SessionSetAppConfigRsp(status=uci.StatusCode.UCI_STATUS_OK, cfg_status=[])
+ uci.SessionSetAppConfigRsp(status=uci.Status.OK, cfg_status=[])
)
await host.expect_control(
@@ -196,7 +222,7 @@ async def controlee(host: Host, peer: Host):
host.send_control(uci.SessionStartCmd(session_id=0))
- await host.expect_control(uci.SessionStartRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStartRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -207,7 +233,7 @@ async def controlee(host: Host, peer: Host):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_ACTIVE)
)
for _ in range(1, 3):
@@ -216,7 +242,7 @@ async def controlee(host: Host, peer: Host):
host.send_control(uci.SessionStopCmd(session_id=0))
- await host.expect_control(uci.SessionStopRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionStopRsp(status=uci.Status.OK))
await host.expect_control(
uci.SessionStatusNtf(
@@ -227,12 +253,12 @@ async def controlee(host: Host, peer: Host):
)
await host.expect_control(
- uci.DeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
+ uci.CoreDeviceStatusNtf(device_state=uci.DeviceState.DEVICE_STATE_READY)
)
host.send_control(uci.SessionDeinitCmd(session_token=0))
- await host.expect_control(uci.SessionDeinitRsp(status=uci.StatusCode.UCI_STATUS_OK))
+ await host.expect_control(uci.SessionDeinitRsp(status=uci.Status.OK))
async def run(address: str, uci_port: int):