diff --git a/bellows/ezsp/v14/commands.py b/bellows/ezsp/v14/commands.py index 5c49dfd0..0994e341 100644 --- a/bellows/ezsp/v14/commands.py +++ b/bellows/ezsp/v14/commands.py @@ -18,6 +18,13 @@ class GetTokenDataRsp(Struct): } COMMANDS = { + "radioSetSchedulerPriorities": ( + 0x012B, + { + "priorities": t.SlZigbeeMultiprotocolPriorities, + }, + {}, + ), "setExtendedTimeout": ( 0x007E, { diff --git a/bellows/ezsp/v16/commands.py b/bellows/ezsp/v16/commands.py index 51dc4248..82483d07 100644 --- a/bellows/ezsp/v16/commands.py +++ b/bellows/ezsp/v16/commands.py @@ -1,5 +1,15 @@ +import bellows.types as t + from ..v14.commands import COMMANDS as COMMANDS_v14 COMMANDS = { **COMMANDS_v14, + # The priorities struct grew from three to five fields + "radioSetSchedulerPriorities": ( + 0x012B, + { + "priorities": t.Sl802154RadioPriorities, + }, + {}, + ), } diff --git a/bellows/ezsp/v18/commands.py b/bellows/ezsp/v18/commands.py index ff458c4c..63812bd8 100644 --- a/bellows/ezsp/v18/commands.py +++ b/bellows/ezsp/v18/commands.py @@ -15,4 +15,225 @@ "messageContents": t.LVBytes, }, ), + # Added in Simplicity SDK 2025.12.0 + "setPendingNetworkUpdateChannel": ( + 0x003D, + { + "channel": t.uint8_t, + }, + {}, + ), + # NOTE: `radioSetSchedulerPriorities` (0x012B) was removed from NCP firmware in + # Simplicity SDK 2025.12.2 without an EZSP version bump: firmware built from + # SiSDK 2025.6.x (also EZSP v18) still implements it. + # Dynamic Hardware Configuration, added in Simplicity SDK 2025.12.2 + "readPaDescriptor": ( + 0x0152, + { + "index": t.uint8_t, + }, + { + "status": t.sl_Status, + "descriptor": t.SlZigbeeDhcPaDescriptor, + }, + ), + "writePaDescriptor": ( + 0x0153, + { + "index": t.uint8_t, + "descriptor": t.SlZigbeeDhcPaDescriptor, + }, + { + "status": t.sl_Status, + }, + ), + "readPaCurveSegment": ( + 0x0154, + { + "index": t.uint8_t, + "segment_index": t.uint8_t, + }, + { + "status": t.sl_Status, + "segment": t.SlZigbeeDhcPaCurveSegment, + }, + ), + "writePaCurveSegment": ( + 0x0155, + { + "index": t.uint8_t, + "segment_index": t.uint8_t, + "segment": t.SlZigbeeDhcPaCurveSegment, + }, + { + "status": t.sl_Status, + }, + ), + "readPaCurve": ( + 0x0156, + { + "index": t.uint8_t, + }, + { + "status": t.sl_Status, + "curve": t.SlZigbeeDhcPaCurve, + }, + ), + "writePaCurve": ( + 0x0157, + { + "index": t.uint8_t, + "curve": t.SlZigbeeDhcPaCurve, + }, + { + "status": t.sl_Status, + }, + ), + "readPaTable": ( + 0x0158, + { + "index": t.uint8_t, + }, + { + "status": t.sl_Status, + "table": t.SlZigbeeDhcPaTable, + }, + ), + "writePaTable": ( + 0x0159, + { + "index": t.uint8_t, + "table": t.SlZigbeeDhcPaTable, + }, + { + "status": t.sl_Status, + }, + ), + "readRssiOffset": ( + 0x015A, + {}, + { + "status": t.sl_Status, + "rssi_offset": t.int8s, + }, + ), + "readPaVoltage": ( + 0x015B, + {}, + { + "status": t.sl_Status, + "pa_voltage": t.uint16_t, + }, + ), + "writePaVoltage": ( + 0x015C, + { + "pa_voltage": t.uint16_t, + }, + { + "status": t.sl_Status, + }, + ), + "readPaMode": ( + 0x015D, + {}, + { + "status": t.sl_Status, + "pa_mode": t.uint8_t, + }, + ), + "writePaMode": ( + 0x015E, + { + "pa_mode": t.uint8_t, + }, + { + "status": t.sl_Status, + }, + ), + "writeRssiOffset": ( + 0x015F, + { + "rssi_offset": t.int8s, + }, + { + "status": t.sl_Status, + }, + ), + "readCtune": ( + 0x0160, + {}, + { + "status": t.sl_Status, + "ctune": t.uint32_t, + }, + ), + "writeCtune": ( + 0x0161, + { + "ctune": t.uint32_t, + }, + { + "status": t.sl_Status, + }, + ), + "readDhcVersion": ( + 0x0162, + {}, + { + "status": t.sl_Status, + "dhc_version": t.uint8_t, + }, + ), + "writeDhcVersion": ( + 0x0163, + { + "dhc_version": t.uint8_t, + }, + { + "status": t.sl_Status, + }, + ), + "readPaVersion": ( + 0x0164, + {}, + { + "status": t.sl_Status, + "pa_version": t.uint8_t, + }, + ), + "readPaSignature": ( + 0x0166, + {}, + { + "status": t.sl_Status, + "pa_signature": t.uint32_t, + }, + ), + "writePaSignature": ( + 0x0167, + { + "pa_signature": t.uint32_t, + }, + { + "status": t.sl_Status, + }, + ), + "readPaMetadata": ( + 0x0168, + {}, + { + "status": t.sl_Status, + "metadata": t.SlZigbeeDhcPaMetadata, + }, + ), + "writePaMetadata": ( + 0x0169, + { + "metadata": t.SlZigbeeDhcPaMetadata, + }, + { + "status": t.sl_Status, + }, + ), } diff --git a/bellows/types/named.py b/bellows/types/named.py index 0e640aa2..513a7cbf 100644 --- a/bellows/types/named.py +++ b/bellows/types/named.py @@ -2884,3 +2884,10 @@ class RouteRecordConcentratortype(basic.enum8): NOT_A_CONCENTRATOR = 0 LOW_RAM = 1 HIGH_RAM = 2 + + +class SlZigbeeDhcPaAlgorithm(basic.enum8): + """Dynamic Hardware Configuration PA descriptor algorithm.""" + + CURVE = 0 + TABLE = 1 diff --git a/bellows/types/struct.py b/bellows/types/struct.py index 91a17c01..a95c09e1 100644 --- a/bellows/types/struct.py +++ b/bellows/types/struct.py @@ -769,3 +769,85 @@ class SlRxPacketInfo(EzspStruct): last_hop_rssi: basic.int8s # Timestamp of the moment when Start Frame Delimiter (SFD) was received last_hop_timestamp: basic.uint32_t + + +class SlZigbeeDhcPaCurveSegment(EzspStruct): + """One PA curve segment (piecewise linear).""" + + # Segment upper bound power level + maxPowerLevel: basic.uint8_t + # Signed slope coefficient + slope: basic.int32s + # Signed intercept coefficient + intercept: basic.int32s + + +class SlZigbeeDhcPaCurve(EzspStruct): + """Full PA curve (fixed 9 segments).""" + + # Curve min ddbm + curve_min_ddbm: basic.int16s + # Curve max ddbm + curve_max_ddbm: basic.int16s + # Curve segments + segments: basic.FixedList[SlZigbeeDhcPaCurveSegment, 9] + + +class SlZigbeeDhcPaDescriptor(EzspStruct): + """Descriptor for either a curve (algorithm=0) or table (algorithm=1).""" + + algorithm: named.SlZigbeeDhcPaAlgorithm + # 9 for curve, 16 for table + num_segments_or_entries: basic.uint8_t + # Minimum ddbm (may be negative) + min_ddbm: basic.int16s + # Maximum ddbm (may be negative) + max_ddbm: basic.int16s + + +class SlZigbeeDhcPaTable(EzspStruct): + """Discrete PA table (16 entries).""" + + # Signed ddbm table entries + ddbm_values: basic.FixedList[basic.int16s, 16] + + +class SlZigbeeDhcPaMetadata(EzspStruct): + """Top-level PA calibration metadata.""" + + # Calibration metadata / dataset version + version: basic.uint8_t + # Number of PA descriptors present + num_descriptors: basic.uint8_t + # PA supply voltage (e.g. mV) + pa_voltage: basic.uint16_t + # Integrity signature / CRC for whole set + signature: basic.uint32_t + + +class SlZigbeeMultiprotocolPriorities(EzspStruct): + """Priorities for Zigbee radio operations in multiprotocol (EZSP v14).""" + + # The priority of a Zigbee RX operation while not receiving a packet + backgroundRx: basic.uint8_t + # The priority of a Zigbee TX operation + tx: basic.uint8_t + # The priority of a Zigbee RX operation while receiving a packet + activeRx: basic.uint8_t + + +class Sl802154RadioPriorities(EzspStruct): + """Scheduler priorities for radio operations (EZSP v16+).""" + + # The priority of a Zigbee RX operation while not receiving a packet + background_rx: basic.uint8_t + # Starting priority of a Zigbee TX operation. The first transmit of the + # packet, before retries, uses this priority + min_tx_priority: basic.uint8_t + # The increase in TX priority (which is a decrement in value) for each retry + tx_step: basic.uint8_t + # Maximum priority of a Zigbee TX operation. Retried messages have + # priorities bumped by tx_step, up to a maximum of max_tx_priority + max_tx_priority: basic.uint8_t + # The priority of a Zigbee RX operation while receiving a packet + active_rx: basic.uint8_t