lr2021/cmd/
cmd_zwave.rs

1// Zwave commands API
2
3use crate::status::Status;
4use super::RxBw;
5
6/// The data rate to be used for the RX and the TX
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum ZwaveMode {
10    Lr1 = 0,
11    R1 = 1,
12    R2 = 2,
13    R3 = 3,
14}
15
16impl ZwaveMode {
17    pub fn new(val: u8) -> Self{
18        match val {
19            3 => ZwaveMode::R3,
20            2 => ZwaveMode::R2,
21            _ => ZwaveMode::R1,
22        }
23    }
24}
25
26/// Enable or disable the filtering of the HomeID
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum ZwaveAddrComp {
30    Off = 0,
31    Homeid = 1,
32    HomeidBeam = 2,
33}
34
35/// FCS mode: auto to automatically generate FCS in TX and remove it in RX. In fifo mode, the FCS is expected to be part of the payload and is not checked in RX.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub enum FcsMode {
39    Auto = 0,
40    Fifo = 1,
41}
42
43/// Address length selection
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub enum AddrLen {
47    Addr8bit = 0,
48    Addr12bit = 1,
49}
50
51/// Sets the parameters for Z-Wave packets
52pub fn set_zwave_params_cmd(zwave_mode: ZwaveMode, rx_bw: RxBw, zwave_addr_comp: ZwaveAddrComp, pld_len: u8, pbl_len_tx: u16, pbl_len_detect: u8, fcs_mode: FcsMode) -> [u8; 10] {
53    let mut cmd = [0u8; 10];
54    cmd[0] = 0x02;
55    cmd[1] = 0x97;
56
57    cmd[2] |= (zwave_mode as u8) & 0x3;
58    cmd[3] |= rx_bw as u8;
59    cmd[4] |= zwave_addr_comp as u8;
60    cmd[5] |= pld_len;
61    cmd[6] |= ((pbl_len_tx >> 8) & 0xFF) as u8;
62    cmd[7] |= (pbl_len_tx & 0xFF) as u8;
63    cmd[8] |= pbl_len_detect;
64    cmd[9] |= (fcs_mode as u8) & 0x1;
65    cmd
66}
67
68/// Sets the HomeID address to use as a filter in Rx. The MSB is the first bit sent/received. Frames that don't match the home_id raise an address error IRQ
69pub fn set_zwave_home_id_filtering_cmd(home_id: u32) -> [u8; 6] {
70    let mut cmd = [0u8; 6];
71    cmd[0] = 0x02;
72    cmd[1] = 0x98;
73
74    cmd[2] |= ((home_id >> 24) & 0xFF) as u8;
75    cmd[3] |= ((home_id >> 16) & 0xFF) as u8;
76    cmd[4] |= ((home_id >> 8) & 0xFF) as u8;
77    cmd[5] |= (home_id & 0xFF) as u8;
78    cmd
79}
80
81/// Gets the status of the last received packet. Status is updated at the end of a reception (RxDone irq), but rssi_sync is already updated on SyncWordValid irq
82pub fn get_zwave_packet_status_req() -> [u8; 2] {
83    [0x02, 0x9A]
84}
85
86/// Settings for filtering incoming beam frames in Rx
87pub fn set_zwave_beam_filtering_cmd(beam_tag: u8, addr_len: AddrLen, node_id: u16, id_hash: u8) -> [u8; 6] {
88    let mut cmd = [0u8; 6];
89    cmd[0] = 0x02;
90    cmd[1] = 0x9B;
91
92    cmd[2] |= beam_tag;
93    cmd[3] |= ((addr_len as u8) & 0x1) << 7;
94    cmd[3] |= ((node_id >> 8) & 0xFF) as u8;
95    cmd[4] |= (node_id & 0xFF) as u8;
96    cmd[5] |= id_hash;
97    cmd
98}
99
100/// This command is used to enter the Zwave RX scan mode. The scan mode will alternate between data rates and channels and attempt to detect an incoming packet
101pub fn set_zwave_scan_cmd() -> [u8; 2] {
102    [0x02, 0x9D]
103}
104
105/// Gets the internal statistics of the received packets. Statistics are reset on a POR, sleep without memory retention and the command ResetRxStats
106pub fn get_zwave_rx_stats_req() -> [u8; 2] {
107    [0x02, 0x99]
108}
109
110// Response structs
111
112/// Response for GetZwavePacketStatus command
113#[derive(Default)]
114pub struct ZwavePacketStatusRsp([u8; 9]);
115
116impl ZwavePacketStatusRsp {
117    /// Create a new response buffer
118    pub fn new() -> Self {
119        Self::default()
120    }
121
122    /// Return Status
123    pub fn status(&mut self) -> Status {
124        Status::from_slice(&self.0[..2])
125    }
126
127    /// Length of the last received packet in bytes (including optional data added in the FIFO, crc, ...)
128    pub fn pkt_len(&self) -> u16 {
129        (self.0[3] as u16) |
130        ((self.0[2] as u16) << 8)
131    }
132
133    /// Average over last packet received of RSSI. Actual signal power is –rssi_pkt/2 (dBm)
134    pub fn rssi_avg(&self) -> u16 {
135        (((self.0[7] >> 2) & 0x1) as u16) |
136        ((self.0[4] as u16) << 1)
137    }
138
139    /// Latch RSSI value after syncword detection. Actual signal power is –rssi_sync/2 (dBm)
140    pub fn rssi_sync(&self) -> u16 {
141        ((self.0[7] & 0x1) as u16) |
142        ((self.0[5] as u16) << 1)
143    }
144
145    /// Last detected packet data rate
146    pub fn last_detect(&self) -> ZwaveMode {
147        ZwaveMode::new(self.0[6] & 0x3)
148    }
149
150    /// Link quality indicator (0.25dB)
151    pub fn lqi(&self) -> u8 {
152        self.0[8]
153    }
154}
155
156impl AsMut<[u8]> for ZwavePacketStatusRsp {
157    fn as_mut(&mut self) -> &mut [u8] {
158        &mut self.0
159    }
160}
161
162/// Response for GetZwaveRxStats command
163#[derive(Default)]
164pub struct ZwaveRxStatsRsp([u8; 8]);
165
166impl ZwaveRxStatsRsp {
167    /// Create a new response buffer
168    pub fn new() -> Self {
169        Self::default()
170    }
171
172    /// Return Status
173    pub fn status(&mut self) -> Status {
174        Status::from_slice(&self.0[..2])
175    }
176
177    /// Total number of received packets
178    pub fn pkt_rx(&self) -> u16 {
179        (self.0[3] as u16) |
180        ((self.0[2] as u16) << 8)
181    }
182
183    /// Number of received packets with a CRC error
184    pub fn crc_error(&self) -> u16 {
185        (self.0[5] as u16) |
186        ((self.0[4] as u16) << 8)
187    }
188
189    /// Number of packets with a length error
190    pub fn len_error(&self) -> u16 {
191        (self.0[7] as u16) |
192        ((self.0[6] as u16) << 8)
193    }
194}
195
196impl AsMut<[u8]> for ZwaveRxStatsRsp {
197    fn as_mut(&mut self) -> &mut [u8] {
198        &mut self.0
199    }
200}