use super::master::AlState;
#[derive(Debug, Clone, Copy)]
pub struct FmmuMapping {
pub logical_start: u32,
pub length: u16,
pub physical_start: u16,
pub read_enable: bool,
pub write_enable: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct EtherCatSlave {
pub address: u16,
pub state: AlState,
pub vendor_id: u32,
pub product_code: u32,
pub revision: u32,
pub fmmus: [Option<FmmuMapping>; 8],
pub fmmu_count: usize,
pub error_count: u16,
}
impl EtherCatSlave {
pub fn new(address: u16, vendor_id: u32, product_code: u32, revision: u32) -> Self {
Self {
address,
state: AlState::Init,
vendor_id,
product_code,
revision,
fmmus: [None; 8],
fmmu_count: 0,
error_count: 0,
}
}
pub fn add_fmmu(&mut self, mapping: FmmuMapping) -> bool {
if self.fmmu_count >= 8 {
return false;
}
self.fmmus[self.fmmu_count] = Some(mapping);
self.fmmu_count += 1;
true
}
pub fn request_state(&mut self, target: AlState) -> bool {
let allowed = matches!(
(self.state, target),
(AlState::Init, AlState::PreOp)
| (AlState::PreOp, AlState::SafeOp)
| (AlState::SafeOp, AlState::Op)
| (AlState::Op, AlState::SafeOp)
| (AlState::SafeOp, AlState::PreOp)
| (AlState::PreOp, AlState::Init)
);
if allowed {
self.state = target;
}
allowed
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slave_state_transitions() {
let mut slave = EtherCatSlave::new(0, 0x22D2, 0x0001, 0x0001);
assert!(slave.request_state(AlState::PreOp));
assert_eq!(slave.state, AlState::PreOp);
assert!(slave.request_state(AlState::SafeOp));
assert!(slave.request_state(AlState::Op));
assert_eq!(slave.state, AlState::Op);
}
#[test]
fn slave_invalid_transition() {
let mut slave = EtherCatSlave::new(0, 0x22D2, 0x0001, 0x0001);
assert!(!slave.request_state(AlState::Op)); assert_eq!(slave.state, AlState::Init);
}
#[test]
fn slave_fmmu_mapping() {
let mut slave = EtherCatSlave::new(0, 0x22D2, 0x0001, 0x0001);
let fmmu = FmmuMapping {
logical_start: 0,
length: 4,
physical_start: 0x1000,
read_enable: true,
write_enable: false,
};
assert!(slave.add_fmmu(fmmu));
assert_eq!(slave.fmmu_count, 1);
}
#[test]
fn slave_fmmu_max_8() {
let mut slave = EtherCatSlave::new(0, 0x22D2, 0x0001, 0x0001);
for _ in 0..8 {
slave.add_fmmu(FmmuMapping {
logical_start: 0,
length: 1,
physical_start: 0,
read_enable: true,
write_enable: false,
});
}
assert!(!slave.add_fmmu(FmmuMapping {
logical_start: 0,
length: 1,
physical_start: 0,
read_enable: true,
write_enable: false,
}));
}
}