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}