use crate::{
socket::EthercatSocket,
rawmaster::{RawMaster, SlaveAddress, PduAnswer},
data::{PduData, Field},
slave::{Slave, CommunicationState},
mapping::{Allocator, Mapping, Group},
clock::DistributedClock,
registers, EthercatError,
error::EthercatResult,
registers::AlError,
};
use std::{
collections::HashSet,
sync::Arc,
};
use core::{
ops::Range,
default::Default,
};
use futures_concurrency::future::Join;
use tokio::sync::RwLockReadGuard;
pub type MixedState = registers::AlMixedState;
pub struct Master {
pub(crate) raw: Arc<RawMaster>,
pub(crate) slaves: std::sync::Mutex<HashSet<SlaveAddress>>,
allocator: Allocator,
clock: tokio::sync::RwLock<Option<DistributedClock>>,
}
impl Master {
pub fn new<S: EthercatSocket + 'static + Send + Sync>(socket: S) -> Self {
Self {
raw: RawMaster::new(socket),
slaves: HashSet::new().into(),
allocator: Allocator::new(),
clock: None.into(),
}
}
pub unsafe fn raw(raw: Arc<RawMaster>) -> Self {
Self {
raw,
slaves: HashSet::new().into(),
allocator: Allocator::new(),
clock: None.into(),
}
}
pub unsafe fn get_raw(&self) -> &Arc<RawMaster> {&self.raw}
pub fn into_raw(self) -> Arc<RawMaster> {self.raw}
pub fn flush(&self) {self.raw.flush()}
pub async fn discover(&self) -> SlaveDiscovery<'_> {
SlaveDiscovery::new(self, self.slaves().await)
}
pub fn allocator(&self) -> &'_ Allocator {
&self.allocator
}
pub async fn group<'a>(&'a self, mapping: &Mapping<'_>) -> Group<'a> {
self.allocator.group(&self.raw, mapping).await
}
pub async fn reset_addresses(&self) {
assert_eq!(self.slaves.lock().unwrap().len(), 0);
assert!(self.clock.read().await.is_none());
(
self.raw.bwr(registers::address::fixed, 0),
self.raw.bwr(registers::address::alias, 0),
).join().await;
}
pub async fn reset_logical(&self) {
assert_eq!(self.slaves.lock().unwrap().len(), 0);
self.raw.bwr(Field::<[u8; 256]>::simple(usize::from(registers::fmmu.address)), [0; 256]).await;
self.raw.bwr(Field::<[u8; 128]>::simple(usize::from(registers::sync_manager::interface.address)), [0; 128]).await;
}
pub async fn reset_mailboxes(&self) {
assert_eq!(self.slaves.lock().unwrap().len(), 0);
self.raw.bwr(Field::<[u8; 256]>::simple(usize::from(registers::sync_manager::interface.address)), [0; 256]).await;
}
pub async fn reset_clock(&self) {
self.clock.write().await.take();
(
self.raw.bwr(registers::dc::all, Default::default()),
self.raw.bwr(registers::isochronous::all, Default::default()),
).join().await;
}
pub async fn init_clock(&self) -> Result<(), EthercatError> {
self.reset_clock().await;
self.clock.write().await.replace(
DistributedClock::new(self.raw.clone(), None, None).await?
);
Ok(())
}
pub async fn clock(&self) -> RwLockReadGuard<'_, DistributedClock> {
RwLockReadGuard::map(
self.clock.read().await,
|o| o.as_ref().expect("clock not initialized"),
)
}
pub async fn slaves(&self) -> u16 {
self.raw.brd(registers::al::status).await.answers
}
pub async fn states(&self) -> MixedState {
self.raw.brd(registers::al::status).await.value().unwrap().state()
}
pub async fn switch(&self, target: CommunicationState) -> EthercatResult<(), AlError> {
self.raw.bwr(registers::al::control, {
let mut config = registers::AlControlRequest::default();
config.set_state(target.into());
config.set_ack(true);
config.set_request_id(true);
config
}).await;
loop {
let status = self.raw.brd(registers::al::response).await;
if status.value().unwrap().error() {
for slave in 0 .. status.answers {
let error = self.raw.aprd(slave, registers::al::error).await.one()?;
if error != AlError::NoError
{return Err(EthercatError::Slave(SlaveAddress::AutoIncremented(slave), error))}
}
}
if status.value().unwrap().state() == target.into()
{break}
}
Ok(())
}
pub async fn broadcast_read<T: PduData>(&self, field: Field<T>) -> PduAnswer<T> {self.raw.brd(field).await}
pub async fn logical_read<T: PduData>(&self, field: Field<T>) -> PduAnswer<T> {self.raw.lrd(field).await}
pub async fn logical_write<T: PduData>(&self, field: Field<T>, value: T) -> PduAnswer<()> {self.raw.lwr(field, value).await}
pub async fn logical_exchange<T: PduData>(&self, field: Field<T>, value: T) -> PduAnswer<T> {self.raw.lrw(field, value).await}
}
pub struct SlaveDiscovery<'a> {
master: &'a Master,
iter: Range<u16>,
}
impl<'a> SlaveDiscovery<'a> {
fn new(master: &'a Master, max: u16) -> Self {
Self {
master,
iter: 0 .. max,
}
}
pub async fn next(&mut self) -> Option<Slave<'a>> {
while let Some(address) = self.iter.next() {
if let Ok(slave) = Slave::new(&self.master, SlaveAddress::AutoIncremented(address)).await
{return Some(slave)}
}
None
}
}