use crate::slave::core::Slave;
use crate::data::error::Result;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CiA401ErrorMode {
Hold = 0,
SafeValue = 1,
}
impl CiA401ErrorMode {
pub fn from_raw(val: u8) -> Self {
match val {
1 => Self::SafeValue,
_ => Self::Hold,
}
}
}
pub const OD_DI: u16 = 0x6000;
pub const OD_DI_16BIT: u16 = 0x6001;
pub const OD_DI_POLARITY: u16 = 0x6002;
pub const OD_DI_FILTER: u16 = 0x6003;
pub const OD_DI_INTERRUPT: u16 = 0x6005;
pub const OD_DI_INTERRUPT_EDGE: u16 = 0x6006;
pub const OD_DI_32BIT: u16 = 0x6020;
pub const OD_DO: u16 = 0x6200;
pub const OD_DO_16BIT: u16 = 0x6201;
pub const OD_DO_POLARITY: u16 = 0x6202;
pub const OD_DO_ERROR_MODE: u16 = 0x6206;
pub const OD_DO_ERROR_VALUE: u16 = 0x6207;
pub const OD_DO_32BIT: u16 = 0x6220;
pub const OD_AI: u16 = 0x6400;
pub const OD_AI_SI_UNIT: u16 = 0x6420;
pub const OD_AI_GLOBAL_INTERRUPT: u16 = 0x6423;
pub const OD_AI_UPPER_LIMIT: u16 = 0x6424;
pub const OD_AI_LOWER_LIMIT: u16 = 0x6425;
pub const OD_AO: u16 = 0x6411;
pub const OD_AO_32BIT: u16 = 0x6412;
pub const OD_AO_SI_UNIT: u16 = 0x6430;
pub const OD_AO_ERROR_MODE: u16 = 0x6443;
pub const OD_AO_ERROR_VALUE: u16 = 0x6444;
pub struct CiA401 {
slave: Slave,
}
impl CiA401 {
pub(crate) fn new(slave: Slave) -> Self {
Self { slave }
}
pub fn read_di(&self, channel: i32) -> bool {
let group = (channel / 8 + 1) as u8;
let bit = channel % 8;
match self.slave.sdo_read(OD_DI, group, false) {
Ok(data) if !data.is_empty() => (data[0] & (1 << bit)) != 0,
_ => false,
}
}
pub fn read_di16(&self, group: i32) -> u16 {
match self.slave.sdo_read(OD_DI_16BIT, group as u8, false) {
Ok(data) if data.len() >= 2 => u16::from_le_bytes([data[0], data[1]]),
_ => 0,
}
}
pub fn read_di32(&self, group: i32) -> u32 {
match self.slave.sdo_read(OD_DI_32BIT, group as u8, false) {
Ok(data) if data.len() >= 4 => u32::from_le_bytes([data[0], data[1], data[2], data[3]]),
_ => 0,
}
}
pub fn set_di_polarity(&self, group: i32, polarity: u8) -> Result<()> {
self.slave.sdo_write(OD_DI_POLARITY, group as u8, false, &[polarity])
}
pub fn di_polarity(&self, group: i32) -> u8 {
match self.slave.sdo_read(OD_DI_POLARITY, group as u8, false) {
Ok(data) if !data.is_empty() => data[0],
_ => 0,
}
}
pub fn set_di_filter(&self, group: i32, filter_enable: u8) -> Result<()> {
self.slave.sdo_write(OD_DI_FILTER, group as u8, false, &[filter_enable])
}
pub fn di_filter(&self, group: i32) -> u8 {
match self.slave.sdo_read(OD_DI_FILTER, group as u8, false) {
Ok(data) if !data.is_empty() => data[0],
_ => 0,
}
}
pub fn read_do(&self, channel: i32) -> bool {
let group = (channel / 8 + 1) as u8;
let bit = channel % 8;
match self.slave.sdo_read(OD_DO, group, false) {
Ok(data) if !data.is_empty() => (data[0] & (1 << bit)) != 0,
_ => false,
}
}
pub fn write_do(&self, channel: i32, state: bool) -> Result<()> {
let group = (channel / 8 + 1) as u8;
let bit = channel % 8;
let current = match self.slave.sdo_read(OD_DO, group, false) {
Ok(data) if !data.is_empty() => data[0],
_ => 0,
};
let new_val = if state {
current | (1 << bit)
} else {
current & !(1 << bit)
};
self.slave.sdo_write(OD_DO, group, false, &[new_val])
}
pub fn read_do16(&self, group: i32) -> u16 {
match self.slave.sdo_read(OD_DO_16BIT, group as u8, false) {
Ok(data) if data.len() >= 2 => u16::from_le_bytes([data[0], data[1]]),
_ => 0,
}
}
pub fn write_do16(&self, group: i32, value: u16) -> Result<()> {
self.slave.sdo_write(OD_DO_16BIT, group as u8, false, &value.to_le_bytes())
}
pub fn read_do32(&self, group: i32) -> u32 {
match self.slave.sdo_read(OD_DO_32BIT, group as u8, false) {
Ok(data) if data.len() >= 4 => u32::from_le_bytes([data[0], data[1], data[2], data[3]]),
_ => 0,
}
}
pub fn write_do32(&self, group: i32, value: u32) -> Result<()> {
self.slave.sdo_write(OD_DO_32BIT, group as u8, false, &value.to_le_bytes())
}
pub fn read_ai(&self, channel: i32) -> i32 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AI, sub, false) {
Ok(data) if data.len() >= 4 => {
i32::from_le_bytes([data[0], data[1], data[2], data[3]])
}
Ok(data) if data.len() >= 2 => {
i16::from_le_bytes([data[0], data[1]]) as i32
}
_ => 0,
}
}
pub fn read_ai_unsigned(&self, channel: i32) -> u16 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AI, sub, false) {
Ok(data) if data.len() >= 2 => u16::from_le_bytes([data[0], data[1]]),
_ => 0,
}
}
pub fn read_ai32_unsigned(&self, channel: i32) -> u32 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AI, sub, false) {
Ok(data) if data.len() >= 4 => u32::from_le_bytes([data[0], data[1], data[2], data[3]]),
_ => 0,
}
}
pub fn global_interrupt_enable(&self) -> bool {
match self.slave.sdo_read(OD_AI_GLOBAL_INTERRUPT, 0, false) {
Ok(data) if !data.is_empty() => data[0] != 0,
_ => false,
}
}
pub fn set_global_interrupt_enable(&self, enabled: bool) -> Result<()> {
self.slave.sdo_write(OD_AI_GLOBAL_INTERRUPT, 0, false, &[if enabled { 1 } else { 0 }])
}
pub fn ai_upper_limit(&self, channel: i32) -> i32 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AI_UPPER_LIMIT, sub, false) {
Ok(data) if data.len() >= 4 => {
i32::from_le_bytes([data[0], data[1], data[2], data[3]])
}
Ok(data) if data.len() >= 2 => {
i16::from_le_bytes([data[0], data[1]]) as i32
}
_ => 0,
}
}
pub fn ai_lower_limit(&self, channel: i32) -> i32 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AI_LOWER_LIMIT, sub, false) {
Ok(data) if data.len() >= 4 => {
i32::from_le_bytes([data[0], data[1], data[2], data[3]])
}
Ok(data) if data.len() >= 2 => {
i16::from_le_bytes([data[0], data[1]]) as i32
}
_ => 0,
}
}
pub fn set_ai_upper_limit(&self, channel: i32, value: i16) -> Result<()> {
let sub = (channel + 1) as u8;
self.slave.sdo_write(OD_AI_UPPER_LIMIT, sub, false, &value.to_le_bytes())
}
pub fn set_ai_lower_limit(&self, channel: i32, value: i16) -> Result<()> {
let sub = (channel + 1) as u8;
self.slave.sdo_write(OD_AI_LOWER_LIMIT, sub, false, &value.to_le_bytes())
}
pub fn read_ao(&self, channel: i32) -> i16 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AO, sub, false) {
Ok(data) if data.len() >= 2 => i16::from_le_bytes([data[0], data[1]]),
_ => 0,
}
}
pub fn write_ao(&self, channel: i32, value: i16) -> Result<()> {
let sub = (channel + 1) as u8;
self.slave.sdo_write(OD_AO, sub, false, &value.to_le_bytes())
}
pub fn read_ao32(&self, channel: i32) -> i32 {
let sub = (channel + 1) as u8;
match self.slave.sdo_read(OD_AO_32BIT, sub, false) {
Ok(data) if data.len() >= 4 => {
i32::from_le_bytes([data[0], data[1], data[2], data[3]])
}
_ => 0,
}
}
pub fn write_ao32(&self, channel: i32, value: i32) -> Result<()> {
let sub = (channel + 1) as u8;
self.slave.sdo_write(OD_AO_32BIT, sub, false, &value.to_le_bytes())
}
pub fn set_do_error_mode(&self, group: i32, mode: CiA401ErrorMode) -> Result<()> {
self.slave.sdo_write(OD_DO_ERROR_MODE, (group + 1) as u8, false, &[mode as u8])
}
pub fn do_error_mode(&self, group: i32) -> CiA401ErrorMode {
match self.slave.sdo_read(OD_DO_ERROR_MODE, (group + 1) as u8, false) {
Ok(data) if !data.is_empty() => CiA401ErrorMode::from_raw(data[0]),
_ => CiA401ErrorMode::Hold,
}
}
pub fn set_do_error_value(&self, group: i32, value: u8) -> Result<()> {
self.slave.sdo_write(OD_DO_ERROR_VALUE, (group + 1) as u8, false, &[value])
}
pub fn do_error_value(&self, group: i32) -> u8 {
match self.slave.sdo_read(OD_DO_ERROR_VALUE, (group + 1) as u8, false) {
Ok(data) if !data.is_empty() => data[0],
_ => 0,
}
}
pub fn set_ao_error_mode(&self, channel: i32, mode: CiA401ErrorMode) -> Result<()> {
self.slave.sdo_write(OD_AO_ERROR_MODE, (channel + 1) as u8, false, &[mode as u8])
}
pub fn set_ao_error_value(&self, channel: i32, value: i16) -> Result<()> {
self.slave.sdo_write(OD_AO_ERROR_VALUE, (channel + 1) as u8, false, &value.to_le_bytes())
}
pub fn get_ao_error_mode(&self, channel: i32) -> CiA401ErrorMode {
match self.slave.sdo_read(OD_AO_ERROR_MODE, (channel + 1) as u8, false) {
Ok(data) if !data.is_empty() => CiA401ErrorMode::from_raw(data[0]),
_ => CiA401ErrorMode::Hold,
}
}
pub fn get_ao_error_value(&self, channel: i32) -> i16 {
match self.slave.sdo_read(OD_AO_ERROR_VALUE, (channel + 1) as u8, false) {
Ok(data) if data.len() >= 2 => i16::from_le_bytes([data[0], data[1]]),
_ => 0,
}
}
}
impl std::fmt::Display for CiA401 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "从站 {}: CiA401 I/O", self.slave.index())
}
}