zencan-node 0.0.4

Library for implementing an OPENCan node, primarily on an MCU
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
use core::{
    cell::RefCell,
    convert::Infallible,
    future::Future,
    pin::{pin, Pin},
    task::Context,
};

use crate::object_dict::{find_object, ODEntry};
use futures::{pending, task::noop_waker_ref};

use defmt_or_log::{debug, warn};

/// Specifies the types of nodes which can be serialized to persistent storage
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum NodeType {
    /// A node containing a saved sub-object value
    ObjectValue = 1,
    /// An unrecognized node type
    Unknown,
}

impl NodeType {
    /// Create a `NodeType` from an ID byte
    pub fn from_byte(b: u8) -> Self {
        match b {
            1 => Self::ObjectValue,
            _ => Self::Unknown,
        }
    }
}

async fn write_bytes(bytes: &[u8], reg: &RefCell<u8>) {
    for b in bytes {
        *reg.borrow_mut() = *b;
        pending!()
    }
}

async fn serialize_object(obj: &ODEntry<'_>, sub: u8, reg: &RefCell<u8>) {
    // Unwrap safety: This can only fail if the sub doesn't exist, and we already
    // checked for that above
    let data_size = obj.data.read_size(sub).unwrap() as u16;
    // Serialized node size is the variable length object data, plus node type (u8), index (u16), and sub index (u8)
    let node_size = data_size + 4;

    write_bytes(&node_size.to_le_bytes(), reg).await;
    write_bytes(&[NodeType::ObjectValue as u8], reg).await;
    write_bytes(&obj.index.to_le_bytes(), reg).await;
    write_bytes(&[sub], reg).await;

    const CHUNK_SIZE: usize = 32;
    let mut buf = [0u8; CHUNK_SIZE];
    let mut read_pos = 0;
    loop {
        // Note: returned read_len is not checked, on purpose. We already committed above to writing
        // a certain number of bytes, and we must write them. This is fine for fields which are
        // shorter than CHUNK_SIZE. This is a problem for fields which are larger than CHUNK_SIZE,
        // and can lead to "torn reads", where different chunks come from different values because
        // the value changed between the two chunks. This is only a problem for large fields which
        // can be modified on a different thread than `Node::process()` is called. Fixing it
        // requires an object locking mechanism, which may be worth considering in the future.
        obj.data.read(sub, read_pos, &mut buf).unwrap();
        let copy_len = data_size as usize - read_pos;
        read_pos += copy_len;
        write_bytes(&buf[0..copy_len], reg).await;
        if read_pos >= data_size as usize {
            break;
        }
    }
}

async fn serialize_sm(objects: &[ODEntry<'_>], reg: &RefCell<u8>) {
    for obj in objects {
        let max_sub = obj.data.max_sub_number();

        for sub in 0..max_sub + 1 {
            let info = obj.data.sub_info(sub);
            // On a record, some subs may not be present. Just skip these.
            if info.is_err() {
                continue;
            }
            let info = info.unwrap();
            if !info.persist {
                continue;
            }
            serialize_object(obj, sub, reg).await;
        }
    }
}

pub fn serialized_size(objects: &[ODEntry]) -> usize {
    const OVERHEAD_SIZE: usize = 6;
    let mut size = 0;
    for obj in objects {
        let max_sub = obj.data.max_sub_number();
        for sub in 0..max_sub + 1 {
            let info = obj.data.sub_info(sub);
            // On a record, some subs may not be present. Just skip these.
            if info.is_err() {
                continue;
            }
            let info = info.unwrap();
            if !info.persist {
                continue;
            }
            // Unwrap safety: This can only fail if the sub doesn't exist, and we already
            // checked for that above
            let data_size = obj.data.read_size(sub).unwrap();
            // Serialized node size is the variable length object data, plus node type (u8),
            // index (u16), and sub index (u8), plus a length header (u16)
            size += data_size + OVERHEAD_SIZE;
        }
    }

    size
}

struct PersistSerializer<'a, 'b, F: Future> {
    f: Pin<&'a mut F>,
    reg: &'b RefCell<u8>,
}

impl<'a, 'b, F: Future> PersistSerializer<'a, 'b, F> {
    pub fn new(f: Pin<&'a mut F>, reg: &'b RefCell<u8>) -> Self {
        Self { f, reg }
    }
}

impl<F: Future> embedded_io::ErrorType for PersistSerializer<'_, '_, F> {
    type Error = Infallible;
}

impl<F: Future> embedded_io::Read for PersistSerializer<'_, '_, F> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Infallible> {
        let mut cx = Context::from_waker(noop_waker_ref());

        let mut pos = 0;
        loop {
            if pos >= buf.len() {
                return Ok(pos);
            }

            match self.f.as_mut().poll(&mut cx) {
                core::task::Poll::Ready(_) => return Ok(pos),
                core::task::Poll::Pending => {
                    buf[pos] = *self.reg.borrow();
                    pos += 1;
                }
            }
        }
    }
}

