1use super::{
2 builder::{self, NoTimer},
3 control_interface::ControlInterface,
4 data_interface::{DataInterface, NoInterface},
5 encoding::json::OtaJob,
6 pal::OtaPal,
7 state::{Error, Events, JobEventData, SmContext, StateMachine, States},
8};
9use crate::jobs::StatusDetails;
10
11pub struct OtaAgent<'a, C, DP, DS, T, ST, PAL, const TIMER_HZ: u32>
13where
14 C: ControlInterface,
15 DP: DataInterface,
16 DS: DataInterface,
17 T: fugit_timer::Timer<TIMER_HZ>,
18 ST: fugit_timer::Timer<TIMER_HZ>,
19 PAL: OtaPal,
20{
21 pub(crate) state: StateMachine<SmContext<'a, C, DP, DS, T, ST, PAL, 3, TIMER_HZ>>,
22}
23
24impl<'a, C, DP, DS, T, ST, PAL, const TIMER_HZ: u32> Drop
27 for OtaAgent<'a, C, DP, DS, T, ST, PAL, TIMER_HZ>
28where
29 C: ControlInterface,
30 DP: DataInterface,
31 DS: DataInterface,
32 T: fugit_timer::Timer<TIMER_HZ>,
33 ST: fugit_timer::Timer<TIMER_HZ>,
34 PAL: OtaPal,
35{
36 fn drop(&mut self) {
37 let sm_context = self.state.context_mut();
38 sm_context.ota_close().ok();
39 sm_context.control.cleanup().ok();
40 }
41}
42
43impl<'a, C, DP, T, PAL, const TIMER_HZ: u32>
44 OtaAgent<'a, C, DP, NoInterface, T, NoTimer, PAL, TIMER_HZ>
45where
46 C: ControlInterface,
47 DP: DataInterface,
48 T: fugit_timer::Timer<TIMER_HZ>,
49 PAL: OtaPal,
50{
51 pub fn builder(
52 control_interface: &'a C,
53 data_primary: DP,
54 request_timer: T,
55 pal: PAL,
56 ) -> builder::OtaAgentBuilder<'a, C, DP, NoInterface, T, NoTimer, PAL, TIMER_HZ> {
57 builder::OtaAgentBuilder::new(control_interface, data_primary, request_timer, pal)
58 }
59}
60
61impl<'a, C, DP, DS, T, ST, PAL, const TIMER_HZ: u32> OtaAgent<'a, C, DP, DS, T, ST, PAL, TIMER_HZ>
63where
64 C: ControlInterface,
65 DP: DataInterface,
66 DS: DataInterface,
67 T: fugit_timer::Timer<TIMER_HZ>,
68 ST: fugit_timer::Timer<TIMER_HZ>,
69 PAL: OtaPal,
70{
71 pub fn init(&mut self) {
72 if matches!(self.state(), &States::Ready) {
73 self.state.process_event(Events::Start).ok();
74 } else {
75 self.state.process_event(Events::Resume).ok();
76 }
77 }
78
79 pub fn job_update(
80 &mut self,
81 job_name: &str,
82 ota_document: &OtaJob,
83 status_details: Option<&StatusDetails>,
84 ) -> Result<&States, Error> {
85 self.state
86 .process_event(Events::ReceivedJobDocument(JobEventData {
87 job_name,
88 ota_document,
89 status_details,
90 }))
91 }
92
93 pub fn timer_callback(&mut self) -> Result<(), Error> {
94 let ctx = self.state.context_mut();
95 if ctx.request_timer.wait().is_ok() {
96 return self.state.process_event(Events::RequestTimer).map(drop);
97 }
98
99 if let Some(ref mut self_test_timer) = ctx.self_test_timer {
100 if self_test_timer.wait().is_ok() {
101 error!(
102 "Self test failed to complete within {} ms",
103 ctx.config.self_test_timeout_ms
104 );
105 ctx.pal.reset_device().ok();
106 }
107 }
108 Ok(())
109 }
110
111 pub fn process_event(&mut self) -> Result<&States, Error> {
112 if let Some(event) = self.state.context_mut().events.dequeue() {
113 self.state.process_event(event)
114 } else {
115 Ok(self.state())
116 }
117 }
118
119 pub fn handle_message(&mut self, payload: &mut [u8]) -> Result<&States, Error> {
120 self.state.process_event(Events::ReceivedFileBlock(payload))
121 }
122
123 pub fn check_for_update(&mut self) -> Result<&States, Error> {
124 if matches!(
125 self.state(),
126 States::WaitingForJob | States::RequestingJob | States::WaitingForFileBlock
127 ) {
128 self.state.process_event(Events::RequestJobDocument)
129 } else {
130 Ok(self.state())
131 }
132 }
133
134 pub fn abort(&mut self) -> Result<&States, Error> {
135 self.state.process_event(Events::UserAbort)
136 }
137
138 pub fn suspend(&mut self) -> Result<&States, Error> {
139 self.state.context_mut().request_timer.cancel().ok();
141
142 self.state.process_event(Events::Suspend)
144 }
145
146 pub fn resume(&mut self) -> Result<&States, Error> {
147 self.state.process_event(Events::Resume)
149 }
150
151 pub fn state(&self) -> &States {
152 self.state.state()
153 }
154}