Skip to main content

darra_ethercat/master/
master_od.rs

1
2use crate::utils::ffi;
3use crate::master::core::EtherCATMaster;
4
5use std::sync::atomic::{AtomicU32, Ordering};
6
7static INSTANCE_COUNTER: AtomicU32 = AtomicU32::new(0);
8
9pub const VENDOR_ID: u32 = 0x00001164;
10
11pub const PRODUCT_CODE: u32 = 0x00000001;
12
13pub struct MasterObjectDictionary<'a> {
14    master: &'a EtherCATMaster,
15
16    serial_number: u32,
17}
18
19impl<'a> MasterObjectDictionary<'a> {
20
21    pub(crate) fn new(master: &'a EtherCATMaster) -> Self {
22        let serial_number = INSTANCE_COUNTER.fetch_add(1, Ordering::SeqCst);
23        Self { master, serial_number }
24    }
25
26    pub fn vendor_id(&self) -> u32 {
27        VENDOR_ID
28    }
29
30    pub fn product_code(&self) -> u32 {
31        PRODUCT_CODE
32    }
33
34    pub fn revision_number(&self) -> u32 {
35        match EtherCATMaster::dll_version() {
36            Some((major, minor, _, _)) => ((major as u32) << 16) | (minor as u32),
37            None => 0,
38        }
39    }
40
41    pub fn serial_number(&self) -> u32 {
42        self.serial_number
43    }
44
45    pub fn read_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
46        match index {
47
48            0x1000 => {
49                Some(0x000011A4u32.to_le_bytes().to_vec())
50            }
51
52            0x1008 => {
53                Some(b"Darra EtherCAT Master".to_vec())
54            }
55
56            0x1009 => {
57                Some(b"1.0".to_vec())
58            }
59
60            0x100A => {
61                match EtherCATMaster::dll_version() {
62                    Some((major, minor, patch, build)) => {
63                        let ver = format!("{}.{}.{}.{}", major, minor, patch, build);
64                        Some(ver.into_bytes())
65                    }
66                    None => Some(b"0.0.0.0".to_vec()),
67                }
68            }
69
70            0x1018 => {
71                self.read_identity_object(subindex)
72            }
73
74            0x8000..=0x8FFF => {
75                let slave_idx = index & 0x0FFF;
76                self.read_slave_config_data(slave_idx, subindex)
77            }
78
79            0x9000..=0x9FFF => {
80                let slave_idx = index & 0x0FFF;
81                self.read_slave_info_data(slave_idx, subindex)
82            }
83
84            0xA000..=0xAFFF => {
85                let slave_idx = index & 0x0FFF;
86                self.read_slave_diag_data(slave_idx, subindex)
87            }
88
89            0xF002 => {
90                self.read_detect_modules(subindex)
91            }
92
93            0xF120 => {
94                self.read_master_diag_data(subindex)
95            }
96
97            0xF200 => {
98
99                Some(vec![0u8; 4])
100            }
101            _ => None,
102        }
103    }
104
105    pub fn write_object(&self, index: u16, subindex: u8, data: &[u8]) -> bool {
106        match index {
107
108            0xF002 => {
109
110                subindex == 1 && !data.is_empty()
111            }
112
113            0xF200 => {
114                !data.is_empty()
115            }
116
117            0xA000..=0xAFFF => {
118
119                subindex == 0 && !data.is_empty()
120            }
121
122            _ => false,
123        }
124    }
125
126    pub fn object_name(&self, index: u16) -> &str {
127        match index {
128            0x1000 => "Device Type",
129            0x1008 => "Manufacturer Device Name",
130            0x1009 => "Manufacturer Hardware Version",
131            0x100A => "Manufacturer Software Version",
132            0x1018 => "Identity Object",
133            0x8000..=0x8FFF => "Configuration Data",
134            0x9000..=0x9FFF => "Information Data",
135            0xA000..=0xAFFF => "Diagnosis Data",
136            0xF002 => "Detect Modules Command",
137            0xF120 => "Master Diag Data",
138            0xF200 => "Diag Interface Control",
139            _ => "Unknown",
140        }
141    }
142
143    pub fn subindex_count(&self, index: u16) -> u8 {
144        match index {
145            0x1000 | 0x1008 | 0x1009 | 0x100A => 0,
146            0x1018 => 4,
147            0x8000..=0x8FFF => 40,
148            0x9000..=0x9FFF => 32,
149            0xA000..=0xAFFF => 19,
150            0xF002 => 3,
151            0xF120 | 0xF200 => 16,
152            _ => 0,
153        }
154    }
155
156    pub fn supported_object_indices(&self) -> Vec<u16> {
157        let mut indices = vec![
158            0x1000, 0x1008, 0x1009, 0x100A, 0x1018,
159            0xF002, 0xF120, 0xF200,
160        ];
161
162        let slave_count = self.slave_count();
163        for i in 1..=slave_count {
164            indices.push(0x8000 | i);
165            indices.push(0x9000 | i);
166            indices.push(0xA000 | i);
167        }
168
169        indices
170    }
171
172    fn slave_count(&self) -> u16 {
173
174        unsafe { ffi::GetGroupSlaveCount(self.master.index(), 0) }
175    }
176
177    fn read_identity_object(&self, subindex: u8) -> Option<Vec<u8>> {
178        match subindex {
179
180            0 => Some(vec![4]),
181
182            1 => Some(VENDOR_ID.to_le_bytes().to_vec()),
183
184            2 => Some(PRODUCT_CODE.to_le_bytes().to_vec()),
185
186            3 => Some(self.revision_number().to_le_bytes().to_vec()),
187
188            4 => Some(self.serial_number.to_le_bytes().to_vec()),
189            _ => None,
190        }
191    }
192
193    fn read_slave_config_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
194        if slave_idx == 0 { return None; }
195
196        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);
197
198        match subindex {
199
200            0 => Some(vec![40]),
201
202            1 => {
203                match slave.identity() {
204                    Ok(id) => Some(id.vendor_id.to_le_bytes().to_vec()),
205                    Err(_) => Some(vec![0; 4]),
206                }
207            }
208            2 => {
209                match slave.identity() {
210                    Ok(id) => Some(id.product_code.to_le_bytes().to_vec()),
211                    Err(_) => Some(vec![0; 4]),
212                }
213            }
214            3 => {
215                match slave.identity() {
216                    Ok(id) => Some(id.revision_no.to_le_bytes().to_vec()),
217                    Err(_) => Some(vec![0; 4]),
218                }
219            }
220            4 => {
221                match slave.identity() {
222                    Ok(id) => Some(id.serial_no.to_le_bytes().to_vec()),
223                    Err(_) => Some(vec![0; 4]),
224                }
225            }
226            _ => Some(vec![0; 4]),
227        }
228    }
229
230    fn read_slave_info_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
231        if slave_idx == 0 { return None; }
232
233        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);
234
235        match subindex {
236
237            0 => Some(vec![32]),
238
239            1 => {
240                let state = slave.state().map(|s| s as u8).unwrap_or(0);
241                Some(vec![state])
242            }
243
244            2 => Some(slave.error_code_raw().to_le_bytes().to_vec()),
245            _ => Some(vec![0; 4]),
246        }
247    }
248
249    fn read_slave_diag_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
250        if slave_idx == 0 { return None; }
251
252        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);
253
254        match subindex {
255
256            0 => Some(vec![19]),
257
258            1 => {
259                let state = slave.state().map(|s| s as u8).unwrap_or(0);
260                Some(vec![state])
261            }
262
263            2 => Some(slave.error_code_raw().to_le_bytes().to_vec()),
264
265            3 => {
266                let quality = unsafe {
267                    ffi::GetSlaveLinkQuality(self.master.index(), slave_idx)
268                };
269                Some(quality.to_le_bytes().to_vec())
270            }
271            _ => Some(vec![0; 4]),
272        }
273    }
274
275    fn read_detect_modules(&self, subindex: u8) -> Option<Vec<u8>> {
276        match subindex {
277
278            0 => Some(vec![3]),
279
280            1 => Some(vec![1]),
281
282            2 => {
283                let count = self.slave_count();
284                Some(count.to_le_bytes().to_vec())
285            }
286
287            3 => Some(vec![0]),
288            _ => None,
289        }
290    }
291
292    fn read_master_diag_data(&self, subindex: u8) -> Option<Vec<u8>> {
293        match subindex {
294
295            0 => Some(vec![16]),
296            _ => {
297
298                let mut diag = ffi::MasterDiagData {
299                    cyclic_lost_frames: 0,
300                    acyclic_lost_frames: 0,
301                    cyclic_frames_per_sec: 0,
302                    acyclic_frames_per_sec: 0,
303                    master_state: 0,
304                };
305                let ok = unsafe {
306                    ffi::GetMasterDiagData(self.master.index(), &mut diag)
307                };
308                if ok == 0 { return Some(vec![0; 4]); }
309
310                match subindex {
311
312                    1 => Some(diag.cyclic_lost_frames.to_le_bytes().to_vec()),
313
314                    2 => Some(diag.acyclic_lost_frames.to_le_bytes().to_vec()),
315
316                    3 => Some(diag.cyclic_frames_per_sec.to_le_bytes().to_vec()),
317
318                    4 => Some(diag.acyclic_frames_per_sec.to_le_bytes().to_vec()),
319
320                    5 => Some(diag.master_state.to_le_bytes().to_vec()),
321                    _ => Some(vec![0; 4]),
322                }
323            }
324        }
325    }
326}
327
328impl<'a> std::fmt::Display for MasterObjectDictionary<'a> {
329    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330        write!(
331            f,
332            "ETG.1510 主站对象字典 (VendorID=0x{:08X}, Serial={})",
333            self.vendor_id(),
334            self.serial_number
335        )
336    }
337}