mediatek_optical/update/
completion.rs1use super::{FlashError, Verified};
4use crate::{drive, layout, receiver, INQUIRY_LEN};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum ReadbackQuality {
10 Complete(Verified),
12 Limited {
14 checked: usize,
16 unverified: usize,
18 },
19}
20
21#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct Startup {
24 inquiry: [u8; INQUIRY_LEN],
25 descriptor: [u8; 0x58],
26}
27impl Startup {
28 pub fn inquiry(&self) -> &[u8; INQUIRY_LEN] {
30 &self.inquiry
31 }
32 pub fn descriptor(&self) -> &[u8; 0x58] {
35 &self.descriptor
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
41pub struct Completion {
42 pub startup: Startup,
44 pub readback: ReadbackQuality,
46}
47impl Completion {
48 pub(crate) fn into_verified<E>(self) -> Result<Verified, FlashError<E>> {
51 match self.readback {
52 ReadbackQuality::Complete(verified) => Ok(verified),
53 ReadbackQuality::Limited {
54 checked,
55 unverified,
56 } => Err(FlashError::Incomplete {
57 checked,
58 unverified,
59 }),
60 }
61 }
62}
63
64#[derive(Debug)]
72#[non_exhaustive]
73pub enum StartupError<E> {
74 Identity(receiver::Error<E>),
76 Read(drive::Error<E>),
78 TargetMismatch,
80}
81impl<E: core::fmt::Debug> core::fmt::Display for StartupError<E> {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 match self {
84 Self::Identity(error) => write!(f, "{error}"),
85 Self::Read(error) => write!(f, "{error}"),
86 Self::TargetMismatch => {
87 f.write_str("live firmware identity or build differs from the selected target")
88 }
89 }
90 }
91}
92impl<E: core::fmt::Debug + 'static> std::error::Error for StartupError<E> {
93 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
94 match self {
95 Self::Identity(source) => Some(source),
96 Self::Read(source) => Some(source),
97 Self::TargetMismatch => None,
98 }
99 }
100}
101
102pub(super) fn complete<T: drive::Transport>(
103 reads: &mut T,
104 image: &[u8],
105 result: Result<Verified, FlashError<T::Error>>,
106) -> Result<Completion, FlashError<T::Error>> {
107 let readback = match result {
108 Ok(verified) => ReadbackQuality::Complete(verified),
109 Err(FlashError::Incomplete {
110 checked,
111 unverified,
112 }) => ReadbackQuality::Limited {
113 checked,
114 unverified,
115 },
116 Err(error) => return Err(error),
119 };
120 let startup = confirm_startup(reads, image).map_err(FlashError::Startup)?;
121 Ok(Completion { startup, readback })
122}
123
124fn confirm_startup<T: drive::Transport>(
125 reads: &mut T,
126 image: &[u8],
127) -> Result<Startup, StartupError<T::Error>> {
128 let expected = layout::DESCRIPTOR
129 .of(image)
130 .ok_or(StartupError::TargetMismatch)?;
131 let mode = receiver::detect_mode(reads).map_err(StartupError::Identity)?;
132 if mode.mode() != receiver::Mode::Firmware || mode.inquiry()[8..36] != expected[..28] {
133 return Err(StartupError::TargetMismatch);
134 }
135 let mut descriptor = [0; layout::DESCRIPTOR.len];
136 drive::read_memory(reads, layout::DESCRIPTOR.start as u32, &mut descriptor)
137 .map_err(StartupError::Read)?;
138 if descriptor[..0x58] != expected[..0x58] {
139 return Err(StartupError::TargetMismatch);
140 }
141 Ok(Startup {
142 inquiry: *mode.inquiry(),
143 descriptor: descriptor[..0x58]
144 .try_into()
145 .expect("fixed descriptor length"),
146 })
147}