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
use crate::protocol::{Command, Status};
use core::convert::Infallible;
use core::future::Future;

use crate::traits::UpdateService;

/// An in-memory updater service, useful in tests.
pub struct InMemory<'a> {
    expected_version: &'a [u8],
    expected_firmware: &'a [u8],
}

impl<'a> InMemory<'a> {
    pub fn new(expected_version: &'a [u8], expected_firmware: &'a [u8]) -> Self {
        Self {
            expected_version,
            expected_firmware,
        }
    }
}

impl<'a> UpdateService for InMemory<'a> {
    type Error = Infallible;

    type RequestFuture<'m> = impl Future<Output = Result<Command<'m>, Self::Error>> + 'm where Self: 'm;
    fn request<'m>(&'m mut self, status: &'m Status<'m>) -> Self::RequestFuture<'m> {
        async move {
            if self.expected_version == status.version.as_ref() {
                Ok(Command::new_sync(
                    self.expected_version,
                    None,
                    status.correlation_id,
                ))
            } else if let Some(update) = &status.update {
                if update.version == self.expected_version {
                    if update.offset as usize >= self.expected_firmware.len() {
                        // Update is finished, instruct device to swap
                        Ok(Command::new_swap(
                            self.expected_version,
                            &[],
                            status.correlation_id,
                        ))
                    } else {
                        // Continue updating
                        let data = self.expected_firmware;
                        let mtu = status.mtu.unwrap_or(16) as usize;
                        let to_copy = core::cmp::min(mtu, data.len() - update.offset as usize);
                        let s = &data[update.offset as usize..update.offset as usize + to_copy];
                        Ok(Command::new_write(
                            self.expected_version,
                            update.offset,
                            s,
                            status.correlation_id,
                        ))
                    }
                } else {
                    //  Unexpected version in status update, we need to start at 0
                    let data = self.expected_firmware;
                    let mtu = status.mtu.unwrap_or(128) as usize;
                    let to_copy = core::cmp::min(mtu, data.len());
                    let s = &data[..to_copy];
                    Ok(Command::new_write(
                        self.expected_version,
                        0,
                        s,
                        status.correlation_id,
                    ))
                }
            } else {
                // No update status, start a new update
                let data = self.expected_firmware;
                let mtu = status.mtu.unwrap_or(128) as usize;
                let to_copy = core::cmp::min(mtu, data.len());
                let s = &data[..to_copy];
                Ok(Command::new_write(
                    self.expected_version,
                    0,
                    s,
                    status.correlation_id,
                ))
            }
        }
    }
}