/// Serialize node data
pub fn serialize(
    od: &[ODEntry],
    callback: &dyn Fn(&mut dyn embedded_io::Read<Error = Infallible>, usize),
) {
    let reg = RefCell::new(0);
    let fut = pin!(serialize_sm(od, &reg));
    let mut serializer = PersistSerializer::new(fut, &reg);
    let size = serialized_size(od);
    callback(&mut serializer, size)
}

/// Error which can be returned while reading persisted data
pub enum PersistReadError {
    /// Not enough bytes were present to construct the node
    NodeLengthShort,
}

/// The data for an ObjectValue node
#[derive(Debug, PartialEq)]
pub struct ObjectValue<'a> {
    /// The object index this value belongs to
    pub index: u16,
    /// The sub-object index this value belongs to
    pub sub: u8,
    /// The raw bytes to be restored to the sub object
    pub data: &'a [u8],
}

/// A reference to a single node within a slice of serialized data
///
/// Returned by the PersistNodeReader iterator.
#[derive(Debug, PartialEq)]
pub enum PersistNodeRef<'a> {
    /// A saved value for a sub-object
    ObjectValue(ObjectValue<'a>),
    /// An unrecognized node type was encountered. Either the serialized data is malformed, or
    /// perhaps it was written with a future version of code that supports more node types
    ///
    /// The bytes of the node are stored in the contained slice, including the node type in the
    /// first byte
    Unknown(&'a [u8]),
}

impl<'a> PersistNodeRef<'a> {
    /// Create a PersistNodeRef from a slice of bytes
    pub fn from_slice(data: &'a [u8]) -> Result<Self, PersistReadError> {
        if data.is_empty() {
            return Err(PersistReadError::NodeLengthShort);
        }

        match NodeType::from_byte(data[0]) {
            NodeType::ObjectValue => {
                if data.len() < 5 {
                    return Err(PersistReadError::NodeLengthShort);
                }
                Ok(Self::ObjectValue(ObjectValue {
                    index: u16::from_le_bytes(data[1..3].try_into().unwrap()),
                    sub: data[3],
                    data: &data[4..],
                }))
            }
            NodeType::Unknown => Ok(PersistNodeRef::Unknown(data)),
        }
    }
}

/// Read serialized object data from a slice of bytes
///
/// PersistNodeReader provides an Iterator of PersistNodeRef objects, representing all of the nodes
/// stored in the slice
struct PersistNodeReader<'a> {
    buf: &'a [u8],
    pos: usize,
}

impl<'a> PersistNodeReader<'a> {
    /// Instantiate a PersistNodeReader from a slice of serialized data
    pub fn new(data: &'a [u8]) -> Self {
        Self { buf: data, pos: 0 }
    }
}

impl<'a> Iterator for PersistNodeReader<'a> {
    type Item = PersistNodeRef<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.buf.len() - self.pos < 2 {
            return None;
        }
        let length = u16::from_le_bytes(self.buf[self.pos..self.pos + 2].try_into().unwrap());
        self.pos += 2;
        let node_slice = &self.buf[self.pos..self.pos + length as usize];
        self.pos += length as usize;

        PersistNodeRef::from_slice(node_slice).ok()
    }
}

/// Load values of objects previously persisted in serialized format with limited range
///
/// All saved objects where `start_index <= saved object index <= end_index` will be restored to the
/// object dictionary. Saved objects outside this range will be dropped.
///
/// # Arguments
/// - `od`: The object dictionary where objects will be updated
/// - `stored_data`: A slice of bytes, as previously provided to the store_objects callback.
/// - 'start_index
pub fn restore_stored_objects_ranged(
    od: &[ODEntry],
    stored_data: &[u8],
    start_index: u16,
    end_index: u16,
) {
    let reader = PersistNodeReader::new(stored_data);
    for item in reader {
        match item {
            PersistNodeRef::ObjectValue(restore) => {
                if restore.index < start_index || restore.index > end_index {
                    continue;
                }
                if let Some(obj) = find_object(od, restore.index) {
                    if let Ok(_sub_info) = obj.sub_info(restore.sub) {
                        debug!(
                            "Restoring 0x{:x}sub{} with {:?}",
                            restore.index, restore.sub, restore.data
                        );
                        if let Err(abort_code) = obj.write(restore.sub, restore.data) {
                            warn!(
                                "Error restoring object 0x{:x}sub{}: {:x}",
                                restore.index, restore.sub, abort_code as u32
                            );
                        }
                    } else {
                        warn!(
                            "Saved object 0x{:x}sub{} not found in OD",
                            restore.index, restore.sub
                        );
                    }
                } else {
                    warn!("Saved object 0x{:x} not found in OD", restore.index);
                }
            }
            PersistNodeRef::Unknown(id) => warn!("Unknown persisted object read: {}", id[0]),
        }
    }
}

