1use core::{convert::Infallible, sync::atomic::Ordering};
6
7use portable_atomic::AtomicBool;
8use zencan_common::{
9 constants::values::SAVE_CMD,
10 objects::{ObjectCode, SubInfo},
11 sdo::AbortCode,
12};
13
14use crate::object_dict::ObjectAccess;
15
16pub type StoreObjectsCallback =
18 dyn Fn(&mut dyn embedded_io::Read<Error = Infallible>, usize) + Sync;
19
20#[derive(Default)]
21#[allow(missing_debug_implementations)]
22pub struct StorageContext {
24 pub(crate) store_flag: AtomicBool,
26 pub(crate) store_supported: AtomicBool,
28}
29
30impl StorageContext {
31 pub const fn new() -> Self {
33 Self {
34 store_flag: AtomicBool::new(false),
35 store_supported: AtomicBool::new(false),
36 }
37 }
38}
39
40#[allow(missing_debug_implementations)]
42pub struct StorageCommandObject {
43 storage_context: &'static StorageContext,
44}
45
46impl StorageCommandObject {
47 pub const fn new(storage_context: &'static StorageContext) -> Self {
49 Self { storage_context }
50 }
51}
52
53impl ObjectAccess for StorageCommandObject {
54 fn read(&self, sub: u8, offset: usize, buf: &mut [u8]) -> Result<usize, AbortCode> {
55 match sub {
56 0 => {
57 if offset != 0 || buf.len() != 1 {
58 Err(AbortCode::DataTypeMismatch)
59 } else {
60 buf[0] = 1;
61 Ok(1)
62 }
63 }
64 1 => {
65 let mut value = 0u32;
68 if self.storage_context.store_supported.load(Ordering::Relaxed) {
69 value |= 1;
70 }
71 let value_bytes = value.to_le_bytes();
72 if offset < value_bytes.len() {
73 let read_len = buf.len().min(value_bytes.len() - offset);
74 buf[..read_len].copy_from_slice(&value_bytes[offset..offset + read_len]);
75 Ok(read_len)
76 } else {
77 Ok(0)
78 }
79 }
80 _ => Err(AbortCode::NoSuchSubIndex),
81 }
82 }
83
84 fn read_size(&self, sub: u8) -> Result<usize, AbortCode> {
85 match sub {
86 0 => Ok(1),
87 1 => Ok(4),
88 _ => Err(AbortCode::NoSuchSubIndex),
89 }
90 }
91
92 fn write(&self, sub: u8, data: &[u8]) -> Result<(), AbortCode> {
93 match sub {
94 0 => Err(AbortCode::ReadOnly),
95 1 => {
96 if data.len() != 4 {
97 Err(AbortCode::DataTypeMismatch)
98 } else {
99 let value = u32::from_le_bytes(data[0..4].try_into().unwrap());
100 if value == SAVE_CMD {
102 if self.storage_context.store_supported.load(Ordering::Relaxed) {
103 self.storage_context
104 .store_flag
105 .store(true, Ordering::Relaxed);
106 Ok(())
107 } else {
108 Err(AbortCode::ResourceNotAvailable)
109 }
110 } else {
111 Err(AbortCode::IncompatibleParameter)
112 }
113 }
114 }
115 _ => Err(AbortCode::NoSuchSubIndex),
116 }
117 }
118
119 fn object_code(&self) -> ObjectCode {
120 ObjectCode::Record
121 }
122
123 fn sub_info(&self, sub: u8) -> Result<SubInfo, AbortCode> {
124 match sub {
125 0 => Ok(SubInfo::MAX_SUB_NUMBER),
126 1 => Ok(SubInfo::new_u32().rw_access()),
127 _ => Err(AbortCode::NoSuchSubIndex),
128 }
129 }
130}