wago modules detected and wrapped as an EtherCatDevice
This commit is contained in:
1 parent
e4d0b3c5be
commit
8c7e810359
17 files changed
+1110
-94
No files matched your search
@@ -251,6 +251,27 @@ pub fn ethercat_device_derive(input: TokenStream) -> TokenStream {
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
#[doc="Implemented by the ethercat_hal_derive::EthercatDevice derive macro"]
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
#[doc="Implemented by the ethercat_hal_derive::EthercatDevice derive macro"]
|
||||
fn is_module(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[doc="Implemented by the ethercat_hal_derive::EthercatDevice derive macro"]
|
||||
fn get_module(&self) -> Option<crate::devices::Module> {
|
||||
None
|
||||
}
|
||||
|
||||
#[doc="Implemented by the ethercat_hal_derive::EthercatDevice derive macro"]
|
||||
fn set_module(&mut self,module : crate::devices::Module){
|
||||
()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl crate::devices::EthercatDeviceUsed for #name {
|
||||
|
||||
@@ -21,6 +21,7 @@ pub mod el7031;
|
||||
pub mod el7031_0030;
|
||||
pub mod el7041_0052;
|
||||
pub mod wago_750_354;
|
||||
pub mod wago_modules;
|
||||
|
||||
use super::devices::el1008::EL1008;
|
||||
use crate::{
|
||||
@@ -42,17 +43,29 @@ use el3021::EL3021_IDENTITY_A;
|
||||
use el3024::EL3024_IDENTITY_A;
|
||||
use el3062_0030::EL3062_0030_IDENTITY_A;
|
||||
use el3204::EL3204_IDENTITY_A;
|
||||
use el3204::EL3204_IDENTITY_B;
|
||||
use el4002::EL4002_IDENTITY_A;
|
||||
use el5152::{EL5152, EL5152_IDENTITY_A};
|
||||
use el6021::{EL6021_IDENTITY_A, EL6021_IDENTITY_B, EL6021_IDENTITY_C, EL6021_IDENTITY_D};
|
||||
use el3204::EL3204_IDENTITY_B;
|
||||
use el7031::{EL7031_IDENTITY_A, EL7031_IDENTITY_B};
|
||||
use el7031_0030::EL7031_0030_IDENTITY_A;
|
||||
use el7041_0052::EL7041_0052_IDENTITY_A;
|
||||
use ethercrab::{MainDevice, SubDeviceIdentity};
|
||||
use smol::lock::RwLock;
|
||||
use wago_750_354::{WAGO_750_354_IDENTITY_A, Wago750_354};
|
||||
use std::{any::Any, fmt::Debug, sync::Arc};
|
||||
use wago_750_354::{WAGO_750_354_IDENTITY_A, Wago750_354};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Module {
|
||||
pub slot: u16,
|
||||
pub belongs_to_addr: u16,
|
||||
pub has_tx: bool,
|
||||
pub has_rx: bool,
|
||||
pub vendor_id: u32,
|
||||
pub product_id: u32,
|
||||
pub tx_offset: usize,
|
||||
pub rx_offset: usize,
|
||||
}
|
||||
|
||||
/// A trait for all devices
|
||||
///
|
||||
@@ -77,7 +90,7 @@ where
|
||||
/// automatically validate input length, then calls input
|
||||
fn input_checked(&mut self, input: &BitSlice<u8, Lsb0>) -> Result<(), anyhow::Error> {
|
||||
// validate input has correct length
|
||||
let expected = self.input_len();
|
||||
/* let expected = self.input_len();
|
||||
let actual = input.len();
|
||||
if actual != expected {
|
||||
return Err(anyhow::anyhow!(
|
||||
@@ -88,7 +101,7 @@ where
|
||||
expected,
|
||||
expected / 8
|
||||
));
|
||||
}
|
||||
}*/
|
||||
self.input(input)
|
||||
}
|
||||
|
||||
@@ -103,7 +116,7 @@ where
|
||||
self.output(output)?;
|
||||
|
||||
// validate input has correct length
|
||||
let expected = self.output_len();
|
||||
/*let expected = self.output_len();
|
||||
let actual = output.len();
|
||||
if output.len() != expected {
|
||||
return Err(anyhow::anyhow!(
|
||||
@@ -114,12 +127,26 @@ where
|
||||
expected,
|
||||
expected / 8
|
||||
));
|
||||
}
|
||||
}*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
fn is_module(&self) -> bool;
|
||||
fn get_module(&self) -> Option<Module>;
|
||||
fn set_module(&mut self, module: Module);
|
||||
}
|
||||
|
||||
pub trait DynamicEthercatDevice: EthercatDevice + EthercatDynamicPDO {}
|
||||
|
||||
pub trait EthercatDynamicPDO {
|
||||
fn get_tx_offset(&self) -> usize;
|
||||
fn get_rx_offset(&self) -> usize;
|
||||
|
||||
fn set_tx_offset(&mut self, offset: usize);
|
||||
fn set_rx_offset(&mut self, offset: usize);
|
||||
}
|
||||
|
||||
/// A trait for devices that want to process input and output data
|
||||
@@ -257,6 +284,10 @@ pub async fn specific_device_from_devices<DEVICE: EthercatDevice>(
|
||||
}
|
||||
|
||||
pub type SubDeviceIdentityTuple = (u32, u32, u32);
|
||||
|
||||
// Is vendor id at 0, and prodid at 1
|
||||
pub type SubDeviceProductTuple = (u32, u32);
|
||||
|
||||
/// function that converts SubDeviceIdentity to tuple
|
||||
pub const fn subdevice_identity_to_tuple(identity: &SubDeviceIdentity) -> SubDeviceIdentityTuple {
|
||||
(identity.vendor_id, identity.product_id, identity.revision)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
||||
pub const WAGO_750_1506_VENDOR_ID: u32 = 0x00000021;
|
||||
pub const WAGO_750_1506_PRODUCT_ID: u32 = 0x07500354;
|
||||
@@ -1,52 +1,155 @@
|
||||
use std::sync::Arc;
|
||||
use crate::helpers::ethercrab_types::EthercrabSubDevicePreoperational;
|
||||
|
||||
use super::{EthercatDevice, EthercatDeviceProcessing, NewEthercatDevice, SubDeviceIdentityTuple};
|
||||
use super::{
|
||||
EthercatDevice, EthercatDeviceProcessing, EthercatDeviceUsed, NewEthercatDevice,
|
||||
SubDeviceIdentityTuple,
|
||||
};
|
||||
use crate::devices::wago_modules::*;
|
||||
use crate::{
|
||||
devices::{
|
||||
DynamicEthercatDevice, Module,
|
||||
wago_modules::{
|
||||
wago_750_501::{WAGO_750_501_MODULE_IDENT, WAGO_750_501_PRODUCT_ID},
|
||||
wago_750_652::{WAGO_750_652_MODULE_IDENT, WAGO_750_652_PRODUCT_ID},
|
||||
wago_750_1506::{WAGO_750_1506_MODULE_IDENT, WAGO_750_1506_PRODUCT_ID},
|
||||
},
|
||||
},
|
||||
helpers::ethercrab_types::EthercrabSubDevicePreoperational,
|
||||
};
|
||||
use anyhow::Error;
|
||||
use ethercat_hal_derive::EthercatDevice;
|
||||
use smol::lock::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
const MODULE_COUNT_INDEX : (u16,u8) = (0xf050,0x00);
|
||||
|
||||
const TX_MAPPING_INDEX : (u16,u8) = (0x1c13,0x00);
|
||||
const RX_MAPPING_INDEX : (u16,u8) = (0x1c12,0x00);
|
||||
const MODULE_COUNT_INDEX: (u16, u8) = (0xf050, 0x00);
|
||||
const TX_MAPPING_INDEX: (u16, u8) = (0x1c13, 0x00);
|
||||
const RX_MAPPING_INDEX: (u16, u8) = (0x1c12, 0x00);
|
||||
// For both the rx and tx The Wago Coupler has 4 bytes, which we dont care about and skip
|
||||
|
||||
/// Wago750_354 bus coupler
|
||||
#[derive(Clone, EthercatDevice)]
|
||||
/*
|
||||
The "Modules" simply write at an offset into rx and read at an offset in tx
|
||||
*/
|
||||
pub struct Wago750_354 {
|
||||
is_used: bool,
|
||||
pub slots: [Option<Module>; 64],
|
||||
pub slot_devices: [Option<Arc<RwLock<dyn DynamicEthercatDevice>>>; 64],
|
||||
pub dev_count: usize,
|
||||
pub module_count: usize,
|
||||
rx_offsets: Vec<usize>,
|
||||
tx_offsets: Vec<usize>,
|
||||
tx_size: usize,
|
||||
rx_size: usize,
|
||||
}
|
||||
|
||||
impl EthercatDevice for Wago750_354 {
|
||||
fn input(
|
||||
&mut self,
|
||||
input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
for slot_device in &mut self.slot_devices {
|
||||
match slot_device {
|
||||
Some(device) => {
|
||||
// Give all Modules access to the couplers input image and call their input func
|
||||
let mut d = device.write_blocking();
|
||||
let _ = d.input(input);
|
||||
drop(d);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn input_len(&self) -> usize {
|
||||
self.tx_size
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
for slot_device in &self.slot_devices {
|
||||
match slot_device {
|
||||
Some(device) => {
|
||||
// Give all Modules access to the couplers Output image and call their output func
|
||||
let d = device.read_blocking();
|
||||
let _ = d.output(output);
|
||||
drop(d);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_len(&self) -> usize {
|
||||
self.rx_size
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn is_module(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn get_module(&self) -> Option<Module> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set_module(&mut self, module: Module) {
|
||||
self.slots[self.module_count] = Some(module);
|
||||
self.module_count += 1;
|
||||
self.tx_size += module.tx_offset;
|
||||
self.rx_size += module.rx_offset;
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceUsed for Wago750_354 {
|
||||
fn is_used(&self) -> bool {
|
||||
self.is_used
|
||||
}
|
||||
|
||||
fn set_used(&mut self, used: bool) {
|
||||
self.is_used = used;
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceProcessing for Wago750_354 {}
|
||||
|
||||
impl NewEthercatDevice for Wago750_354 {
|
||||
fn new() -> Self {
|
||||
Self { is_used: false }
|
||||
Self {
|
||||
is_used: false,
|
||||
slots: [const { None }; 64],
|
||||
slot_devices: [const { None }; 64],
|
||||
module_count: 0,
|
||||
dev_count: 0,
|
||||
tx_size: 0,
|
||||
rx_size: 0,
|
||||
rx_offsets: vec![],
|
||||
tx_offsets: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Wago750_354 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Wago_750_354")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub slot : u16,
|
||||
pub belongs_to_slave_index : u16,
|
||||
pub has_tx : bool,
|
||||
pub has_rx : bool,
|
||||
pub vendor_id : u32,
|
||||
pub product_id : u32,
|
||||
pub name : String,
|
||||
}
|
||||
|
||||
impl Wago750_354 {
|
||||
pub async fn get_pdo_offsets<'a>(device: &EthercrabSubDevicePreoperational<'a>,get_tx : bool) -> Result<Vec<usize>,Error> {
|
||||
let mut vec : Vec<usize>= vec![];
|
||||
pub async fn get_pdo_offsets<'a>(
|
||||
&mut self,
|
||||
device: &EthercrabSubDevicePreoperational<'a>,
|
||||
get_tx: bool,
|
||||
) -> Result<(), Error> {
|
||||
let mut vec: Vec<usize> = vec![];
|
||||
let mut bit_offset = 0;
|
||||
let start_subindex = 0x1;
|
||||
let index = match get_tx {
|
||||
@@ -57,69 +160,182 @@ impl Wago750_354 {
|
||||
|
||||
for i in 0..count {
|
||||
vec.push(bit_offset);
|
||||
let pdo_index = device.sdo_read(index.0, start_subindex+i).await?;
|
||||
let pdo_index = device.sdo_read(index.0, start_subindex + i).await?;
|
||||
if pdo_index != 0 {
|
||||
let pdo_map_count = device.sdo_read::<u8>(pdo_index, 0).await?;
|
||||
|
||||
// Iterate over every PDO Mapped entry and add it to the cumulative bit offset
|
||||
for j in 0..pdo_map_count {
|
||||
let pdo_mapping : u32 = device.sdo_read(pdo_index, 1 + j).await?;
|
||||
// We only need / Want the bit len
|
||||
let pdo_mapping: u32 = device.sdo_read(pdo_index, 1 + j).await?;
|
||||
// We only need / Want the bit len, which we extract with a bitmask extracting the lsb
|
||||
let bit_length = (pdo_mapping & 0xFF) as u8;
|
||||
bit_offset += bit_length as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
tracing::info!("{} is tx: {}",count,get_tx);
|
||||
Ok(vec)
|
||||
if get_tx {
|
||||
self.tx_offsets = vec;
|
||||
} else {
|
||||
self.rx_offsets = vec;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// The Coupler gets itself as a Preop Subdevice
|
||||
pub async fn get_module_count<'a>(device: &EthercrabSubDevicePreoperational<'a>) -> Result<usize,Error> {
|
||||
match device.sdo_read::<u8>(MODULE_COUNT_INDEX.0, MODULE_COUNT_INDEX.1).await {
|
||||
pub async fn get_module_count<'a>(
|
||||
device: &EthercrabSubDevicePreoperational<'a>,
|
||||
) -> Result<usize, Error> {
|
||||
match device
|
||||
.sdo_read::<u8>(MODULE_COUNT_INDEX.0, MODULE_COUNT_INDEX.1)
|
||||
.await
|
||||
{
|
||||
Ok(value) => Ok(value as usize),
|
||||
Err(e) => Err(anyhow::anyhow!("Failed to read Module Count for Wago750_354: {:?}",e)),
|
||||
Err(e) => Err(anyhow::anyhow!(
|
||||
"Failed to read Module Count for Wago750_354: {:?}",
|
||||
e
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_modules<'a>(device: &EthercrabSubDevicePreoperational<'a>, module_count : usize) -> Result<Vec<Module>,Error> {
|
||||
const MODULES_START_ADDR : u16 = 0x9000;
|
||||
let modules : Vec<Module> = vec![];
|
||||
// This should probably be a generic function instead
|
||||
pub async fn get_modules<'a>(
|
||||
device: &EthercrabSubDevicePreoperational<'a>,
|
||||
module_count: usize,
|
||||
) -> Result<Vec<crate::devices::Module>, Error> {
|
||||
const MODULES_START_ADDR: u16 = 0x9000;
|
||||
const MODULE_IDENT_SUBINDEX: u8 = 0x0a;
|
||||
let mut modules: Vec<Module> = vec![];
|
||||
for i in 0..module_count {
|
||||
let module_addr = MODULES_START_ADDR + (i * 0x10) as u16;
|
||||
let ident = device.sdo_read::<u32>(module_addr, 0x00).await?;
|
||||
device.sdo_read(index, sub_index).await?;
|
||||
let ident_iom = device
|
||||
.sdo_read::<u32>(module_addr, MODULE_IDENT_SUBINDEX)
|
||||
.await?;
|
||||
// For Wago the IOM well be the product ID
|
||||
let mut module = Module {
|
||||
slot: i as u16,
|
||||
belongs_to_addr: device.configured_address(),
|
||||
vendor_id: device.identity().vendor_id,
|
||||
product_id: ident_iom,
|
||||
has_tx: false,
|
||||
has_rx: false,
|
||||
tx_offset: 0,
|
||||
rx_offset: 0,
|
||||
};
|
||||
|
||||
match ident_iom {
|
||||
// Add Module idents here:
|
||||
WAGO_750_1506_PRODUCT_ID => {
|
||||
module.has_tx = true;
|
||||
module.has_rx = true;
|
||||
}
|
||||
WAGO_750_501_PRODUCT_ID => {
|
||||
module.has_tx = false;
|
||||
module.has_rx = true;
|
||||
}
|
||||
WAGO_750_652_PRODUCT_ID => {
|
||||
module.has_tx = true;
|
||||
module.has_rx = true;
|
||||
}
|
||||
_ => println!(
|
||||
"Wago-750-354 found Unknown/Unimplemented Module: {}",
|
||||
ident_iom
|
||||
),
|
||||
}
|
||||
modules.push(module);
|
||||
}
|
||||
Ok(vec![])
|
||||
Ok(modules)
|
||||
}
|
||||
|
||||
pub async fn initialize_modules<'a> (device: &EthercrabSubDevicePreoperational<'a>) -> Result<Vec<Arc<RwLock<dyn EthercatDevice>>>,Error> {
|
||||
/// Call after all modules have been added
|
||||
pub fn init_slot_modules<'a>(&mut self, device: &EthercrabSubDevicePreoperational<'a>) {
|
||||
// Already initialized
|
||||
if self.dev_count != 0 {
|
||||
return;
|
||||
}
|
||||
let mut tx_index = 1;
|
||||
let mut rx_index = 1;
|
||||
|
||||
smol::block_on(async {
|
||||
let _ = self.get_pdo_offsets(device, true).await;
|
||||
let _ = self.get_pdo_offsets(device, false).await;
|
||||
});
|
||||
|
||||
for module in self.slots {
|
||||
match module {
|
||||
Some(m) => {
|
||||
// Map ModuleIdent's to Terminals
|
||||
let dev: Arc<RwLock<dyn DynamicEthercatDevice>> = match (
|
||||
m.vendor_id,
|
||||
m.product_id,
|
||||
) {
|
||||
WAGO_750_501_MODULE_IDENT => {
|
||||
Arc::new(RwLock::new(wago_750_501::Wago750_501::new()))
|
||||
}
|
||||
WAGO_750_1506_MODULE_IDENT => {
|
||||
Arc::new(RwLock::new(wago_750_1506::Wago750_1506::new()))
|
||||
}
|
||||
WAGO_750_652_MODULE_IDENT => {
|
||||
Arc::new(RwLock::new(wago_750_652::Wago750_652::new()))
|
||||
}
|
||||
_ => {
|
||||
println!(
|
||||
"{} Missing Implementation for Module Identification: vendor_id: {:?}, module ident: {:?} !",
|
||||
module_path!(),
|
||||
m.vendor_id,
|
||||
m.product_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let tx_pdo_offset = self.tx_offsets.get(tx_index as usize);
|
||||
if m.has_tx {
|
||||
tx_index += 1;
|
||||
}
|
||||
|
||||
let rx_pdo_offset = self.rx_offsets.get(rx_index as usize);
|
||||
if m.has_rx {
|
||||
rx_index += 1;
|
||||
}
|
||||
|
||||
let mut dev_guard = dev.write_blocking();
|
||||
match tx_pdo_offset {
|
||||
Some(offset) => dev_guard.set_tx_offset(*offset),
|
||||
None => (),
|
||||
}
|
||||
|
||||
match rx_pdo_offset {
|
||||
Some(offset) => dev_guard.set_rx_offset(*offset),
|
||||
None => (),
|
||||
}
|
||||
drop(dev_guard);
|
||||
self.slot_devices[self.dev_count] = Some(dev);
|
||||
self.dev_count += 1;
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize_modules<'a>(
|
||||
device: &EthercrabSubDevicePreoperational<'a>,
|
||||
) -> Result<Vec<Module>, Error> {
|
||||
let count = match Wago750_354::get_module_count(device).await {
|
||||
Ok(count) => count,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
if count == 0 {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let tx_offsets = Wago750_354::get_pdo_offsets(device,true).await?;
|
||||
let rx_offsets = Wago750_354::get_pdo_offsets(device,false).await?;
|
||||
|
||||
println!("{:?}",tx_offsets);
|
||||
println!("{:?}",rx_offsets);
|
||||
Ok(vec![])
|
||||
let modules = Wago750_354::get_modules(device, count).await?;
|
||||
Ok(modules)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pub const WAGO_750_354_VENDOR_ID: u32 = 0x00000021;
|
||||
pub const WAGO_750_354_PRODUCT_ID: u32 = 0x07500354;
|
||||
pub const WAGO_750_354_REVISION_A: u32 = 0x2;
|
||||
pub const WAGO_750_354_IDENTITY_A: SubDeviceIdentityTuple =
|
||||
(WAGO_750_354_VENDOR_ID, WAGO_750_354_PRODUCT_ID, WAGO_750_354_REVISION_A);
|
||||
pub const WAGO_750_354_IDENTITY_A: SubDeviceIdentityTuple = (
|
||||
WAGO_750_354_VENDOR_ID,
|
||||
WAGO_750_354_PRODUCT_ID,
|
||||
WAGO_750_354_REVISION_A,
|
||||
);
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,3 @@
|
||||
pub mod wago_750_1506;
|
||||
pub mod wago_750_501;
|
||||
pub mod wago_750_652;
|
||||
@@ -0,0 +1,335 @@
|
||||
use crate::{
|
||||
devices::{
|
||||
DynamicEthercatDevice, EthercatDevice, EthercatDeviceProcessing, EthercatDeviceUsed,
|
||||
EthercatDynamicPDO, Module, NewEthercatDevice, SubDeviceProductTuple,
|
||||
},
|
||||
io::{
|
||||
digital_input::{DigitalInputDevice, DigitalInputInput},
|
||||
digital_output::{DigitalOutputDevice, DigitalOutputOutput},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Wago750_1506OutputPort {
|
||||
DO1,
|
||||
DO2,
|
||||
DO3,
|
||||
DO4,
|
||||
DO5,
|
||||
DO6,
|
||||
DO7,
|
||||
DO8,
|
||||
}
|
||||
|
||||
impl From<Wago750_1506OutputPort> for usize {
|
||||
fn from(value: Wago750_1506OutputPort) -> Self {
|
||||
match value {
|
||||
Wago750_1506OutputPort::DO1 => 0,
|
||||
Wago750_1506OutputPort::DO2 => 1,
|
||||
Wago750_1506OutputPort::DO3 => 2,
|
||||
Wago750_1506OutputPort::DO4 => 3,
|
||||
Wago750_1506OutputPort::DO5 => 4,
|
||||
Wago750_1506OutputPort::DO6 => 5,
|
||||
Wago750_1506OutputPort::DO7 => 6,
|
||||
Wago750_1506OutputPort::DO8 => 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Wago750_1506InputPort {
|
||||
DO1,
|
||||
DO2,
|
||||
DO3,
|
||||
DO4,
|
||||
DO5,
|
||||
DO6,
|
||||
DO7,
|
||||
DO8,
|
||||
}
|
||||
|
||||
impl From<Wago750_1506InputPort> for usize {
|
||||
fn from(value: Wago750_1506InputPort) -> Self {
|
||||
match value {
|
||||
Wago750_1506InputPort::DO1 => 0,
|
||||
Wago750_1506InputPort::DO2 => 1,
|
||||
Wago750_1506InputPort::DO3 => 2,
|
||||
Wago750_1506InputPort::DO4 => 3,
|
||||
Wago750_1506InputPort::DO5 => 4,
|
||||
Wago750_1506InputPort::DO6 => 5,
|
||||
Wago750_1506InputPort::DO7 => 6,
|
||||
Wago750_1506InputPort::DO8 => 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Wago750_1506RxPdo {
|
||||
port1: bool,
|
||||
port2: bool,
|
||||
port3: bool,
|
||||
port4: bool,
|
||||
port5: bool,
|
||||
port6: bool,
|
||||
port7: bool,
|
||||
port8: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Wago750_1506TxPdo {
|
||||
port1: bool,
|
||||
port2: bool,
|
||||
port3: bool,
|
||||
port4: bool,
|
||||
port5: bool,
|
||||
port6: bool,
|
||||
port7: bool,
|
||||
port8: bool,
|
||||
}
|
||||
|
||||
impl DigitalInputDevice<Wago750_1506InputPort> for Wago750_1506 {
|
||||
fn get_input(&self, port: Wago750_1506InputPort) -> Result<DigitalInputInput, anyhow::Error> {
|
||||
Ok(DigitalInputInput {
|
||||
value: match port {
|
||||
Wago750_1506InputPort::DO1 => self.tx_pdo.port1,
|
||||
Wago750_1506InputPort::DO2 => self.tx_pdo.port2,
|
||||
Wago750_1506InputPort::DO3 => self.tx_pdo.port3,
|
||||
Wago750_1506InputPort::DO4 => self.tx_pdo.port4,
|
||||
Wago750_1506InputPort::DO5 => self.tx_pdo.port5,
|
||||
Wago750_1506InputPort::DO6 => self.tx_pdo.port6,
|
||||
Wago750_1506InputPort::DO7 => self.tx_pdo.port7,
|
||||
Wago750_1506InputPort::DO8 => self.tx_pdo.port8,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DigitalOutputDevice<Wago750_1506OutputPort> for Wago750_1506 {
|
||||
/// Writes the new output value into the device's RXPDO structure (in-memory PDI).
|
||||
fn set_output(&mut self, port: Wago750_1506OutputPort, value: DigitalOutputOutput) {
|
||||
// The DigitalOutputOutput is converted to a bool using the From trait
|
||||
let output_value: bool = value.into();
|
||||
match port {
|
||||
Wago750_1506OutputPort::DO1 => self.rx_pdo.port1 = output_value,
|
||||
Wago750_1506OutputPort::DO2 => self.rx_pdo.port2 = output_value,
|
||||
Wago750_1506OutputPort::DO3 => self.rx_pdo.port3 = output_value,
|
||||
Wago750_1506OutputPort::DO4 => self.rx_pdo.port4 = output_value,
|
||||
Wago750_1506OutputPort::DO5 => self.rx_pdo.port5 = output_value,
|
||||
Wago750_1506OutputPort::DO6 => self.rx_pdo.port6 = output_value,
|
||||
Wago750_1506OutputPort::DO7 => self.rx_pdo.port7 = output_value,
|
||||
Wago750_1506OutputPort::DO8 => self.rx_pdo.port8 = output_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the current output value from the device's RXPDO structure (in-memory PDI).
|
||||
fn get_output(&self, port: Wago750_1506OutputPort) -> DigitalOutputOutput {
|
||||
let current_value = match port {
|
||||
Wago750_1506OutputPort::DO1 => self.rx_pdo.port1,
|
||||
Wago750_1506OutputPort::DO2 => self.rx_pdo.port2,
|
||||
Wago750_1506OutputPort::DO3 => self.rx_pdo.port3,
|
||||
Wago750_1506OutputPort::DO4 => self.rx_pdo.port4,
|
||||
Wago750_1506OutputPort::DO5 => self.rx_pdo.port5,
|
||||
Wago750_1506OutputPort::DO6 => self.rx_pdo.port6,
|
||||
Wago750_1506OutputPort::DO7 => self.rx_pdo.port7,
|
||||
Wago750_1506OutputPort::DO8 => self.rx_pdo.port8,
|
||||
};
|
||||
// Wrap the bool back into the type-safe wrapper
|
||||
DigitalOutputOutput(current_value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Wago750_1506 {
|
||||
is_used: bool,
|
||||
tx_bit_offset: usize,
|
||||
rx_bit_offset: usize,
|
||||
// Should always have on but not when calling constructor
|
||||
module: Option<Module>,
|
||||
rx_pdo: Wago750_1506RxPdo,
|
||||
tx_pdo: Wago750_1506TxPdo,
|
||||
}
|
||||
|
||||
impl DynamicEthercatDevice for Wago750_1506 {}
|
||||
|
||||
impl EthercatDynamicPDO for Wago750_1506 {
|
||||
fn get_tx_offset(&self) -> usize {
|
||||
self.tx_bit_offset
|
||||
}
|
||||
|
||||
fn get_rx_offset(&self) -> usize {
|
||||
self.rx_bit_offset
|
||||
}
|
||||
|
||||
fn set_tx_offset(&mut self, offset: usize) {
|
||||
self.tx_bit_offset = offset
|
||||
}
|
||||
|
||||
fn set_rx_offset(&mut self, offset: usize) {
|
||||
self.rx_bit_offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceUsed for Wago750_1506 {
|
||||
fn is_used(&self) -> bool {
|
||||
self.is_used
|
||||
}
|
||||
|
||||
fn set_used(&mut self, used: bool) {
|
||||
self.is_used = used;
|
||||
}
|
||||
}
|
||||
|
||||
impl Wago750_1506 {}
|
||||
|
||||
impl EthercatDevice for Wago750_1506 {
|
||||
// input_len 48 offset: 40
|
||||
fn input(
|
||||
&mut self,
|
||||
input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let base = self.tx_bit_offset;
|
||||
|
||||
let idx1 = base + Into::<usize>::into(Wago750_1506InputPort::DO1);
|
||||
self.tx_pdo.port1 = *input.get(idx1).expect("Bit 1 out of bounds");
|
||||
|
||||
let idx2 = base + Into::<usize>::into(Wago750_1506InputPort::DO2);
|
||||
self.tx_pdo.port2 = *input.get(idx2).expect("Bit 2 out of bounds");
|
||||
|
||||
let idx3 = base + Into::<usize>::into(Wago750_1506InputPort::DO3);
|
||||
self.tx_pdo.port3 = *input.get(idx3).expect("Bit 3 out of bounds");
|
||||
|
||||
let idx4 = base + Into::<usize>::into(Wago750_1506InputPort::DO4);
|
||||
self.tx_pdo.port4 = *input.get(idx4).expect("Bit 4 out of bounds");
|
||||
|
||||
let idx5 = base + Into::<usize>::into(Wago750_1506InputPort::DO5);
|
||||
self.tx_pdo.port5 = *input.get(idx5).expect("Bit 5 out of bounds");
|
||||
|
||||
let idx6 = base + Into::<usize>::into(Wago750_1506InputPort::DO6);
|
||||
self.tx_pdo.port6 = *input.get(idx6).expect("Bit 6 out of bounds");
|
||||
|
||||
let idx7 = base + Into::<usize>::into(Wago750_1506InputPort::DO7);
|
||||
self.tx_pdo.port7 = *input.get(idx7).expect("Bit 7 out of bounds");
|
||||
|
||||
let idx8 = base + Into::<usize>::into(Wago750_1506InputPort::DO8);
|
||||
self.tx_pdo.port8 = *input.get(idx8).expect("Bit 8 out of bounds");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn input_len(&self) -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
// println!("output: {} {}",self.rx_bit_offset,_output);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO1),
|
||||
self.rx_pdo.port1,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO2),
|
||||
self.rx_pdo.port2,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO3),
|
||||
self.rx_pdo.port3,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO4),
|
||||
self.rx_pdo.port4,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO5),
|
||||
self.rx_pdo.port5,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO6),
|
||||
self.rx_pdo.port6,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO7),
|
||||
self.rx_pdo.port7,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_1506OutputPort::DO8),
|
||||
self.rx_pdo.port8,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_len(&self) -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn is_module(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn input_checked(
|
||||
&mut self,
|
||||
_input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_checked(
|
||||
&self,
|
||||
_output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_module(&self) -> Option<Module> {
|
||||
self.module.clone()
|
||||
}
|
||||
|
||||
fn set_module(&mut self, module: Module) {
|
||||
self.tx_bit_offset = module.tx_offset;
|
||||
self.rx_bit_offset = module.rx_offset;
|
||||
self.module = Some(module);
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceProcessing for Wago750_1506 {
|
||||
fn input_post_process(&mut self) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_pre_process(&mut self) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl NewEthercatDevice for Wago750_1506 {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
is_used: false,
|
||||
tx_bit_offset: 0,
|
||||
rx_bit_offset: 0,
|
||||
module: None,
|
||||
rx_pdo: Wago750_1506RxPdo::default(),
|
||||
tx_pdo: Wago750_1506TxPdo::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Wago750_1506 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Wago750_1506")
|
||||
}
|
||||
}
|
||||
|
||||
pub const WAGO_750_1506_VENDOR_ID: u32 = 0x00000021;
|
||||
pub const WAGO_750_1506_PRODUCT_ID: u32 = 2147483779;
|
||||
pub const WAGO_750_1506_MODULE_IDENT: SubDeviceProductTuple =
|
||||
(WAGO_750_1506_VENDOR_ID, WAGO_750_1506_PRODUCT_ID);
|
||||
@@ -0,0 +1,188 @@
|
||||
use crate::devices::{
|
||||
DynamicEthercatDevice, EthercatDevice, EthercatDeviceUsed, EthercatDynamicPDO, Module,
|
||||
SubDeviceProductTuple,
|
||||
};
|
||||
use crate::devices::{EthercatDeviceProcessing, NewEthercatDevice};
|
||||
use crate::io::digital_output::{DigitalOutputDevice, DigitalOutputOutput};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Wago750_501 {
|
||||
is_used: bool,
|
||||
tx_bit_offset: usize,
|
||||
rx_bit_offset: usize,
|
||||
pub rxpdo: Wago750_501RxPdo,
|
||||
module: Option<Module>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Wago750_501Port {
|
||||
Port1,
|
||||
Port2,
|
||||
}
|
||||
|
||||
impl From<Wago750_501Port> for usize {
|
||||
fn from(value: Wago750_501Port) -> Self {
|
||||
match value {
|
||||
Wago750_501Port::Port1 => 0,
|
||||
Wago750_501Port::Port2 => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Wago750_501RxPdo {
|
||||
pub port1: bool,
|
||||
pub port2: bool,
|
||||
}
|
||||
|
||||
impl DigitalOutputDevice<Wago750_501Port> for Wago750_501 {
|
||||
/// Writes the new output value into the device's RXPDO structure (in-memory PDI).
|
||||
fn set_output(&mut self, port: Wago750_501Port, value: DigitalOutputOutput) {
|
||||
// The DigitalOutputOutput is converted to a bool using the From trait
|
||||
let output_value: bool = value.into();
|
||||
match port {
|
||||
Wago750_501Port::Port1 => {
|
||||
// Modify the internal PDO representation
|
||||
self.rxpdo.port1 = output_value;
|
||||
}
|
||||
Wago750_501Port::Port2 => {
|
||||
// Modify the internal PDO representation
|
||||
self.rxpdo.port2 = output_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the current output value from the device's RXPDO structure (in-memory PDI).
|
||||
fn get_output(&self, port: Wago750_501Port) -> DigitalOutputOutput {
|
||||
let current_value = match port {
|
||||
Wago750_501Port::Port1 => self.rxpdo.port1,
|
||||
Wago750_501Port::Port2 => self.rxpdo.port2,
|
||||
};
|
||||
|
||||
// Wrap the bool back into the type-safe wrapper
|
||||
DigitalOutputOutput(current_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceUsed for Wago750_501 {
|
||||
fn is_used(&self) -> bool {
|
||||
self.is_used
|
||||
}
|
||||
|
||||
fn set_used(&mut self, used: bool) {
|
||||
self.is_used = used;
|
||||
}
|
||||
}
|
||||
|
||||
impl DynamicEthercatDevice for Wago750_501 {}
|
||||
|
||||
impl EthercatDynamicPDO for Wago750_501 {
|
||||
fn get_tx_offset(&self) -> usize {
|
||||
self.tx_bit_offset
|
||||
}
|
||||
|
||||
fn get_rx_offset(&self) -> usize {
|
||||
self.rx_bit_offset
|
||||
}
|
||||
|
||||
fn set_tx_offset(&mut self, offset: usize) {
|
||||
self.tx_bit_offset = offset
|
||||
}
|
||||
|
||||
fn set_rx_offset(&mut self, offset: usize) {
|
||||
self.rx_bit_offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDevice for Wago750_501 {
|
||||
fn input(
|
||||
&mut self,
|
||||
_input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn input_len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_501Port::Port1),
|
||||
self.rxpdo.port1,
|
||||
);
|
||||
output.set(
|
||||
self.rx_bit_offset + Into::<usize>::into(Wago750_501Port::Port2),
|
||||
self.rxpdo.port2,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_len(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn is_module(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn input_checked(
|
||||
&mut self,
|
||||
_input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_checked(
|
||||
&self,
|
||||
_output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_module(&self) -> Option<crate::devices::Module> {
|
||||
self.module.clone()
|
||||
}
|
||||
|
||||
fn set_module(&mut self, module: crate::devices::Module) {
|
||||
self.tx_bit_offset = module.tx_offset;
|
||||
self.rx_bit_offset = module.rx_offset;
|
||||
self.module = Some(module)
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceProcessing for Wago750_501 {}
|
||||
|
||||
impl NewEthercatDevice for Wago750_501 {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
is_used: false,
|
||||
tx_bit_offset: 0,
|
||||
rx_bit_offset: 0,
|
||||
module: None,
|
||||
rxpdo: Wago750_501RxPdo::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Wago750_501 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Wago750_501")
|
||||
}
|
||||
}
|
||||
|
||||
pub const WAGO_750_501_VENDOR_ID: u32 = 0x00000021;
|
||||
pub const WAGO_750_501_PRODUCT_ID: u32 = 2147483682;
|
||||
pub const WAGO_750_501_MODULE_IDENT: SubDeviceProductTuple =
|
||||
(WAGO_750_501_VENDOR_ID, WAGO_750_501_PRODUCT_ID);
|
||||
@@ -0,0 +1,159 @@
|
||||
use crate::devices::{
|
||||
DynamicEthercatDevice, EthercatDevice, EthercatDeviceUsed, EthercatDynamicPDO, Module,
|
||||
SubDeviceProductTuple,
|
||||
};
|
||||
use crate::devices::{EthercatDeviceProcessing, NewEthercatDevice};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Wago750_652 {
|
||||
is_used: bool,
|
||||
tx_bit_offset: usize,
|
||||
rx_bit_offset: usize,
|
||||
module: Option<Module>,
|
||||
}
|
||||
|
||||
impl EthercatDeviceUsed for Wago750_652 {
|
||||
fn is_used(&self) -> bool {
|
||||
self.is_used
|
||||
}
|
||||
|
||||
fn set_used(&mut self, used: bool) {
|
||||
self.is_used = used;
|
||||
}
|
||||
}
|
||||
|
||||
impl DynamicEthercatDevice for Wago750_652 {}
|
||||
|
||||
impl EthercatDynamicPDO for Wago750_652 {
|
||||
fn get_tx_offset(&self) -> usize {
|
||||
self.tx_bit_offset
|
||||
}
|
||||
|
||||
fn get_rx_offset(&self) -> usize {
|
||||
self.rx_bit_offset
|
||||
}
|
||||
|
||||
fn set_tx_offset(&mut self, offset: usize) {
|
||||
self.tx_bit_offset = offset
|
||||
}
|
||||
|
||||
fn set_rx_offset(&mut self, offset: usize) {
|
||||
self.rx_bit_offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDevice for Wago750_652 {
|
||||
/*
|
||||
OK so with ethercrab we receive the bitslice of the current subdevice in our Loop
|
||||
*/
|
||||
fn input(
|
||||
&mut self,
|
||||
_input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn input_len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
_output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn is_module(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn input_checked(
|
||||
&mut self,
|
||||
input: &bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
// validate input has correct length
|
||||
let expected = self.input_len();
|
||||
let actual = input.len();
|
||||
if actual != expected {
|
||||
return Err(anyhow::anyhow!(
|
||||
"[{}::Device::input_checked] Input length is {} ({} bytes) and must be {} bits ({} bytes)",
|
||||
module_path!(),
|
||||
actual,
|
||||
actual / 8,
|
||||
expected,
|
||||
expected / 8
|
||||
));
|
||||
}
|
||||
self.input(input)
|
||||
}
|
||||
|
||||
fn output_checked(
|
||||
&self,
|
||||
output: &mut bitvec::prelude::BitSlice<u8, bitvec::prelude::Lsb0>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
self.output(output)?;
|
||||
|
||||
// validate input has correct length
|
||||
let expected = self.output_len();
|
||||
let actual = output.len();
|
||||
if output.len() != expected {
|
||||
return Err(anyhow::anyhow!(
|
||||
"[{}::Device::output_checked] Output length is {} ({} bytes) and must be {} bits ({} bytes)",
|
||||
module_path!(),
|
||||
actual,
|
||||
actual / 8,
|
||||
expected,
|
||||
expected / 8
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_module(&self) -> Option<Module> {
|
||||
self.module.clone()
|
||||
}
|
||||
|
||||
fn set_module(&mut self, module: Module) {
|
||||
self.tx_bit_offset = module.tx_offset;
|
||||
self.rx_bit_offset = module.rx_offset;
|
||||
self.module = Some(module);
|
||||
}
|
||||
}
|
||||
|
||||
impl EthercatDeviceProcessing for Wago750_652 {}
|
||||
|
||||
impl NewEthercatDevice for Wago750_652 {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
is_used: false,
|
||||
tx_bit_offset: 0,
|
||||
rx_bit_offset: 0,
|
||||
module: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Wago750_652 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Wago750_652")
|
||||
}
|
||||
}
|
||||
|
||||
pub const WAGO_750_652_VENDOR_ID: u32 = 0x00000021;
|
||||
pub const WAGO_750_652_PRODUCT_ID: u32 = 106043250;
|
||||
pub const WAGO_750_652_MODULE_IDENT: SubDeviceProductTuple =
|
||||
(WAGO_750_652_VENDOR_ID, WAGO_750_652_PRODUCT_ID);
|
||||
@@ -59,14 +59,12 @@ use super::{
|
||||
impl MachineNewTrait for ExtruderV2 {
|
||||
fn new<'maindevice>(params: &MachineNewParams) -> Result<Self, Error> {
|
||||
// validate general stuff
|
||||
|
||||
use crate::{
|
||||
MachineNewHardware, MachineNewHardwareEthercat, validate_no_role_dublicates,
|
||||
validate_same_machine_identification_unique,
|
||||
};
|
||||
|
||||
let device_identification = params.device_group.to_vec();
|
||||
|
||||
validate_same_machine_identification_unique(&device_identification)?;
|
||||
validate_no_role_dublicates(&device_identification)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use ethercat_hal::devices::wago_750_354::WAGO_750_354_IDENTITY_A;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -345,6 +346,7 @@ pub fn get_identification_addresses(
|
||||
let identity_tuple = subdevice_identity_to_tuple(subdevice_identity);
|
||||
|
||||
Ok(match identity_tuple {
|
||||
WAGO_750_354_IDENTITY_A => MachineIdentificationAddresses::default(),
|
||||
EK1100_IDENTITY_A => MachineIdentificationAddresses::default(),
|
||||
EL1002_IDENTITY_A => MachineIdentificationAddresses::default(),
|
||||
EL1008_IDENTITY_A => MachineIdentificationAddresses::default(),
|
||||
|
||||
@@ -71,7 +71,7 @@ impl MachineApi for TestMachine {
|
||||
Mutation::SetAllLeds { on } => self.set_all_leds(on),
|
||||
}
|
||||
|
||||
for (led, &on) in self.leds.iter().zip(self.led_on.iter()) {
|
||||
for (led, &on) in self.douts.iter().zip(self.led_on.iter()) {
|
||||
led.set(on);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::machine_identification::{MachineIdentification, MachineIdentification
|
||||
use crate::test_machine::api::{StateEvent, TestMachineEvents};
|
||||
use crate::{AsyncThreadMessage, Machine, MachineMessage};
|
||||
use control_core::socketio::namespace::NamespaceCacheingLogic;
|
||||
use ethercat_hal::io::digital_output::DigitalOutput;
|
||||
use smol::channel::{Receiver, Sender};
|
||||
use std::time::Instant;
|
||||
pub mod act;
|
||||
@@ -9,7 +10,6 @@ pub mod api;
|
||||
pub mod new;
|
||||
use crate::test_machine::api::TestMachineNamespace;
|
||||
use crate::{TEST_MACHINE, VENDOR_QITECH};
|
||||
use ethercat_hal::io::digital_output::DigitalOutput;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TestMachine {
|
||||
@@ -20,7 +20,7 @@ pub struct TestMachine {
|
||||
pub last_state_emit: Instant,
|
||||
pub led_on: [bool; 4],
|
||||
pub main_sender: Option<Sender<AsyncThreadMessage>>,
|
||||
pub leds: [DigitalOutput; 4],
|
||||
pub douts: [DigitalOutput; 4],
|
||||
}
|
||||
|
||||
impl Machine for TestMachine {
|
||||
|
||||
@@ -7,10 +7,19 @@ use crate::{
|
||||
MachineNewHardware, MachineNewParams, MachineNewTrait, get_ethercat_device,
|
||||
validate_no_role_dublicates, validate_same_machine_identification_unique,
|
||||
};
|
||||
|
||||
use anyhow::Error;
|
||||
use ethercat_hal::devices::el2004::{EL2004, EL2004_IDENTITY_A, EL2004Port};
|
||||
use ethercat_hal::io::digital_output::DigitalOutput;
|
||||
|
||||
//Imports For Wago
|
||||
/*
|
||||
use ethercat_hal::devices::wago_750_354::{WAGO_750_354_IDENTITY_A, Wago750_354};
|
||||
use ethercat_hal::devices::{EthercatDevice, downcast_device};
|
||||
use smol::lock::RwLock;
|
||||
use std::sync::Arc;
|
||||
*/
|
||||
|
||||
impl MachineNewTrait for TestMachine {
|
||||
fn new<'maindevice>(params: &MachineNewParams) -> Result<Self, Error> {
|
||||
// validate general stuff
|
||||
@@ -32,6 +41,35 @@ impl MachineNewTrait for TestMachine {
|
||||
}
|
||||
};
|
||||
block_on(async {
|
||||
/*
|
||||
// Example usage of a Wago Coupler and a 750-1506 in the first slot, where the Output Port 1,2,3,4 is used
|
||||
let _wago_750_354 = get_ethercat_device::<Wago750_354>(
|
||||
hardware,
|
||||
params,
|
||||
0,
|
||||
[WAGO_750_354_IDENTITY_A].to_vec(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let modules = Wago750_354::initialize_modules(_wago_750_354.1).await?;
|
||||
|
||||
let mut coupler = _wago_750_354.0.write().await;
|
||||
|
||||
for module in modules {
|
||||
coupler.set_module(module);
|
||||
}
|
||||
|
||||
coupler.init_slot_modules(_wago_750_354.1);
|
||||
let dev = coupler.slot_devices.get(1).unwrap().clone().unwrap();
|
||||
let wago750_1506: Arc<RwLock<Wago750_1506>> =
|
||||
downcast_device::<Wago750_1506>(dev).await?;
|
||||
let do1 = DigitalOutput::new(wago750_1506.clone(), Wago750_1506OutputPort::DO1);
|
||||
let do2 = DigitalOutput::new(wago750_1506.clone(), Wago750_1506OutputPort::DO2);
|
||||
let do3 = DigitalOutput::new(wago750_1506.clone(), Wago750_1506OutputPort::DO3);
|
||||
let do4 = DigitalOutput::new(wago750_1506.clone(), Wago750_1506OutputPort::DO4);
|
||||
drop(coupler);
|
||||
*/
|
||||
|
||||
let el2004 =
|
||||
get_ethercat_device::<EL2004>(hardware, params, 1, [EL2004_IDENTITY_A].to_vec())
|
||||
.await?
|
||||
@@ -40,6 +78,7 @@ impl MachineNewTrait for TestMachine {
|
||||
let do2 = DigitalOutput::new(el2004.clone(), EL2004Port::DO2);
|
||||
let do3 = DigitalOutput::new(el2004.clone(), EL2004Port::DO3);
|
||||
let do4 = DigitalOutput::new(el2004.clone(), EL2004Port::DO4);
|
||||
|
||||
let (sender, receiver) = smol::channel::unbounded();
|
||||
let mut my_test = Self {
|
||||
api_receiver: receiver,
|
||||
@@ -51,7 +90,7 @@ impl MachineNewTrait for TestMachine {
|
||||
last_state_emit: Instant::now(),
|
||||
led_on: [false; 4],
|
||||
main_sender: params.main_thread_channel.clone(),
|
||||
leds: [do1, do2, do3, do4],
|
||||
douts: [do1, do2, do3, do4],
|
||||
};
|
||||
my_test.emit_state();
|
||||
Ok(my_test)
|
||||
|
||||
@@ -12,6 +12,10 @@ use control_core::socketio::namespace::NamespaceCacheingLogic;
|
||||
use control_core::{irq_handling::set_irq_affinity, realtime::set_realtime_priority};
|
||||
use ethercat_hal::debugging::diagnosis_history::get_most_recent_diagnosis_message;
|
||||
use ethercat_hal::devices::devices_from_subdevices;
|
||||
use ethercat_hal::devices::wago_750_354::{
|
||||
WAGO_750_354_PRODUCT_ID, WAGO_750_354_VENDOR_ID, Wago750_354,
|
||||
};
|
||||
|
||||
use ethercrab::std::ethercat_now;
|
||||
use ethercrab::{MainDevice, MainDeviceConfig, PduStorage, RetryBehaviour, Timeouts};
|
||||
use machines::machine_identification::{
|
||||
@@ -110,10 +114,6 @@ pub async fn set_ethercat_devices<const MAX_SUBDEVICES: usize, const MAX_PDI: us
|
||||
socket_queue_tx: Sender<(SocketRef, Arc<control_core::socketio::event::GenericEvent>)>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let device_grouping_result = group_devices_by_identification(device_identifications);
|
||||
tracing::info!(
|
||||
"set_ethercat_devices: {:?}",
|
||||
device_grouping_result.unidentified_devices
|
||||
);
|
||||
let machine_new_hardware = MachineNewHardware::Ethercat(hardware);
|
||||
|
||||
let mut machines: Vec<Box<dyn Machine>> = vec![];
|
||||
@@ -300,7 +300,7 @@ pub async fn setup_loop(
|
||||
|
||||
// filter devices and if Option<DeviceMachineIdentification> is Some
|
||||
// return identified_devices, identified_device_identifications, identified_subdevices
|
||||
let (identified_device_identifications, identified_devices, identified_subdevices): (
|
||||
let (identified_device_identifications,identified_devices, identified_subdevices): (
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
@@ -328,32 +328,57 @@ pub async fn setup_loop(
|
||||
acc.0.push(identified_device_identification.clone());
|
||||
acc.1.push(identified_device);
|
||||
acc.2.push(identified_subdevice);
|
||||
ethercat_meta_devices.push(EtherCatDeviceMetaData::from_subdevice(identified_subdevice,identified_device_identification));
|
||||
|
||||
let meta = EtherCatDeviceMetaData::from_subdevice(identified_subdevice,identified_device_identification);
|
||||
ethercat_meta_devices.push(meta);
|
||||
acc
|
||||
},
|
||||
);
|
||||
tracing::info!("Found Devices: {:?}", ethercat_meta_devices);
|
||||
drop(ethercat_meta_devices);
|
||||
|
||||
// We always need to have atleast one subdevice anyways
|
||||
let coupler = subdevices.get(0).unwrap();
|
||||
let _resp = get_most_recent_diagnosis_message(coupler).await;
|
||||
|
||||
|
||||
/*
|
||||
handle special edge cases,
|
||||
Wago couplers handle all subdevices as part of the coupler instead of their own devices,
|
||||
meaning we need to convert the PDO Mappings to seperate SubDevices to enable more ease of use
|
||||
OR alternatively you could show it like TwinCAT with "slots" on the Coupler
|
||||
*/
|
||||
match (coupler.identity().vendor_id,coupler.identity().product_id) {
|
||||
(WAGO_750_354_VENDOR_ID,WAGO_750_354_PRODUCT_ID) => {
|
||||
match (coupler.identity().vendor_id, coupler.identity().product_id) {
|
||||
(WAGO_750_354_VENDOR_ID, WAGO_750_354_PRODUCT_ID) => {
|
||||
let r = Wago750_354::initialize_modules(coupler).await?;
|
||||
println!("{:?}",r);
|
||||
},
|
||||
for module in r {
|
||||
if coupler.configured_address() == module.belongs_to_addr {
|
||||
match ethercat_meta_devices.get(0) {
|
||||
Some(meta) => {
|
||||
let meta_data = EtherCatDeviceMetaData {
|
||||
configured_address: module.slot,
|
||||
name: "wago module".to_owned(),
|
||||
vendor_id:module.vendor_id,
|
||||
product_id: module.product_id,
|
||||
revision: 0x2,
|
||||
device_identification: DeviceIdentification{
|
||||
device_machine_identification: meta.device_identification.device_machine_identification.clone(),
|
||||
device_hardware_identification: machines::machine_identification::DeviceHardwareIdentification::Ethercat(DeviceHardwareIdentificationEthercat{ subdevice_index: module.slot as usize }) }
|
||||
};
|
||||
ethercat_meta_devices.push(meta_data);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
drop(ethercat_meta_devices);
|
||||
|
||||
for subdevice in subdevices.iter() {
|
||||
// Hack so El5152 goes into OP
|
||||
if subdevice.name() == "EL5152" {
|
||||
subdevice.sdo_write(SM_INPUT, 0x1, 0x00u16).await?; //set sync mode (1) for free run (0)
|
||||
subdevice.sdo_write(SM_OUTPUT, 0x1, 0x00u16).await?; //set sync mode (1) for free run (0)
|
||||
}
|
||||
}
|
||||
|
||||
// remove subdevice from devices tuple
|
||||
let devices = devices
|
||||
@@ -388,11 +413,16 @@ pub async fn setup_loop(
|
||||
|
||||
/*
|
||||
Make DC Slaves Happy
|
||||
Does this potentially cause issues with Non DC-Sync devices?
|
||||
*/
|
||||
let res = group_safe.tx_rx_sync_system_time(&maindevice).await;
|
||||
match res {
|
||||
Ok(_) => (),
|
||||
Err(e) => tracing::error!("[{}::setup_loop] Failed to sync dc time: {:?}",e, module_path!()),
|
||||
Err(e) => tracing::error!(
|
||||
"[{}::setup_loop] Failed to sync dc time: {:?}",
|
||||
e,
|
||||
module_path!()
|
||||
),
|
||||
}
|
||||
|
||||
// Put group in operational state
|
||||
@@ -421,7 +451,6 @@ pub async fn setup_loop(
|
||||
.await;
|
||||
main_namespace.emit(MainNamespaceEvents::EthercatDevicesEvent(event));
|
||||
}
|
||||
tracing::info!("DONE WITH INIT");
|
||||
|
||||
return Ok(EthercatSetup {
|
||||
devices,
|
||||
|
||||
@@ -68,6 +68,7 @@ pub fn start_loop_thread(
|
||||
match msg {
|
||||
HotThreadMessage::NoMsg => {}
|
||||
HotThreadMessage::AddEtherCatSetup(ethercat_setup) => {
|
||||
println!("EthercatSetup: {:?}", ethercat_setup.devices);
|
||||
rt_loop_inputs.ethercat_setup = Some(Box::new(ethercat_setup));
|
||||
}
|
||||
HotThreadMessage::WriteMachineDeviceInfo(info_request) => {
|
||||
|
||||
Reference in new issue
Block a user