1use zencan_common::{
4 objects::{AccessType, DataType, ObjectCode, SubInfo},
5 sdo::AbortCode,
6 AtomicCell,
7};
8
9use super::{ObjectFlagAccess, SubObjectAccess};
10
11pub trait ObjectAccess: Sync + Send {
15 fn read(&self, sub: u8, offset: usize, buf: &mut [u8]) -> Result<usize, AbortCode>;
21
22 fn read_size(&self, sub: u8) -> Result<usize, AbortCode>;
24
25 fn write(&self, sub: u8, data: &[u8]) -> Result<(), AbortCode>;
34
35 fn begin_partial(&self, sub: u8) -> Result<(), AbortCode> {
46 if let Ok(sub_info) = self.sub_info(sub) {
47 if sub_info.access_type.is_writable() {
48 Err(AbortCode::UnsupportedAccess)
49 } else {
50 Err(AbortCode::ReadOnly)
51 }
52 } else {
53 Err(AbortCode::NoSuchSubIndex)
54 }
55 }
56
57 fn write_partial(&self, _sub: u8, _buf: &[u8]) -> Result<(), AbortCode> {
66 Err(AbortCode::GeneralError)
68 }
69
70 fn end_partial(&self, _sub: u8) -> Result<(), AbortCode> {
75 Err(AbortCode::GeneralError)
76 }
77
78 fn object_code(&self) -> ObjectCode;
80
81 fn sub_info(&self, sub: u8) -> Result<SubInfo, AbortCode>;
83
84 fn max_sub_number(&self) -> u8 {
86 match self.object_code() {
87 ObjectCode::Null => 0,
88 ObjectCode::Domain => 0,
89 ObjectCode::DefType => 0,
90 ObjectCode::DefStruct => 0,
91 ObjectCode::Var => 0,
92 ObjectCode::Array => self.read_u8(0).unwrap(),
93 ObjectCode::Record => self.read_u8(0).unwrap(),
94 }
95 }
96
97 fn set_event_flag(&self, _sub: u8) -> Result<(), AbortCode> {
102 Err(AbortCode::UnsupportedAccess)
103 }
104
105 fn read_event_flag(&self, _sub: u8) -> bool {
109 false
110 }
111
112 fn clear_events(&self) {}
116
117 fn access_type(&self, sub: u8) -> Result<AccessType, AbortCode> {
119 Ok(self.sub_info(sub)?.access_type)
120 }
121
122 fn data_type(&self, sub: u8) -> Result<DataType, AbortCode> {
124 Ok(self.sub_info(sub)?.data_type)
125 }
126
127 fn size(&self, sub: u8) -> Result<usize, AbortCode> {
132 Ok(self.sub_info(sub)?.size)
133 }
134
135 fn current_size(&self, sub: u8) -> Result<usize, AbortCode> {
142 const CHUNK_SIZE: usize = 8;
143
144 let size = self.size(sub)?;
145 if self.data_type(sub)?.is_str() {
146 let mut chunk = 0;
148 let mut buf = [0; CHUNK_SIZE];
149 while chunk < size / CHUNK_SIZE + 1 {
150 let offset = chunk * CHUNK_SIZE;
151 let bytes_to_read = (size - offset).min(CHUNK_SIZE);
152 self.read(sub, offset, &mut buf[0..bytes_to_read])?;
153
154 if let Some(zero_pos) = buf[0..bytes_to_read].iter().position(|b| *b == 0) {
155 return Ok(zero_pos + chunk * CHUNK_SIZE);
156 }
157 chunk += 1;
158 }
159 }
160 Ok(size)
162 }
163
164 fn read_u32(&self, sub: u8) -> Result<u32, AbortCode> {
166 let mut buf = [0; 4];
167 self.read(sub, 0, &mut buf)?;
168 Ok(u32::from_le_bytes(buf))
169 }
170
171 fn read_u16(&self, sub: u8) -> Result<u16, AbortCode> {
173 let mut buf = [0; 2];
174 self.read(sub, 0, &mut buf)?;
175 Ok(u16::from_le_bytes(buf))
176 }
177
178 fn read_u8(&self, sub: u8) -> Result<u8, AbortCode> {
180 let mut buf = [0; 1];
181 self.read(sub, 0, &mut buf)?;
182 Ok(buf[0])
183 }
184
185 fn read_i32(&self, sub: u8) -> Result<i32, AbortCode> {
187 let mut buf = [0; 4];
188 self.read(sub, 0, &mut buf)?;
189 Ok(i32::from_le_bytes(buf))
190 }
191
192 fn read_i16(&self, sub: u8) -> Result<i16, AbortCode> {
194 let mut buf = [0; 2];
195 self.read(sub, 0, &mut buf)?;
196 Ok(i16::from_le_bytes(buf))
197 }
198
199 fn read_i8(&self, sub: u8) -> Result<i8, AbortCode> {
201 let mut buf = [0; 1];
202 self.read(sub, 0, &mut buf)?;
203 Ok(buf[0] as i8)
204 }
205}
206pub trait ProvidesSubObjects {
212 fn get_sub_object(&self, sub: u8) -> Option<(SubInfo, &dyn SubObjectAccess)>;
220
221 fn flags(&self) -> Option<&dyn ObjectFlagAccess> {
228 None
229 }
230
231 fn object_code(&self) -> ObjectCode;
233}
234
235impl<T: ProvidesSubObjects + Sync + Send> ObjectAccess for T {
237 fn read(&self, sub: u8, offset: usize, buf: &mut [u8]) -> Result<usize, AbortCode> {
238 if let Some((info, access)) = self.get_sub_object(sub) {
239 if info.access_type.is_readable() {
240 access.read(offset, buf)
241 } else {
242 Err(AbortCode::WriteOnly)
243 }
244 } else {
245 Err(AbortCode::NoSuchSubIndex)
246 }
247 }
248
249 fn read_size(&self, sub: u8) -> Result<usize, AbortCode> {
250 if let Some((_info, access)) = self.get_sub_object(sub) {
251 Ok(access.read_size())
252 } else {
253 Err(AbortCode::NoSuchSubIndex)
254 }
255 }
256
257 fn write(&self, sub: u8, data: &[u8]) -> Result<(), AbortCode> {
258 if let Some((info, access)) = self.get_sub_object(sub) {
259 if info.access_type.is_writable() {
260 access.write(data)
261 } else {
262 Err(AbortCode::ReadOnly)
263 }
264 } else {
265 Err(AbortCode::NoSuchSubIndex)
266 }
267 }
268
269 fn begin_partial(&self, sub: u8) -> Result<(), AbortCode> {
270 if let Some((info, access)) = self.get_sub_object(sub) {
271 if info.access_type.is_writable() {
272 access.begin_partial()
273 } else {
274 Err(AbortCode::ReadOnly)
275 }
276 } else {
277 Err(AbortCode::NoSuchSubIndex)
278 }
279 }
280
281 fn write_partial(&self, sub: u8, buf: &[u8]) -> Result<(), AbortCode> {
282 if let Some((_, access)) = self.get_sub_object(sub) {
283 access.write_partial(buf)
284 } else {
285 Err(AbortCode::NoSuchSubIndex)
286 }
287 }
288
289 fn end_partial(&self, sub: u8) -> Result<(), AbortCode> {
290 if let Some((_, access)) = self.get_sub_object(sub) {
291 access.end_partial()
292 } else {
293 Err(AbortCode::NoSuchSubIndex)
294 }
295 }
296
297 fn set_event_flag(&self, sub: u8) -> Result<(), AbortCode> {
298 if let Some(flags) = self.flags() {
299 flags.set_flag(sub);
300 Ok(())
301 } else {
302 Err(AbortCode::UnsupportedAccess)
303 }
304 }
305
306 fn read_event_flag(&self, sub: u8) -> bool {
307 if let Some(flags) = self.flags() {
308 flags.get_flag(sub)
309 } else {
310 false
311 }
312 }
313
314 fn object_code(&self) -> ObjectCode {
315 self.object_code()
316 }
317
318 fn sub_info(&self, sub: u8) -> Result<SubInfo, AbortCode> {
319 if let Some((info, _access)) = self.get_sub_object(sub) {
320 Ok(info)
321 } else {
322 Err(AbortCode::NoSuchSubIndex)
323 }
324 }
325}
326
327#[allow(missing_debug_implementations)]
329pub struct CallbackObject<'a> {
330 obj: AtomicCell<Option<&'a dyn ObjectAccess>>,
331 object_code: ObjectCode,
332}
333
334impl CallbackObject<'_> {
335 pub fn new(object_code: ObjectCode) -> Self {
337 Self {
338 obj: AtomicCell::new(None),
339 object_code,
340 }
341 }
342}
343
344impl ObjectAccess for CallbackObject<'_> {
345 fn read(&self, sub: u8, offset: usize, buf: &mut [u8]) -> Result<usize, AbortCode> {
346 if let Some(obj) = self.obj.load() {
347 obj.read(sub, offset, buf)
348 } else {
349 Err(AbortCode::ResourceNotAvailable)
350 }
351 }
352
353 fn read_size(&self, sub: u8) -> Result<usize, AbortCode> {
354 if let Some(obj) = self.obj.load() {
355 obj.read_size(sub)
356 } else {
357 Err(AbortCode::ResourceNotAvailable)
358 }
359 }
360
361 fn write(&self, sub: u8, data: &[u8]) -> Result<(), AbortCode> {
362 if let Some(obj) = self.obj.load() {
363 obj.write(sub, data)
364 } else {
365 Err(AbortCode::ResourceNotAvailable)
366 }
367 }
368
369 fn write_partial(&self, sub: u8, buf: &[u8]) -> Result<(), AbortCode> {
370 if let Some(obj) = self.obj.load() {
371 obj.write_partial(sub, buf)
372 } else {
373 Err(AbortCode::ResourceNotAvailable)
374 }
375 }
376
377 fn end_partial(&self, sub: u8) -> Result<(), AbortCode> {
378 if let Some(obj) = self.obj.load() {
379 obj.end_partial(sub)
380 } else {
381 Err(AbortCode::ResourceNotAvailable)
382 }
383 }
384
385 fn object_code(&self) -> ObjectCode {
386 self.object_code
387 }
388
389 fn sub_info(&self, sub: u8) -> Result<SubInfo, AbortCode> {
390 if let Some(obj) = self.obj.load() {
391 obj.sub_info(sub)
392 } else {
393 Err(AbortCode::ResourceNotAvailable)
394 }
395 }
396}
397
398#[allow(missing_debug_implementations)]
400pub struct ODEntry<'a> {
401 pub index: u16,
403 pub data: &'a dyn ObjectAccess,
405}
406
407pub fn find_object<'a>(table: &[ODEntry<'a>], index: u16) -> Option<&'a dyn ObjectAccess> {
411 find_object_entry(table, index).map(|entry| entry.data)
412}
413
414pub fn find_object_entry<'a, 'b>(table: &'b [ODEntry<'a>], index: u16) -> Option<&'b ODEntry<'a>> {
421 table
422 .binary_search_by_key(&index, |e| e.index)
423 .ok()
424 .map(|i| &table[i])
425}