use embedded_hal::digital::OutputPin;
use embedded_hal_async::spi::SpiBus;
pub use super::cmd::cmd_zwave::*;
use super::{BusyPin, Lr2021, Lr2021Error, RxBw};
#[derive(Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ZwavePacketParams {
pub mode: ZwaveMode,
pub rx_bw: RxBw,
pub addr_comp: ZwaveAddrComp,
pub pld_len: u8,
pub pbl_len_tx: u16,
pub pbl_len_detect: u8,
pub fcs_mode: FcsMode,
}
#[derive(Debug, Clone, Copy)]
pub enum ZwavePpduKind {
SingleCast, MultiCast, Beam
}
impl ZwavePacketParams {
pub fn new(mode: ZwaveMode, rx_bw: RxBw, addr_comp: ZwaveAddrComp, pld_len: u8, pbl_len_tx: u16, pbl_len_detect: u8, fcs_mode: FcsMode) -> Self {
Self {mode, rx_bw, addr_comp, pld_len, pbl_len_tx, pbl_len_detect, fcs_mode}
}
pub fn from_mode(mode: ZwaveMode, kind: ZwavePpduKind, pld_len: u8) -> Self {
let fcs_mode = if mode==ZwaveMode::Lr1 {FcsMode::Fifo} else {FcsMode::Auto};
let pbl_len_tx = match (kind, mode) {
(ZwavePpduKind::Beam , ZwaveMode::Lr1) => 2,
(_ , ZwaveMode::Lr1) => 10,
(ZwavePpduKind::SingleCast, _ ) => 10,
(ZwavePpduKind::MultiCast , ZwaveMode::R1 ) => 10,
(ZwavePpduKind::MultiCast , ZwaveMode::R2 ) => 20,
(ZwavePpduKind::MultiCast , ZwaveMode::R3 ) => 24,
(ZwavePpduKind::Beam , ZwaveMode::R3 ) => 8,
(ZwavePpduKind::Beam , _ ) => 20,
} * 8; Self {
mode,
rx_bw: RxBw::BwAuto,
addr_comp: ZwaveAddrComp::Off,
pld_len,
pbl_len_tx,
pbl_len_detect:32,
fcs_mode
}
}
pub fn with_filt(self, beam_en: bool) -> Self {
Self {
mode: self.mode,
rx_bw: self.rx_bw,
addr_comp: if beam_en {ZwaveAddrComp::HomeidBeam} else {ZwaveAddrComp::Homeid},
pld_len: self.pld_len,
pbl_len_tx: self.pbl_len_tx,
pbl_len_detect: self.pbl_len_detect,
fcs_mode: self.fcs_mode,
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ZwaveChanCfg {
pub freq: u32,
pub mode: ZwaveMode,
pub timeout: u8,
pub cca_en: bool,
}
impl ZwaveChanCfg {
pub fn r1(freq: u32) -> Self {
Self {
freq,
mode: ZwaveMode::R1,
timeout: 19,
cca_en: false,
}
}
pub fn r2(freq: u32, fast: bool) -> Self {
Self {
freq,
mode: ZwaveMode::R2,
timeout: if fast {30} else {34},
cca_en: false,
}
}
pub fn r3(freq: u32, fast: bool) -> Self {
Self {
freq,
mode: ZwaveMode::R3,
timeout: if fast {7} else {8},
cca_en: false,
}
}
pub fn lr1(freq: u32) -> Self {
Self {
freq,
mode: ZwaveMode::Lr1,
timeout: 12,
cca_en: false,
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ZwaveScanCfg {
pub addr_comp: ZwaveAddrComp,
pub fcs_mode: FcsMode,
pub nb_ch: u8,
pub ch1 : ZwaveChanCfg,
pub ch2 : ZwaveChanCfg,
pub ch3 : ZwaveChanCfg,
pub ch4 : ZwaveChanCfg,
}
pub enum ZwaveRfRegion {Anz, Cn, Eu, EuLr1, EuLr2, Hk, Il, In, Jp, Kr, Ru, Us, UsLr1, UsLr2}
impl ZwaveScanCfg {
pub fn from_region(addr_comp: ZwaveAddrComp, fcs_mode: FcsMode, region: ZwaveRfRegion) -> Self {
match region {
ZwaveRfRegion::Anz => Self::base_rate(addr_comp, fcs_mode, 921_400_000, 921_400_000, 919_800_000),
ZwaveRfRegion::Cn => Self::base_rate(addr_comp, fcs_mode, 868_400_000, 868_400_000, 868_400_000),
ZwaveRfRegion::Eu => Self::base_rate(addr_comp, fcs_mode, 868_400_000, 868_400_000, 869_850_000),
ZwaveRfRegion::Hk => Self::base_rate(addr_comp, fcs_mode, 919_800_000, 919_800_000, 919_800_000),
ZwaveRfRegion::Il => Self::base_rate(addr_comp, fcs_mode, 916_000_000, 916_000_000, 916_000_000),
ZwaveRfRegion::In => Self::base_rate(addr_comp, fcs_mode, 865_200_000, 865_200_000, 865_200_000),
ZwaveRfRegion::Ru => Self::base_rate(addr_comp, fcs_mode, 869_000_000, 869_000_000, 869_000_000),
ZwaveRfRegion::Us => Self::base_rate(addr_comp, fcs_mode, 908_400_000, 908_400_000, 916_000_000),
ZwaveRfRegion::Jp => Self::all_r3(addr_comp, fcs_mode, 922_500_000, 923_900_000, 926_300_000),
ZwaveRfRegion::Kr => Self::all_r3(addr_comp, fcs_mode, 920_900_000, 921_700_000, 923_100_000),
ZwaveRfRegion::EuLr1 => Self::all_rate(addr_comp, fcs_mode, 868_400_000, 868_400_000, 869_850_000, 864_400_000),
ZwaveRfRegion::EuLr2 => Self::all_rate(addr_comp, fcs_mode, 868_400_000, 868_400_000, 869_850_000, 866_400_000),
ZwaveRfRegion::UsLr1 => Self::all_rate(addr_comp, fcs_mode, 908_400_000, 908_400_000, 916_000_000, 912_000_000),
ZwaveRfRegion::UsLr2 => Self::all_rate(addr_comp, fcs_mode, 908_400_000, 908_400_000, 916_000_000, 920_000_000),
}
}
pub fn base_rate(addr_comp: ZwaveAddrComp, fcs_mode: FcsMode, rf_r1: u32, rf_r2: u32, rf_r3: u32) -> Self {
Self {addr_comp, fcs_mode, nb_ch: 3,
ch1: ZwaveChanCfg::r1(rf_r1),
ch2: ZwaveChanCfg::r2(rf_r2, false),
ch3: ZwaveChanCfg::r3(rf_r3, false),
ch4: ZwaveChanCfg::lr1(912_000_000),
}
}
pub fn all_rate(addr_comp: ZwaveAddrComp, fcs_mode: FcsMode, rf_r1: u32, rf_r2: u32, rf_r3: u32, rf_lr1: u32) -> Self {
Self {addr_comp, fcs_mode, nb_ch: 4,
ch1: ZwaveChanCfg::r1(rf_r1),
ch2: ZwaveChanCfg::r2(rf_r2, true),
ch3: ZwaveChanCfg::r3(rf_r3, true),
ch4: ZwaveChanCfg::lr1(rf_lr1),
}
}
pub fn all_r3(addr_comp: ZwaveAddrComp, fcs_mode: FcsMode, rf_r1: u32, rf_r2: u32, rf_r3: u32) -> Self {
Self {addr_comp, fcs_mode, nb_ch: 3,
ch1: ZwaveChanCfg::r3(rf_r1, false),
ch2: ZwaveChanCfg::r3(rf_r2, false),
ch3: ZwaveChanCfg::r3(rf_r3, false),
ch4: ZwaveChanCfg::lr1(912_000_000),
}
}
pub fn lr_only(addr_comp: ZwaveAddrComp, fcs_mode: FcsMode, is_us: bool) -> Self {
if is_us {
Self {addr_comp, fcs_mode, nb_ch: 2, ch1:ZwaveChanCfg::lr1(912_000_000), ch2: ZwaveChanCfg::lr1(920_000_000), ch3: ZwaveChanCfg::lr1(919_800_000), ch4: ZwaveChanCfg::lr1(919_800_000)}
} else {
Self {addr_comp, fcs_mode, nb_ch: 2, ch1:ZwaveChanCfg::lr1(864_400_000), ch2: ZwaveChanCfg::lr1(866_400_000), ch3: ZwaveChanCfg::lr1(919_800_000), ch4: ZwaveChanCfg::lr1(919_800_000)}
}
}
pub fn cmd_nb_ch(&self) -> u8 {
((self.nb_ch&0x0F) << 4) |
if self.ch1.cca_en {1} else {0} |
if self.ch2.cca_en {2} else {0} |
if self.ch3.cca_en {4} else {0} |
if self.ch4.cca_en {8} else {0}
}
pub fn cmd_mode(&self) -> u8 {
(self.ch1.mode as u8) |
((self.ch2.mode as u8) << 2) |
((self.ch3.mode as u8) << 4) |
((self.ch4.mode as u8) << 6)
}
}
impl<O,SPI, M> Lr2021<O,SPI, M> where
O: OutputPin, SPI: SpiBus<u8>, M: BusyPin
{
pub async fn set_zwave_packet(&mut self, params: &ZwavePacketParams) -> Result<(), Lr2021Error> {
let req = set_zwave_params_cmd(
params.mode,
params.rx_bw,
params.addr_comp,
params.pld_len,
params.pbl_len_tx,
params.pbl_len_detect,
params.fcs_mode);
self.cmd_wr(&req).await
}
pub async fn set_zwave_home_id(&mut self, id: u32) -> Result<(), Lr2021Error> {
let req = set_zwave_home_id_filtering_cmd(id);
self.cmd_wr(&req).await
}
pub async fn set_zwave_beam_filt(&mut self, beam_tag: u8, addr_len: AddrLen, node_id: u16, id_hash: u8) -> Result<(), Lr2021Error> {
let req = set_zwave_beam_filtering_cmd(beam_tag, addr_len, node_id, id_hash);
self.cmd_wr(&req).await
}
pub async fn set_zwave_scan_config(&mut self, cfg: &ZwaveScanCfg) -> Result<(), Lr2021Error> {
let req = [0x02, 0x9C,
cfg.cmd_nb_ch(),
cfg.cmd_mode(),
cfg.addr_comp as u8,
cfg.fcs_mode as u8,
((cfg.ch1.freq >> 24) & 0xFF) as u8,
((cfg.ch1.freq >> 16) & 0xFF) as u8,
((cfg.ch1.freq >> 8 ) & 0xFF) as u8,
( cfg.ch1.freq & 0xFF) as u8,
cfg.ch1.timeout,
((cfg.ch2.freq >> 24) & 0xFF) as u8,
((cfg.ch2.freq >> 16) & 0xFF) as u8,
((cfg.ch2.freq >> 8 ) & 0xFF) as u8,
( cfg.ch2.freq & 0xFF) as u8,
cfg.ch2.timeout,
((cfg.ch3.freq >> 24) & 0xFF) as u8,
((cfg.ch3.freq >> 16) & 0xFF) as u8,
((cfg.ch3.freq >> 8 ) & 0xFF) as u8,
( cfg.ch3.freq & 0xFF) as u8,
cfg.ch3.timeout,
((cfg.ch4.freq >> 24) & 0xFF) as u8,
((cfg.ch4.freq >> 16) & 0xFF) as u8,
((cfg.ch4.freq >> 8 ) & 0xFF) as u8,
( cfg.ch4.freq & 0xFF) as u8,
cfg.ch4.timeout,
];
let len = match cfg.nb_ch {
2 => 16,
3 => 21,
_ => 26,
};
self.cmd_wr(&req[..len]).await
}
pub async fn start_zwave_scan(&mut self) -> Result<(), Lr2021Error> {
let req = set_zwave_scan_cmd();
self.cmd_wr(&req).await
}
pub async fn get_zwave_packet_status(&mut self) -> Result<ZwavePacketStatusRsp, Lr2021Error> {
let req = get_zwave_packet_status_req();
let mut rsp = ZwavePacketStatusRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp)
}
pub async fn get_zwave_rx_stats(&mut self) -> Result<ZwaveRxStatsRsp, Lr2021Error> {
let req = get_zwave_rx_stats_req();
let mut rsp = ZwaveRxStatsRsp::new();
self.cmd_rd(&req, rsp.as_mut()).await?;
Ok(rsp)
}
}