diff --git a/ethercat-hal/src/devices/el3024.rs b/ethercat-hal/src/devices/el3024.rs index 722b06ae..c1b082ae 100644 --- a/ethercat-hal/src/devices/el3024.rs +++ b/ethercat-hal/src/devices/el3024.rs @@ -1,23 +1,40 @@ use crate::{ coe::{ConfigurableDevice, Configuration}, pdo::{ el30xx::{AiCompact, AiStandard}, - PredefinedPdoAssignment, TxPdo, - }, shared_config::el30xx::{EL30XXConfiguration, EL30XXPresentation}, signing::Integer16 + PredefinedPdoAssignment, + }, shared_config::el30xx::{EL30XXChannelConfiguration, EL30XXPresentation}, signing::Integer16 }; use crate::{ io::analog_input::{AnalogInputDevice, AnalogInputInput, AnalogInputState}, types::EthercrabSubDevicePreoperational, }; use ethercat_hal_derive::{Device, RxPdo, TxPdo}; - use super::{NewDevice, SubDeviceIdentityTuple}; +use crate::pdo::RxPdo; +use crate::pdo::TxPdo; + +#[derive(Debug, Clone)] +pub struct EL3024Configuration { + pub pdo_assignment: EL3024PdoPreset, + // Input1+ and Input1- + pub channel1 : EL30XXChannelConfiguration, + // Input2+ and Input2- + pub channel2 : EL30XXChannelConfiguration, + // Input3+ and Input3- + pub channel3 : EL30XXChannelConfiguration, + // Input4+ and Input4- + pub channel4 : EL30XXChannelConfiguration +} #[derive(Device)] pub struct EL3024 { - pub input_ts: u64, + pub configuration: EL3024Configuration, pub txpdo: EL3024TxPdo, - pub configuration: EL30XXConfiguration, + pub rxpdo: EL3024RxPdo, + pub output_ts: u64, + pub input_ts: u64, + } impl std::fmt::Debug for EL3024 { @@ -32,13 +49,27 @@ impl Default for EL3024PdoPreset { } } +impl Default for EL3024Configuration { + fn default() -> Self { + Self { + pdo_assignment: EL3024PdoPreset::Standard, + channel1: EL30XXChannelConfiguration::default(), + channel2: EL30XXChannelConfiguration::default(), + channel3: EL30XXChannelConfiguration::default(), + channel4: EL30XXChannelConfiguration::default(), + } + } +} + impl NewDevice for EL3024 { fn new() -> Self { - let configuration: EL30XXConfiguration = EL30XXConfiguration::default(); + let configuration = EL3024Configuration::default(); // Initialize first Self { - input_ts: 0, + configuration: configuration.clone(), txpdo: configuration.pdo_assignment.txpdo_assignment(), - configuration, + rxpdo: configuration.pdo_assignment.rxpdo_assignment(), + output_ts: 0, + input_ts: 0, } } } @@ -92,11 +123,22 @@ impl AnalogInputDevice for EL3024 { }, }; let raw_value = Integer16::from(raw_value); - let value: i16 = match self.configuration.presentation { + println!("{}",raw_value); + + let presentation = match port { + EL3024Port::AI1 => self.configuration.channel1.presentation, + EL3024Port::AI2 => self.configuration.channel2.presentation, + EL3024Port::AI3 => self.configuration.channel3.presentation, + EL3024Port::AI4 => self.configuration.channel4.presentation + + }; + + let value: i16 = match presentation { EL30XXPresentation::Unsigned => raw_value.into_unsigned() as i16, EL30XXPresentation::Signed => raw_value.into_signed(), EL30XXPresentation::SignedMagnitude => raw_value.into_signed_magnitude(), }; + let normalized = f32::from(value) / f32::from(i16::MAX); AnalogInputState { input_ts: self.input_ts, @@ -105,11 +147,11 @@ impl AnalogInputDevice for EL3024 { } } -impl ConfigurableDevice> for EL3024 { +impl ConfigurableDevice for EL3024 { async fn write_config<'maindevice>( &mut self, device: &EthercrabSubDevicePreoperational<'maindevice>, - config: &EL30XXConfiguration, + config: &EL3024Configuration, ) -> Result<(), anyhow::Error> { config.write_config(device).await?; self.configuration = config.clone(); @@ -117,7 +159,7 @@ impl ConfigurableDevice EL30XXConfiguration { + fn get_config(&self) -> EL3024Configuration { self.configuration.clone() } } @@ -156,12 +198,26 @@ pub struct EL3024TxPdo { #[derive(Debug, Clone, RxPdo)] pub struct EL3024RxPdo {} - -impl Configuration for EL30XXConfiguration { +impl Configuration for EL3024Configuration { async fn write_config<'a>( &self, device: &EthercrabSubDevicePreoperational<'a>, ) -> Result<(), anyhow::Error> { + + // Write configuration for Channel 1 + self.channel1.write_channel_config(device, 0x8000) + .await?; + + // Write configuration for Channel 2 + self.channel2.write_channel_config(device, 0x8010) + .await?; + // Write configuration for Channel 3 + self.channel3.write_channel_config(device, 0x8020) + .await?; + + // Write configuration for Channel 4 + self.channel4.write_channel_config(device, 0x8030) + .await?; self.pdo_assignment .txpdo_assignment() .write_config(device) diff --git a/ethercat-hal/src/shared_config/el30xx.rs b/ethercat-hal/src/shared_config/el30xx.rs index 587169bc..79a79b33 100644 --- a/ethercat-hal/src/shared_config/el30xx.rs +++ b/ethercat-hal/src/shared_config/el30xx.rs @@ -1,178 +1,131 @@ -use crate::coe::Configuration; -use crate::pdo::PredefinedPdoAssignment; use crate::types::EthercrabSubDevicePreoperational; -use std::marker::PhantomData; // needed to avoid compile error -/// 0x8000 CoE -#[derive(Debug, Clone)] -pub struct EL30XXConfiguration where T:PredefinedPdoAssignment { - /// # 0x8000:01 - /// Enable user scale - /// - /// default: `false` - pub enable_user_scale: bool, - - /// # 0x8000:02 - /// Presentation - /// - /// default: `Signed` - pub presentation: EL30XXPresentation, - - /// # 0x8000:05 - /// Siemens bits - /// - /// default: `false` - pub siemens_bits: bool, - - /// # 0x8000:06 - /// Enable filter - /// - /// default: `true` - pub enable_filter: bool, - - /// # 0x8000:07 - /// Enable limit 1 - /// - /// default: `false` - pub enable_limit_1: bool, - - /// # 0x8000:08 - /// Enable limit 2 - /// - /// default: `false` - pub enable_limit_2: bool, - - /// # 0x8000:0A - /// Enable user calibration - /// - /// default: `false` - pub enable_user_calibration: bool, - - /// # 0x8000:0B - /// Enable vendor calibration - /// - /// default: `true` - pub enable_vendor_calibration: bool, - - /// # 0x8000:0E - /// Swap limit bits - /// - /// default: `false` - pub swap_limit_bits: bool, - - /// # 0x8000:11 - /// User scale offset - /// - /// default: `0` - pub user_scale_offset: i16, - - /// # 0x8000:12 - /// User scale gain - /// - /// default: `65536` - pub user_scale_gain: i32, - - /// # 0x8000:13 - /// Limit 1 - /// - /// default: `0` - pub limit_1: i16, - - /// # 0x8000:14 - /// Limit 2 - /// - /// default: `0` - pub limit_2: i16, - - /// # 0x8000:15 - /// Filter settings - /// - /// default: `50 Hz FIR` - pub filter_settings: EL30XXFilterSettings, - - /// # 0x8000:17 - /// User calibration offset - /// - /// default: `0` - pub user_calibration_offset: i16, - - /// # 0x8000:18 - /// User calibration gain - /// - /// default: `16384` - pub user_calibration_gain: i16, - - /// # 0x1400 & 0x1600 - pub pdo_assignment: T, - - // PhantomData ensures A and B are "used" without being stored - pub _marker_a: PhantomData, // needed to avoid compile error - pub _marker_b: PhantomData, // needed to avoid compile error -} - - - - - -impl Configuration for EL30XXConfiguration -where - T: PredefinedPdoAssignment + Configuration, - A: Configuration, // Ensures pdo_assignment can call write_config() - B: Configuration -{ - async fn write_config<'a>( +impl EL30XXChannelConfiguration { + pub async fn write_channel_config<'a>( &self, device: &EthercrabSubDevicePreoperational<'a>, + base_index: u16, ) -> Result<(), anyhow::Error> { device - .sdo_write(0x8000, 0x01, self.enable_user_scale) + .sdo_write(base_index, 0x01, self.enable_user_scale) .await?; device - .sdo_write(0x8000, 0x02, u8::from(self.presentation)) + .sdo_write(base_index, 0x02, u8::from(self.presentation)) .await?; - device.sdo_write(0x8000, 0x05, self.siemens_bits).await?; - device.sdo_write(0x8000, 0x06, self.enable_filter).await?; - device.sdo_write(0x8000, 0x07, self.enable_limit_1).await?; - device.sdo_write(0x8000, 0x08, self.enable_limit_2).await?; + device.sdo_write(base_index, 0x05, self.siemens_bits).await?; + device.sdo_write(base_index, 0x06, self.enable_filter).await?; + device.sdo_write(base_index, 0x07, self.enable_limit_1).await?; + device.sdo_write(base_index, 0x08, self.enable_limit_2).await?; device - .sdo_write(0x8000, 0x0A, self.enable_user_calibration) + .sdo_write(base_index, 0x0A, self.enable_user_calibration) .await?; device - .sdo_write(0x8000, 0x0B, self.enable_vendor_calibration) + .sdo_write(base_index, 0x0B, self.enable_vendor_calibration) .await?; - device.sdo_write(0x8000, 0x0E, self.swap_limit_bits).await?; + device.sdo_write(base_index, 0x0E, self.swap_limit_bits).await?; device - .sdo_write(0x8000, 0x11, self.user_scale_offset) + .sdo_write(base_index, 0x11, self.user_scale_offset) .await?; - device.sdo_write(0x8000, 0x12, self.user_scale_gain).await?; - device.sdo_write(0x8000, 0x13, self.limit_1).await?; - device.sdo_write(0x8000, 0x14, self.limit_2).await?; + device.sdo_write(base_index, 0x12, self.user_scale_gain).await?; + device.sdo_write(base_index, 0x13, self.limit_1).await?; + device.sdo_write(base_index, 0x14, self.limit_2).await?; device - .sdo_write(0x8000, 0x15, u16::from(self.filter_settings)) + .sdo_write(base_index, 0x15, u16::from(self.filter_settings)) .await?; device - .sdo_write(0x8000, 0x17, self.user_calibration_offset) + .sdo_write(base_index, 0x17, self.user_calibration_offset) .await?; device - .sdo_write(0x8000, 0x18, self.user_calibration_gain) - .await?; - self.pdo_assignment - .txpdo_assignment() - .write_config(device) - .await?; - self.pdo_assignment - .rxpdo_assignment() - .write_config(device) + .sdo_write(base_index, 0x18, self.user_calibration_gain) .await?; Ok(()) } } -impl Default for EL30XXConfiguration -where - T: PredefinedPdoAssignment, - T: Default, // Ensure `T` has a default value +#[derive(Debug, Clone)] +pub struct EL30XXChannelConfiguration { + // 80n0:01 User Scaling is Active + pub enable_user_scale : bool, + // 80n0:02 + // 0: Signed presentation + // 1: Unsigned presentation + // 2: Absolute value with MSB as sign + // Signed amount representation + pub presentation : EL30XXPresentation, + + // 80n0:03 + // the S5 bits are displayed in the three low-order bits + pub siemens_bits : bool, + + // 80n0:04 + // Enable filter, which makes PLC-cycle-synchronous + // data exchange unnecessary + pub enable_filter : bool, + + // 80n0:05 + // limit 1 enabled + pub enable_limit_1 : bool, + + // 80n0:06 + // limit2 enabled + pub enable_limit_2 : bool, + + // 80n0:07 + // enabling of user_calibration + pub enable_user_calibration : bool, + + // 80n0:08 + // enabling of vendor_calibration + pub enable_vendor_calibration : bool, + + // 80n0:09 + // Swap Limit Bits + pub swap_limit_bits : bool, + + // 80n0:10 + // User Scaling Offset + pub user_scale_offset : i16, + + // 80n0:11 + // Gain of the user scaling + // The gain has a fixed-point-representation with the factor + // 2^-16 The value 1 corresponds to 65535 and is limited to +/- 0x7FFFFF + pub user_scale_gain : i32, + + // 80n0:12 + // First limit value for setting the status bits + pub limit_1: i16, + + // 80n0:13 + // Second limit value for setting the status bits + pub limit_2: i16, + + // 80n0:14 + /* + This object determines the digital filter settings if it is + active via Enable filter (Index base_index:06 [} 320]). + The possible settings are numbered consecutively. + 0: 50 Hz FIR + 1: 60 Hz FIR + 2: IIR 1 + 3: IIR 2 + ... + 9: IIR 8 + */ + pub filter_settings: EL30XXFilterSettings, + + // 80n0:15 + // User calibration offset + pub user_calibration_offset: i16, + + // 80n0:16 + // User calibration gain + pub user_calibration_gain: i16 +} + + +impl Default for EL30XXChannelConfiguration { fn default() -> Self { Self { @@ -191,16 +144,11 @@ where limit_2: 0, filter_settings: EL30XXFilterSettings::FIR50Hz, user_calibration_offset: 0, - user_calibration_gain: 16384, - pdo_assignment: T::default(), // Use the default for `T` - _marker_a: PhantomData, // needed to avoid compile error - _marker_b: PhantomData // needed to avoid compile error + user_calibration_gain: 16384, } } } - - #[derive(Debug, Clone, Copy)] pub enum EL30XXPresentation { Signed, diff --git a/server/src/ethercat/loop.rs b/server/src/ethercat/loop.rs index 658e751c..329f4c65 100644 --- a/server/src/ethercat/loop.rs +++ b/server/src/ethercat/loop.rs @@ -7,11 +7,14 @@ use crate::{ ethercat::config::{MAX_FRAMES, MAX_PDU_DATA, MAX_SUBDEVICES, PDI_LEN}, }; use bitvec::prelude::*; +use control_core::actors::analog_input_getter::{AnalogInputDevice, AnalogInputGetter}; use control_core::actors::Actor; use control_core::identification::identify_device_groups; use control_core::socketio::event::EventBuilder; use control_core::socketio::room::RoomCacheingLogic; -use ethercat_hal::devices::devices_from_subdevices; +use ethercat_hal::devices::el3024::{EL3024Port, EL3024}; +use ethercat_hal::devices::{devices_from_subdevices, downcast_device}; +use ethercat_hal::io::analog_input::AnalogInput; use ethercrab::std::{ethercat_now, tx_rx_task}; use ethercrab::{MainDevice, MainDeviceConfig, PduStorage, RetryBehaviour, Timeouts}; use smol::lock::RwLock; @@ -133,6 +136,11 @@ pub async fn setup_loop(interface: &str, app_state: Arc) -> Result<(), } } + let el3024 = downcast_device::(devices.get(1).unwrap().clone()).await.unwrap(); + let analog_input = AnalogInput::new(el3024, EL3024Port::AI1); + let analog_input_getter = AnalogInputGetter::new(analog_input, AnalogInputDevice::EL305x.into()); + actors.push(Arc::new(RwLock::new(analog_input_getter))); + // Write all this stuff to `app_state` { let mut ethercat_setup_guard = app_state.ethercat_setup.write().await; diff --git a/server/src/machines/winder1/new.rs b/server/src/machines/winder1/new.rs index eed35372..95dbb081 100644 --- a/server/src/machines/winder1/new.rs +++ b/server/src/machines/winder1/new.rs @@ -16,7 +16,7 @@ use ethercat_hal::devices::el2521::{EL2521Configuration, EL2521Port, EL2521}; use ethercat_hal::devices::el2522::{ EL2522ChannelConfiguration, EL2522Configuration, EL2522Port, EL2522, }; -use ethercat_hal::devices::el3001::{EL3001PdoPreset, EL3001Port, EL3001}; +use ethercat_hal::devices::el3001::{EL3001Configuration, EL3001PdoPreset, EL3001Port, EL3001}; use ethercat_hal::devices::{downcast_device, subdevice_identity_to_tuple, Device}; use ethercat_hal::devices::{ ek1100::EK1100_IDENTITY_A, @@ -28,7 +28,6 @@ use ethercat_hal::devices::{ use ethercat_hal::io::analog_input::AnalogInput; use ethercat_hal::io::digital_output::DigitalOutput; use ethercat_hal::io::pulse_train_output::PulseTrainOutput; -use ethercat_hal::shared_config::el30xx::EL30XXConfiguration; use ethercat_hal::types::EthercrabSubDevicePreoperational; use futures::executor::block_on; use smol::lock::RwLock; @@ -120,7 +119,7 @@ impl MachineNewTrait for WinderV1 { .await .write_config( &subdevice, - &EL30XXConfiguration { + &EL3001Configuration { pdo_assignment: EL3001PdoPreset::Compact, ..Default::default() },