use std::error::Error; use core::time::Duration; use futures_concurrency::future::Join; use etherage::{ EthernetSocket, Master, Slave, SlaveAddress, CommunicationState, data::Field, sdo::{self, OperationMode}, mapping::{self, Mapping, Group}, registers::{self, SyncDirection}, }; #[tokio::main] async fn main() -> Result<(), Box> { let master = Master::new(EthernetSocket::new("eno1")?); println!("create mapping"); let config = mapping::Config::default(); let mapping = Mapping::new(&config); let mut slave = mapping.slave(1); let _statuscom = slave.register(SyncDirection::Read, registers::al::status); let mut channel = slave.channel(sdo::sync_manager.logical_write(), 0x1800 .. 0x1c00); let mut pdo = channel.push(sdo::Pdo::with_capacity(0x1600, false, 10)); let controlword = pdo.push(sdo::cia402::controlword); let target_mode = pdo.push(sdo::cia402::target::mode); let target_position = pdo.push(sdo::cia402::target::position); let mut channel = slave.channel(sdo::sync_manager.logical_read(), 0x1c00 .. 0x2000); let mut pdo = channel.push(sdo::Pdo::with_capacity(0x1a00, false, 10)); let statusword = pdo.push(sdo::cia402::statusword); let error = pdo.push(sdo::cia402::error); let current_position = pdo.push(sdo::cia402::current::position); drop(slave); println!("done {:#?}", config); let group = master.group(&mapping).await; println!("group {:#?}", group); println!("fields {:#?}", (statusword, controlword)); let mut slave = Slave::new(&master, SlaveAddress::AutoIncremented(0)).await?; slave.switch(CommunicationState::Init).await?; slave.set_address(1).await?; slave.init_coe().await?; slave.switch(CommunicationState::PreOperational).await?; group.configure(&slave).await?; slave.switch(CommunicationState::SafeOperational).await?; slave.switch(CommunicationState::Operational).await?; let cycle = tokio::sync::Notify::new(); ( async { let mut period = tokio::time::interval(Duration::from_millis(1)); loop { group.data().await.exchange().await; cycle.notify_waiters(); period.tick().await; } }, async { let initial = { let mut group = group.data().await; let initial = group.get(current_position); group.set(target_mode, OperationMode::SynchronousPosition); group.set(target_position, initial); println!("error {:x}", group.get(error)); println!("position {}", initial); initial }; use bilge::prelude::u2; println!("power: {:?}", slave.coe().await.sdo_read(&sdo::error, u2::new(0)).await); println!("switch on"); switch_on(statusword, controlword, error, &group, &cycle).await; // coder with 2^23 pulses/rotation // let increment = 3_000_000; // let course = 100_000_000; // coder with 2^16 pulses/rotation let increment = 1_000; let course = 100_000; println!("move forward"); loop { cycle.notified().await; let mut group = group.data().await; let position = group.get(current_position); if position >= initial + course {break} group.set(target_position, position + increment); println!(" {}", position); } println!("move backward"); loop { cycle.notified().await; let mut group = group.data().await; let position = group.get(current_position); if position <= initial {break} group.set(target_position, position - increment); println!(" {}", position); } println!("done"); }, ).join().await; Ok(()) } pub async fn switch_on( statusword: Field, controlword: Field, error: Field, group: &Group<'_>, cycle: &tokio::sync::Notify, ) { loop { { let mut group = group.data().await; let status = group.get(statusword); let mut control = sdo::ControlWord::default(); // state "not ready to switch on" // we are in the state we wanted ! if status.operation_enabled() { return; } // state "fault" else if status.fault() && ! status.switched_on() { // move to "switch on disabled" control.set_reset_fault(true); } else if ! status.quick_stop() { // move to "switch on disabled" control.set_quick_stop(true); control.set_enable_voltage(true); } // state "switch on disabled" else if status.switch_on_disabled() { control.set_quick_stop(true); control.set_enable_voltage(true); control.set_switch_on(false); } // state "ready to switch on" else if ! status.switched_on() && status.ready_switch_on() { // move to "switched on" control.set_quick_stop(true); control.set_enable_voltage(true); control.set_switch_on(true); control.set_enable_operation(false); } // state "ready to switch on" or "switched on" else if ! status.operation_enabled() && (status.ready_switch_on() | status.switched_on()) { // move to "operation enabled" control.set_quick_stop(true); control.set_enable_voltage(true); control.set_switch_on(true); control.set_enable_operation(true); } group.set(controlword, control); println!("switch on {} {} {:#x}", status, control, group.get(error)); } cycle.notified().await; } }