/// Restore all stored objects in stored data to the object dict
pub fn restore_stored_objects(od: &[ODEntry], stored_data: &[u8]) {
    restore_stored_objects_ranged(od, stored_data, 0, u16::MAX);
}

/// Restore only communications objects from the stored data to the object dict
///
/// Communications objects are objects 0x1000-0x1fff.
pub fn restore_stored_comm_objects(od: &[ODEntry], stored_data: &[u8]) {
    restore_stored_objects_ranged(od, stored_data, 0x1000, 0x1fff);
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::object_dict::{
        ConstField, NullTermByteField, ODEntry, ProvidesSubObjects, ScalarField, SubObjectAccess,
    };
    use zencan_common::objects::{DataType, ObjectCode, SubInfo};

    use crate::persist::serialize;

    #[test]
    fn test_serialize_deserialize() {
        #[derive(Default)]
        struct Object100 {
            value1: ScalarField<u32>,
            value2: ScalarField<u16>,
        }

        impl ProvidesSubObjects for Object100 {
            fn get_sub_object(&self, sub: u8) -> Option<(SubInfo, &dyn SubObjectAccess)> {
                match sub {
                    0 => Some((
                        SubInfo::MAX_SUB_NUMBER,
                        const { &ConstField::new(2u8.to_le_bytes()) },
                    )),
                    1 => Some((
                        SubInfo {
                            size: 4,
                            data_type: DataType::UInt32,
                            persist: true,
                            ..Default::default()
                        },
                        &self.value1,
                    )),
                    2 => Some((
                        SubInfo {
                            size: 4,
                            data_type: DataType::UInt32,
                            persist: false,
                            ..Default::default()
                        },
                        &self.value2,
                    )),
                    _ => None,
                }
            }

            fn object_code(&self) -> ObjectCode {
                ObjectCode::Record
            }
        }

        #[derive(Default)]
        struct Object200 {
            string: NullTermByteField<15>,
        }

        impl ProvidesSubObjects for Object200 {
            fn get_sub_object(&self, sub: u8) -> Option<(SubInfo, &dyn SubObjectAccess)> {
                match sub {
                    0 => Some((
                        SubInfo::new_visibile_str(self.string.len()).persist(true),
                        &self.string,
                    )),
                    _ => None,
                }
            }

            fn object_code(&self) -> ObjectCode {
                ObjectCode::Var
            }
        }

        let inst100 = Box::leak(Box::new(Object100::default()));
        let inst200 = Box::leak(Box::new(Object200::default()));

        let od = Box::leak(Box::new([
            ODEntry {
                index: 0x100,
                data: inst100,
            },
            ODEntry {
                index: 0x200,
                data: inst200,
            },
        ]));
        inst100.value1.store(42);
        inst200.string.set_str("test".as_bytes()).unwrap();

        let data = RefCell::new(Vec::new());
        serialize(od, &|reader, _size| {
            const CHUNK_SIZE: usize = 2;
            let mut buf = [0; CHUNK_SIZE];
            loop {
                let n = reader.read(&mut buf).unwrap();
                data.borrow_mut().extend_from_slice(&buf[..n]);
                if n < buf.len() {
                    break;
                }
            }
        });

        let data = data.take();
        assert_eq!(20, data.len());
        assert_eq!(data.len(), serialized_size(od));

        let mut deser = PersistNodeReader::new(&data);
        assert_eq!(
            deser.next().unwrap(),
            PersistNodeRef::ObjectValue(ObjectValue {
                index: 0x100,
                sub: 1,
                data: &42u32.to_le_bytes()
            })
        );
        assert_eq!(
            deser.next().unwrap(),
            PersistNodeRef::ObjectValue(ObjectValue {
                index: 0x200,
                sub: 0,
                data: "test".as_bytes()
            })
        );
        assert_eq!(deser.next(), None);
    }
}