use crate::utils::ffi;
pub const OBJ_DEVICE_TYPE: u16 = 0x1000;
pub const OBJ_DEVICE_NAME: u16 = 0x1008;
pub const OBJ_HW_VERSION: u16 = 0x1009;
pub const OBJ_SW_VERSION: u16 = 0x100A;
pub const OBJ_IDENTITY: u16 = 0x1018;
pub const OBJ_DETECT_MODULES: u16 = 0xF002;
pub const OBJ_MASTER_DIAG_DATA: u16 = 0xF120;
pub const OBJ_DIAG_INTERFACE_CTRL: u16 = 0xF200;
pub struct MasterOdEtg1510 {
master_index: u16,
pub vendor_id: u32,
pub product_code: u32,
pub serial_number: u32,
}
impl MasterOdEtg1510 {
pub fn new(master_index: u16, instance_id: u32) -> Self {
Self {
master_index,
vendor_id: 0x00001164,
product_code: 0x00000001,
serial_number: instance_id,
}
}
pub fn revision_number(&self) -> u32 {
let ver = crate::statics::version_info::dll_version().unwrap_or_default();
((ver.major as u32) << 16) | (ver.minor as u32)
}
pub fn read_device_type(&self) -> Vec<u8> {
0x00001389u32.to_le_bytes().to_vec()
}
pub fn read_device_name(&self) -> Vec<u8> {
b"Darra EtherCAT Master".to_vec()
}
pub fn read_hw_version(&self) -> Vec<u8> {
if cfg!(target_pointer_width = "64") {
b"x64".to_vec()
} else {
b"x86".to_vec()
}
}
pub fn read_sw_version(&self) -> Vec<u8> {
let ver = crate::statics::version_info::dll_version().unwrap_or_default();
format!("{}.{}.{}.{}", ver.major, ver.minor, ver.patch, ver.build)
.into_bytes()
}
pub fn read_identity(&self, subindex: u8) -> Option<Vec<u8>> {
match subindex {
0 => Some(vec![4]),
1 => Some(self.vendor_id.to_le_bytes().to_vec()),
2 => Some(self.product_code.to_le_bytes().to_vec()),
3 => Some(self.revision_number().to_le_bytes().to_vec()),
4 => Some(self.serial_number.to_le_bytes().to_vec()),
_ => None,
}
}
pub fn master_identity(&self) -> Option<crate::utils::ffi::MasterIdentity> {
let mut identity = crate::utils::ffi::MasterIdentity::default();
unsafe {
if ffi::GetMasterIdentity(self.master_index, &mut identity) != 0 {
Some(identity)
} else {
None
}
}
}
pub fn master_diag_data(&self) -> Option<crate::utils::ffi::MasterDiagData> {
let mut diag = crate::utils::ffi::MasterDiagData::default();
unsafe {
if ffi::GetMasterDiagData(self.master_index, &mut diag) != 0 {
Some(diag)
} else {
None
}
}
}
pub fn read_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
match index {
OBJ_DEVICE_TYPE => {
if subindex == 0 { Some(self.read_device_type()) } else { None }
}
OBJ_DEVICE_NAME => {
if subindex == 0 { Some(self.read_device_name()) } else { None }
}
OBJ_HW_VERSION => {
if subindex == 0 { Some(self.read_hw_version()) } else { None }
}
OBJ_SW_VERSION => {
if subindex == 0 { Some(self.read_sw_version()) } else { None }
}
OBJ_IDENTITY => self.read_identity(subindex),
0x8000..=0x8FFF => {
self.read_slave_object(index, subindex)
}
0x9000..=0x9FFF => {
self.read_slave_object(index, subindex)
}
0xA000..=0xAFFF => {
self.read_slave_object(index, subindex)
}
OBJ_DETECT_MODULES => {
self.read_command_object(index, subindex)
}
OBJ_MASTER_DIAG_DATA => {
self.read_command_object(index, subindex)
}
OBJ_DIAG_INTERFACE_CTRL => {
self.read_command_object(index, subindex)
}
_ => None,
}
}
fn read_slave_object(&self, _index: u16, _subindex: u8) -> Option<Vec<u8>> {
None
}
fn read_command_object(&self, _index: u16, _subindex: u8) -> Option<Vec<u8>> {
None
}
pub fn get_supported_object_indices(&self) -> Vec<u16> {
let mut indices = vec![
OBJ_DEVICE_TYPE, OBJ_DEVICE_NAME, OBJ_HW_VERSION, OBJ_SW_VERSION, OBJ_IDENTITY, OBJ_DETECT_MODULES, OBJ_MASTER_DIAG_DATA, OBJ_DIAG_INTERFACE_CTRL, ];
for slave_idx in 0u16..64 {
let config_index = 0x8000 + slave_idx * 0x10;
if self.read_slave_object(config_index, 0).is_some() {
indices.push(config_index);
indices.push(0x9000 + slave_idx * 0x10);
indices.push(0xA000 + slave_idx * 0x10);
} else {
break; }
}
indices
}
pub fn object_name(&self, index: u16) -> &str {
match index {
0x1000 => "Device Type",
0x1008 => "Manufacturer Device Name",
0x1009 => "Manufacturer Hardware Version",
0x100A => "Manufacturer Software Version",
0x1018 => "Identity Object",
0xF002 => "Detect Modules Command",
0xF120 => "Master Diag Data",
0xF200 => "Diag Interface Control",
_ if index >= 0x8000 && index <= 0x8FFF => "Configuration Data",
_ if index >= 0x9000 && index <= 0x9FFF => "Information Data",
_ if index >= 0xA000 && index <= 0xAFFF => "Diagnosis Data",
_ => "Unknown",
}
}
pub fn subindex_count(&self, index: u16) -> u8 {
match index {
0x1000 | 0x1008 | 0x1009 | 0x100A => 0,
0x1018 => 4,
i if i >= 0x8000 && i <= 0x8FFF => 40,
i if i >= 0x9000 && i <= 0x9FFF => 32,
i if i >= 0xA000 && i <= 0xAFFF => 19,
0xF002 => 3,
0xF120 | 0xF200 => 16,
_ => 0,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct SlaveDiagData {
pub al_status_extended: u16,
pub last_al_status_code: u16,
pub last_coe_soe_protocol_error: u32,
pub cyclic_wc_error_counter: u32,
pub new_diag_messages_available: bool,
pub disable_automatic_link_control: bool,
}
pub struct Etg1510DiagInterface {
master_index: u16,
od: MasterOdEtg1510,
}
impl Etg1510DiagInterface {
pub fn new(master_index: u16) -> Self {
Self {
master_index,
od: MasterOdEtg1510::new(master_index, 0),
}
}
pub fn write_master_object(&self, index: u16, subindex: u8, data: &[u8]) -> bool {
if let Some(f) = ffi::dynamic_ffi::ffi_gap().diag_etg1510_write {
let rc = unsafe {
f(self.master_index, index, subindex,
data.as_ptr(), data.len() as u32)
};
if rc != 0 {
return true;
}
}
match index {
OBJ_DEVICE_TYPE | OBJ_DEVICE_NAME | OBJ_HW_VERSION | OBJ_SW_VERSION
| OBJ_IDENTITY => false,
OBJ_DETECT_MODULES | OBJ_DIAG_INTERFACE_CTRL
| 0xA000..=0xAFFF => {
let ok = unsafe {
ffi::SDOwrite_raw(
self.master_index, 0, index, subindex, 0,
data.as_ptr(), data.len() as core::ffi::c_int,
)
};
ok != 0
}
_ => false,
}
}
pub fn read_master_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
if let Some(f) = ffi::dynamic_ffi::ffi_gap().diag_etg1510_read {
let mut buf = [0u8; 4096];
let mut out_size: u32 = 0;
let rc = unsafe {
f(self.master_index, index, subindex,
buf.as_mut_ptr(), buf.len() as u32, &mut out_size)
};
if rc != 0 && out_size > 0 {
return Some(buf[..out_size as usize].to_vec());
}
}
if let Some(v) = self.od.read_object(index, subindex) {
return Some(v);
}
let mut size: core::ffi::c_int = 0;
let ptr = unsafe {
ffi::SDOread(self.master_index, 0, index, subindex, 0, &mut size)
};
if !ptr.is_null() && size > 0 {
let data = unsafe {
std::slice::from_raw_parts(ptr, size as usize).to_vec()
};
unsafe { ffi::FreeMemory(ptr as *mut _) };
return Some(data);
}
if !ptr.is_null() {
unsafe { ffi::FreeMemory(ptr as *mut _) };
}
None
}
pub fn al_status_extended(&self, slave_index: u16) -> u16 {
self.read_master_object(0xA000 + slave_index, 1)
.and_then(|d| if d.len() >= 2 { Some(u16::from_le_bytes([d[0], d[1]])) } else { None })
.unwrap_or(0)
}
pub fn last_al_status_code(&self, slave_index: u16) -> u16 {
self.read_master_object(0xA000 + slave_index, 2)
.and_then(|d| if d.len() >= 2 { Some(u16::from_le_bytes([d[0], d[1]])) } else { None })
.unwrap_or(0)
}
pub fn last_coe_soe_protocol_error(&self, slave_index: u16) -> u32 {
self.read_master_object(0xA000 + slave_index, 4)
.and_then(|d| if d.len() >= 4 { Some(u32::from_le_bytes([d[0], d[1], d[2], d[3]])) } else { None })
.unwrap_or(0)
}
pub fn cyclic_wc_error_counter(&self, slave_index: u16) -> u32 {
self.read_master_object(0xA000 + slave_index, 3)
.and_then(|d| if d.len() >= 4 { Some(u32::from_le_bytes([d[0], d[1], d[2], d[3]])) } else { None })
.unwrap_or(0)
}
pub fn new_diag_messages_available(&self, slave_index: u16) -> bool {
self.read_master_object(0xA000 + slave_index, 6)
.map(|d| d.first().copied().unwrap_or(0) != 0)
.unwrap_or(false)
}
pub fn disable_automatic_link_control(&self, slave_index: u16) -> bool {
self.read_master_object(0xA000 + slave_index, 5)
.map(|d| d.first().copied().unwrap_or(0) != 0)
.unwrap_or(false)
}
}