use crate::slave::coe::EcDataType;
use std::sync::Mutex;
#[derive(Debug, Clone)]
pub enum EcValue {
Bool(bool),
I8(i8),
U8(u8),
I16(i16),
U16(u16),
I32(i32),
U32(u32),
I64(i64),
U64(u64),
F32(f32),
F64(f64),
String(String),
Bytes(Vec<u8>),
}
impl std::fmt::Display for EcValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EcValue::Bool(v) => write!(f, "{}", v),
EcValue::I8(v) => write!(f, "{}", v),
EcValue::U8(v) => write!(f, "{}", v),
EcValue::I16(v) => write!(f, "{}", v),
EcValue::U16(v) => write!(f, "{}", v),
EcValue::I32(v) => write!(f, "{}", v),
EcValue::U32(v) => write!(f, "{}", v),
EcValue::I64(v) => write!(f, "{}", v),
EcValue::U64(v) => write!(f, "{}", v),
EcValue::F32(v) => write!(f, "{}", v),
EcValue::F64(v) => write!(f, "{}", v),
EcValue::String(v) => write!(f, "{}", v),
EcValue::Bytes(v) => write!(f, "[{} bytes]", v.len()),
}
}
}
pub struct BaseData {
data_type: EcDataType,
raw_data: Mutex<Vec<u8>>,
}
impl BaseData {
pub fn new(data_type: EcDataType) -> Self {
let size = type_size(data_type);
Self {
data_type,
raw_data: Mutex::new(vec![0u8; size]),
}
}
pub fn with_value(data_type: EcDataType, value: &EcValue) -> Self {
let bd = Self::new(data_type);
let _ = bd.write(value);
bd
}
pub fn data_type(&self) -> EcDataType {
self.data_type
}
pub fn read(&self) -> EcValue {
let guard = self.raw_data.lock().unwrap();
convert_from_bytes(&guard, self.data_type)
}
pub fn write(&self, value: &EcValue) -> bool {
match convert_to_bytes(value, self.data_type) {
Some(bytes) => {
let mut guard = self.raw_data.lock().unwrap();
*guard = bytes;
true
}
None => false,
}
}
pub fn write_raw(&self, data: &[u8]) -> bool {
match self.data_type {
EcDataType::OctetString | EcDataType::UnicodeString
| EcDataType::VisibleString | EcDataType::Domain => {
let mut guard = self.raw_data.lock().unwrap();
guard.clear();
guard.extend_from_slice(data);
return true;
}
_ => {}
}
let expected = type_size(self.data_type);
if data.len() != expected {
return false;
}
let mut guard = self.raw_data.lock().unwrap();
guard.clear();
guard.extend_from_slice(data);
true
}
pub fn raw_data(&self) -> Vec<u8> {
self.raw_data.lock().unwrap().clone()
}
pub fn get_bit(&self, bit_index: usize) -> Option<bool> {
let guard = self.raw_data.lock().unwrap();
let byte_index = bit_index / 8;
let bit_offset = bit_index % 8;
if byte_index >= guard.len() {
return None;
}
Some((guard[byte_index] & (1 << bit_offset)) != 0)
}
pub fn set_bit(&self, bit_index: usize, value: bool) -> bool {
let mut guard = self.raw_data.lock().unwrap();
let byte_index = bit_index / 8;
let bit_offset = bit_index % 8;
if byte_index >= guard.len() {
return false;
}
if value {
guard[byte_index] |= 1 << bit_offset;
} else {
guard[byte_index] &= !(1 << bit_offset);
}
true
}
}
impl std::fmt::Display for BaseData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.read())
}
}
impl std::fmt::Debug for BaseData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BaseData")
.field("type", &self.data_type)
.field("value", &self.read())
.finish()
}
}
pub fn type_size(dt: EcDataType) -> usize {
match dt {
EcDataType::Boolean | EcDataType::Integer8 | EcDataType::Unsigned8 => 1,
EcDataType::Bit1 | EcDataType::Bit2 | EcDataType::Bit3 | EcDataType::Bit4 => 1,
EcDataType::Bit5 | EcDataType::Bit6 | EcDataType::Bit7 | EcDataType::Bit8 => 1,
EcDataType::Integer16 | EcDataType::Unsigned16 => 2,
EcDataType::Integer24 | EcDataType::Unsigned24 => 3,
EcDataType::Integer32 | EcDataType::Unsigned32 | EcDataType::Real32 => 4,
EcDataType::Integer64 | EcDataType::Unsigned64 | EcDataType::Real64 => 8,
EcDataType::TimeOfDay | EcDataType::TimeDifference => 8,
EcDataType::VisibleString | EcDataType::OctetString | EcDataType::Domain => 256,
EcDataType::UnicodeString => 512,
_ => 1,
}
}
pub fn convert_from_bytes(data: &[u8], dt: EcDataType) -> EcValue {
if data.is_empty() {
return default_value(dt);
}
match dt {
EcDataType::Boolean => EcValue::Bool(data[0] != 0),
EcDataType::Bit1 | EcDataType::Bit2 | EcDataType::Bit3
| EcDataType::Bit4 | EcDataType::Bit5 | EcDataType::Bit6 | EcDataType::Bit7
| EcDataType::Bit8 => EcValue::Bool((data[0] & 1) != 0),
EcDataType::Integer8 => EcValue::I8(data[0] as i8),
EcDataType::Unsigned8 => EcValue::U8(data[0]),
EcDataType::Integer16 if data.len() >= 2 => {
EcValue::I16(i16::from_le_bytes([data[0], data[1]]))
}
EcDataType::Unsigned16 if data.len() >= 2 => {
EcValue::U16(u16::from_le_bytes([data[0], data[1]]))
}
EcDataType::Integer24 if data.len() >= 3 => {
let v = (data[0] as i32) | ((data[1] as i32) << 8) | ((data[2] as i32) << 16);
let v = if v & 0x800000 != 0 { v | !0xFFFFFF_i32 } else { v };
EcValue::I32(v)
}
EcDataType::Unsigned24 if data.len() >= 3 => {
let v = (data[0] as u32) | ((data[1] as u32) << 8) | ((data[2] as u32) << 16);
EcValue::U32(v)
}
EcDataType::Integer32 if data.len() >= 4 => {
EcValue::I32(i32::from_le_bytes([data[0], data[1], data[2], data[3]]))
}
EcDataType::Unsigned32 if data.len() >= 4 => {
EcValue::U32(u32::from_le_bytes([data[0], data[1], data[2], data[3]]))
}
EcDataType::Integer64 if data.len() >= 8 => {
let mut buf = [0u8; 8];
buf.copy_from_slice(&data[..8]);
EcValue::I64(i64::from_le_bytes(buf))
}
EcDataType::Unsigned64 if data.len() >= 8 => {
let mut buf = [0u8; 8];
buf.copy_from_slice(&data[..8]);
EcValue::U64(u64::from_le_bytes(buf))
}
EcDataType::Real32 if data.len() >= 4 => {
EcValue::F32(f32::from_le_bytes([data[0], data[1], data[2], data[3]]))
}
EcDataType::Real64 if data.len() >= 8 => {
let mut buf = [0u8; 8];
buf.copy_from_slice(&data[..8]);
EcValue::F64(f64::from_le_bytes(buf))
}
EcDataType::VisibleString => {
let null_pos = data.iter().position(|&b| b == 0).unwrap_or(data.len());
EcValue::String(crate::utils::help::decode_ethercat_string(&data[..null_pos]))
}
EcDataType::UnicodeString => {
let null_pos = data.chunks(2)
.position(|c| c.len() == 2 && c[0] == 0 && c[1] == 0)
.unwrap_or(data.len() / 2);
let u16s: Vec<u16> = data[..null_pos * 2].chunks(2)
.filter(|c| c.len() == 2)
.map(|c| u16::from_le_bytes([c[0], c[1]]))
.collect();
EcValue::String(String::from_utf16_lossy(&u16s))
}
EcDataType::OctetString | EcDataType::Domain => {
EcValue::Bytes(data.to_vec())
}
EcDataType::TimeOfDay | EcDataType::TimeDifference if data.len() >= 8 => {
let mut buf = [0u8; 8];
buf.copy_from_slice(&data[..8]);
EcValue::I64(i64::from_le_bytes(buf))
}
_ => default_value(dt),
}
}
pub fn convert_to_bytes(value: &EcValue, dt: EcDataType) -> Option<Vec<u8>> {
match (value, dt) {
(EcValue::Bool(v), EcDataType::Boolean)
| (EcValue::Bool(v), EcDataType::Bit1)
| (EcValue::Bool(v), EcDataType::Bit2)
| (EcValue::Bool(v), EcDataType::Bit3)
| (EcValue::Bool(v), EcDataType::Bit4)
| (EcValue::Bool(v), EcDataType::Bit5)
| (EcValue::Bool(v), EcDataType::Bit6)
| (EcValue::Bool(v), EcDataType::Bit7)
| (EcValue::Bool(v), EcDataType::Bit8) => {
Some(vec![if *v { 1 } else { 0 }])
}
(EcValue::I8(v), EcDataType::Integer8) => Some(vec![*v as u8]),
(EcValue::U8(v), EcDataType::Unsigned8) => Some(vec![*v]),
(EcValue::I16(v), EcDataType::Integer16) => Some(v.to_le_bytes().to_vec()),
(EcValue::U16(v), EcDataType::Unsigned16) => Some(v.to_le_bytes().to_vec()),
(EcValue::I32(v), EcDataType::Integer24) => {
let bytes = v.to_le_bytes();
Some(vec![bytes[0], bytes[1], bytes[2]])
}
(EcValue::U32(v), EcDataType::Unsigned24) => {
let bytes = v.to_le_bytes();
Some(vec![bytes[0], bytes[1], bytes[2]])
}
(EcValue::I32(v), EcDataType::Integer32) => Some(v.to_le_bytes().to_vec()),
(EcValue::U32(v), EcDataType::Unsigned32) => Some(v.to_le_bytes().to_vec()),
(EcValue::I64(v), EcDataType::Integer64) => Some(v.to_le_bytes().to_vec()),
(EcValue::U64(v), EcDataType::Unsigned64) => Some(v.to_le_bytes().to_vec()),
(EcValue::F32(v), EcDataType::Real32) => Some(v.to_le_bytes().to_vec()),
(EcValue::F64(v), EcDataType::Real64) => Some(v.to_le_bytes().to_vec()),
(EcValue::String(v), EcDataType::VisibleString) => {
let mut buf = vec![0u8; 256];
let bytes = v.as_bytes();
let len = bytes.len().min(255);
buf[..len].copy_from_slice(&bytes[..len]);
Some(buf)
}
(EcValue::String(v), EcDataType::UnicodeString) => {
let mut buf = vec![0u8; 512];
let u16s: Vec<u16> = v.encode_utf16().collect();
let len = u16s.len().min(255);
for (i, &c) in u16s[..len].iter().enumerate() {
let bytes = c.to_le_bytes();
buf[i * 2] = bytes[0];
buf[i * 2 + 1] = bytes[1];
}
Some(buf)
}
(EcValue::Bytes(v), EcDataType::OctetString)
| (EcValue::Bytes(v), EcDataType::Domain) => Some(v.clone()),
(EcValue::I64(v), EcDataType::TimeOfDay)
| (EcValue::I64(v), EcDataType::TimeDifference) => Some(v.to_le_bytes().to_vec()),
_ => None,
}
}
pub fn default_value(dt: EcDataType) -> EcValue {
match dt {
EcDataType::Boolean | EcDataType::Bit1 | EcDataType::Bit2 | EcDataType::Bit3
| EcDataType::Bit4 | EcDataType::Bit5 | EcDataType::Bit6 | EcDataType::Bit7
| EcDataType::Bit8 => EcValue::Bool(false),
EcDataType::Integer8 => EcValue::I8(0),
EcDataType::Unsigned8 => EcValue::U8(0),
EcDataType::Integer16 => EcValue::I16(0),
EcDataType::Unsigned16 => EcValue::U16(0),
EcDataType::Integer24 | EcDataType::Integer32 => EcValue::I32(0),
EcDataType::Unsigned24 | EcDataType::Unsigned32 => EcValue::U32(0),
EcDataType::Integer64 | EcDataType::TimeOfDay | EcDataType::TimeDifference => EcValue::I64(0),
EcDataType::Unsigned64 => EcValue::U64(0),
EcDataType::Real32 => EcValue::F32(0.0),
EcDataType::Real64 => EcValue::F64(0.0),
EcDataType::VisibleString | EcDataType::UnicodeString => EcValue::String(String::new()),
EcDataType::OctetString | EcDataType::Domain => EcValue::Bytes(Vec::new()),
_ => EcValue::U8(0),
}
}