1
2use crate::{
3 master::Master,
4 rawmaster::{RawMaster, SlaveAddress},
5 data::{PduData, Field},
6 sii::{Sii, SiiError},
7 mailbox::Mailbox,
8 can::Can,
9 registers::{self, AlError},
10 eeprom,
11 error::{EthercatError, EthercatResult},
12 };
13use tokio::sync::{Mutex, MutexGuard};
14use std::sync::Arc;
15use core::time::Duration;
16
17
18
19pub type CommunicationState = registers::AlState;
20use registers::AlState::*;
21
22
23
24pub struct Slave<'a> {
59 master: Arc<RawMaster>,
60 address: SlaveAddress,
62 state: CommunicationState,
64 safemaster: Option<&'a Master>,
66
67 sii: Option<Mutex<Sii>>,
69 mailbox: Option<Arc<Mutex<Mailbox>>>,
70 coe: Option<Arc<Mutex<Can>>>,
71}
72impl<'a> Slave<'a> {
73 pub fn raw(master: Arc<RawMaster>, address: SlaveAddress) -> Self {
78 Self {
79 master,
80 safemaster: None,
81 address,
82 state: Init,
83
84 sii: None,
85 mailbox: None,
86 coe: None,
87 }
88 }
89 pub async fn new(master: &'a Master, address: SlaveAddress) -> EthercatResult<Slave<'a>> {
93 let fixed = SlaveAddress::Fixed(master.raw.read(address, registers::address::fixed).await.one()?);
94 let mut book = master.slaves.lock().unwrap();
95
96 if book.contains(&address)
97 || book.contains(&fixed)
98 {Err(EthercatError::Master("slave already in use by an other instance"))}
99 else {
100 book.insert(address);
101 drop(book);
102 Ok(Self {
103 master: master.raw.clone(),
104 safemaster: Some(master),
105 address,
106 state: Init,
107
108 sii: None,
109 mailbox: None,
110 coe: None,
111 })
112 }
113 }
114
115 pub unsafe fn raw_master(&self) -> &Arc<RawMaster> {&self.master}
117
118 pub fn informations(&self) {todo!()}
120
121 pub async fn state(&self) -> EthercatResult<CommunicationState> {
123 self.master.read(self.address, registers::al::status).await.one()?
124 .state().try_into()
125 .map_err(|_| EthercatError::Protocol("undefined slave state"))
126 }
127 pub async fn switch(&mut self, target: CommunicationState) -> EthercatResult<(), AlError> {
129 self.master.write(self.address, registers::al::control, {
131 let mut config = registers::AlControlRequest::default();
132 config.set_state(target.into());
133 config.set_ack(true);
134 config.set_request_id(true);
135 config
136 }).await.one()?;
137
138 loop {
140 let status = self.master.read(self.address, registers::al::response).await.one()?;
141 if status.error() {
142let error = self.master.read(self.address, registers::al::error).await.one()?;
144 if error != registers::AlError::NoError
145 {return Err(EthercatError::Slave(self.address, error))}
146}
150 if status.state() == target.into() {break}
151 }
152 self.state = target;
153 Ok(())
154 }
155 pub fn expect(&mut self, state: CommunicationState) {
161 self.state = state;
162 }
163 pub fn expected(&self) -> CommunicationState {
165 self.state
166 }
167
168 pub fn address(&self) -> SlaveAddress {self.address}
170 pub async fn set_address(&mut self, fixed: u16) -> EthercatResult {
172 assert!(fixed != 0);
173 self.master.write(self.address, registers::address::fixed, fixed).await.one()?;
174 let new = SlaveAddress::Fixed(fixed);
175 if let Some(safe) = self.safemaster {
177 let mut book = safe.slaves.lock().unwrap();
178 book.remove(&self.address);
179 book.insert(new);
180 }
181 self.address = new;
182 Ok(())
183 }
184 pub async fn reset_address(self) -> EthercatResult {
186 self.master.write(self.address, registers::address::fixed, 0).await.one()?;
187 Ok(())
188 }
189
190 pub async fn init_sii(&mut self) -> EthercatResult<(), SiiError> {
192 let sii = Sii::new(self.master.clone(), self.address).await?;
193 self.sii = Some(Mutex::new(sii));
194 Ok(())
195 }
196
197 pub async fn init_mailbox(&mut self) -> EthercatResult<(), SiiError> {
199 assert_eq!(self.state, Init);
200
201 let address = match self.address {
202 SlaveAddress::Fixed(i) => i,
203 _ => panic!("mailbox is unsafe without fixed addresses"),
204 };
205 if self.sii.is_none() {
207 self.init_sii().await?;
208 }
209 let mut sii = self.sii().await;
210 sii.acquire().await?;
211 let write_offset = sii.read(eeprom::mailbox::standard::write::offset).await?;
212 let write_size = sii.read(eeprom::mailbox::standard::write::size).await?;
213 let read_offset = sii.read(eeprom::mailbox::standard::read::offset).await?;
214 let read_size = sii.read(eeprom::mailbox::standard::read::size).await?;
215 sii.release().await?;
216 drop(sii);
217
218 let mailbox = Mailbox::new(
220 self.master.clone(),
221 address,
222 (registers::sync_manager::interface.mailbox_write(), write_offset .. write_offset + write_size),
223 (registers::sync_manager::interface.mailbox_read(), read_offset .. read_offset + read_size),
224 ).await?;
225
226 self.coe = None;
227 self.mailbox = Some(Arc::new(Mutex::new(mailbox)));
228 Ok(())
229 }
230
231 pub async fn init_coe(&mut self) -> EthercatResult<(), SiiError> {
233 if self.mailbox.is_none() {
234 self.init_mailbox().await?;
235 }
236 let mailbox = self.mailbox.clone().unwrap();
237 self.coe = Some(Arc::new(Mutex::new(Can::new(mailbox))));
238 Ok(())
239 }
240
241 pub async fn init_sync(&mut self, period: Duration, activation: Duration) -> EthercatResult {
251 assert_eq!(self.state, PreOperational);
252 let period = u32::try_from(period.as_nanos()).expect("synchronization period must be below 4seconds");
253 let activation = u32::try_from(activation.as_nanos()).expect("activation delay must be below 4seconds");
254
255 self.master.write(self.address, registers::isochronous::sync::enable, Default::default()).await.one()?;
256 self.master.write(self.address, Field::<u8>::simple(0x980), 0).await.one()?;
257 let start = self.master.read(self.address, registers::dc::system_time).await.one()? as u32;
258 let start = ((start + activation) / period) * period + period;
259 self.master.write(self.address, registers::isochronous::sync::start_time, start).await.one()?;
260 self.master.write(self.address, registers::isochronous::sync::sync0_cycle_time, period).await.one()?;
261 self.master.write(self.address, registers::isochronous::sync::enable, {
262 let mut enables = registers::IsochronousEnables::default();
263 enables.set_operation(true);
264 enables.set_sync0(true);
265 enables
266 }).await.one()?;
267 Ok(())
268 }
269
270 pub async fn sii(&self) -> MutexGuard<'_, Sii> {
272 self.sii
273 .as_ref().expect("sii not initialized")
274 .lock().await
275 }
276
277 pub async fn coe(&self) -> MutexGuard<'_, Can> {
279 self.coe
280 .as_ref().expect("coe not initialized")
281 .lock().await
282 }
283
284pub async fn physical_read<T: PduData>(&self, field: Field<T>) -> EthercatResult<T> {
289 self.master.read(self.address, field).await.one()
290 }
291}
292
293impl Drop for Slave<'_> {
294 fn drop(&mut self) {
295 if let Some(safe) = self.safemaster {
297 let mut book = safe.slaves.lock().unwrap();
298 book.remove(&self.address);
299 }
300 }
301}
302
303
304impl From<EthercatError<()>> for EthercatError<AlError> {
305 fn from(src: EthercatError<()>) -> Self {src.upgrade()}
306}