mod reads;
mod writes;
use ethercrab_wire::{EtherCrabWireSized, EtherCrabWireWriteSized};
pub use reads::{Reads, WrappedRead};
pub use writes::{WrappedWrite, Writes};
const NOP: u8 = 0x00;
const APRD: u8 = 0x01;
const FPRD: u8 = 0x04;
const BRD: u8 = 0x07;
const LRD: u8 = 0x0A;
const BWR: u8 = 0x08;
const APWR: u8 = 0x02;
const FPWR: u8 = 0x05;
const FRMW: u8 = 0x0E;
const LWR: u8 = 0x0B;
const LRW: u8 = 0x0c;
#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum Command {
#[default]
Nop,
Read(Reads),
Write(Writes),
}
impl EtherCrabWireSized for Command {
const PACKED_LEN: usize = 4;
type Buffer = [u8; Self::PACKED_LEN];
fn buffer() -> Self::Buffer {
[0u8; Self::PACKED_LEN]
}
}
impl EtherCrabWireWriteSized for Command {
fn pack(&self) -> Self::Buffer {
match *self {
Command::Nop => Self::buffer(),
Command::Read(Reads::Aprd { address, register })
| Command::Read(Reads::Brd { address, register })
| Command::Read(Reads::Fprd { address, register })
| Command::Read(Reads::Frmw { address, register })
| Command::Write(Writes::Apwr { address, register })
| Command::Write(Writes::Fpwr { address, register })
| Command::Write(Writes::Bwr { address, register }) => {
u32::to_le_bytes((u32::from(register) << 16) + u32::from(address))
}
Command::Read(Reads::Lrd { address })
| Command::Write(Writes::Lwr { address })
| Command::Write(Writes::Lrw { address }) => address.to_le_bytes(),
}
}
}
impl core::fmt::Display for Command {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Command::Nop => write!(f, "NOP"),
Command::Read(read) => match read {
Reads::Aprd { address, register } => {
write!(f, "APRD(addr {:#06x}, reg {:#06x})", address, register)
}
Reads::Fprd { address, register } => {
write!(f, "FPRD(addr {:#06x}, reg {:#06x})", address, register)
}
Reads::Brd { address, register } => {
write!(f, "BRD(addr {:#06x}, reg {:#06x})", address, register)
}
Reads::Lrd { address } => write!(f, "LRD(addr {:#010x})", address),
Reads::Frmw { address, register } => {
write!(f, "FRMW(addr {:#06x}, reg {:#06x})", address, register)
}
},
Command::Write(write) => match write {
Writes::Bwr { address, register } => {
write!(f, "BWR(addr {:#06x}, reg {:#06x})", address, register)
}
Writes::Apwr { address, register } => {
write!(f, "APWR(addr {:#06x}, reg {:#06x})", address, register)
}
Writes::Fpwr { address, register } => {
write!(f, "FPWR(addr {:#06x}, reg {:#06x})", address, register)
}
Writes::Lwr { address } => write!(f, "LWR(addr {:#010x})", address),
Writes::Lrw { address } => write!(f, "LRW(addr {:#010x})", address),
},
}
}
}
impl Command {
pub fn brd(register: u16) -> WrappedRead {
WrappedRead::new(Reads::Brd {
address: 0,
register,
})
}
pub fn bwr(register: u16) -> WrappedWrite {
WrappedWrite::new(Writes::Bwr {
address: 0,
register,
})
}
pub fn fprd(address: u16, register: u16) -> WrappedRead {
WrappedRead::new(Reads::Fprd { address, register })
}
pub fn fpwr(address: u16, register: u16) -> WrappedWrite {
WrappedWrite::new(Writes::Fpwr { address, register })
}
pub fn aprd(address: u16, register: u16) -> WrappedRead {
WrappedRead::new(Reads::Aprd {
address: 0u16.wrapping_sub(address),
register,
})
}
pub fn apwr(address: u16, register: u16) -> WrappedWrite {
WrappedWrite::new(Writes::Apwr {
address: 0u16.wrapping_sub(address),
register,
})
}
pub fn frmw(address: u16, register: u16) -> WrappedRead {
WrappedRead::new(Reads::Frmw { address, register })
}
pub fn lrw(address: u32) -> WrappedWrite {
WrappedWrite::new(Writes::Lrw { address })
}
pub fn lwr(address: u32) -> WrappedWrite {
WrappedWrite::new(Writes::Lwr { address })
}
pub(crate) const fn code(&self) -> u8 {
match self {
Self::Nop => NOP,
Self::Read(read) => match read {
Reads::Aprd { .. } => APRD,
Reads::Fprd { .. } => FPRD,
Reads::Brd { .. } => BRD,
Reads::Lrd { .. } => LRD,
Reads::Frmw { .. } => FRMW,
},
Self::Write(write) => match write {
Writes::Bwr { .. } => BWR,
Writes::Apwr { .. } => APWR,
Writes::Fpwr { .. } => FPWR,
Writes::Lwr { .. } => LWR,
Writes::Lrw { .. } => LRW,
},
}
}
}
impl From<Reads> for Command {
fn from(value: Reads) -> Self {
Self::Read(value)
}
}
impl From<Writes> for Command {
fn from(value: Writes) -> Self {
Self::Write(value)
}
}
impl From<WrappedRead> for Command {
fn from(value: WrappedRead) -> Self {
Self::Read(value.command)
}
}
impl From<WrappedWrite> for Command {
fn from(value: WrappedWrite) -> Self {
Self::Write(value.command)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pack_command_data() {
let address = 0x1004;
let register = 0x0980;
let expected = [0x04, 0x10, 0x80, 0x09];
assert_eq!(
Command::Write(Command::fpwr(address, register).command).pack(),
expected
);
}
}