aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-net-esp-hosted/src/control.rs46
-rw-r--r--embassy-net-esp-hosted/src/ioctl.rs17
-rw-r--r--embassy-net-esp-hosted/src/lib.rs5
-rw-r--r--embassy-net-esp-hosted/src/proto.rs12
4 files changed, 73 insertions, 7 deletions
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index 38ec648b4..d96a62daf 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -24,6 +24,11 @@ pub struct Control<'a> {
24 shared: &'a Shared, 24 shared: &'a Shared,
25} 25}
26 26
27/// Handle for managing firmware update.
28pub struct UpdateControl<'a, 'd> {
29 control: &'a mut Control<'d>,
30}
31
27/// WiFi mode. 32/// WiFi mode.
28#[allow(unused)] 33#[allow(unused)]
29#[derive(Copy, Clone, PartialEq, Eq, Debug)] 34#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -146,6 +151,13 @@ impl<'a> Control<'a> {
146 Ok(()) 151 Ok(())
147 } 152 }
148 153
154 /// Initiate a firmware update.
155 pub async fn update(&mut self) -> Result<UpdateControl<'_, 'a>, Error> {
156 let req = proto::CtrlMsg_Req_OTABegin {};
157 ioctl!(self, ReqOtaBegin, RespOtaBegin, req, resp);
158 Ok(UpdateControl { control: self })
159 }
160
149 /// duration in seconds, clamped to [10, 3600] 161 /// duration in seconds, clamped to [10, 3600]
150 async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> { 162 async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> {
151 let req = proto::CtrlMsg_Req_ConfigHeartbeat { 163 let req = proto::CtrlMsg_Req_ConfigHeartbeat {
@@ -175,7 +187,8 @@ impl<'a> Control<'a> {
175 async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> { 187 async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> {
176 debug!("ioctl req: {:?}", &msg); 188 debug!("ioctl req: {:?}", &msg);
177 189
178 let mut buf = [0u8; 128]; 190 // Theoretical max overhead is 29 bytes. Biggest message is OTA write with 256 bytes.
191 let mut buf = [0u8; 256 + 29];
179 let buf_len = buf.len(); 192 let buf_len = buf.len();
180 193
181 let mut encoder = PbEncoder::new(&mut buf[..]); 194 let mut encoder = PbEncoder::new(&mut buf[..]);
@@ -216,6 +229,37 @@ impl<'a> Control<'a> {
216 } 229 }
217} 230}
218 231
232impl<'a, 'd> UpdateControl<'a, 'd> {
233 /// Write slice of firmware to a device.
234 ///
235 /// The slice is split into chunks that can be sent across
236 /// the ioctl protocol to the wifi adapter.
237 pub async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
238 let this = &mut self.control;
239 for chunk in data.chunks(256) {
240 let req = proto::CtrlMsg_Req_OTAWrite {
241 ota_data: heapless::Vec::from_slice(chunk).unwrap(),
242 };
243 ioctl!(this, ReqOtaWrite, RespOtaWrite, req, resp);
244 }
245 Ok(())
246 }
247
248 /// End the OTA session.
249 ///
250 /// NOTE: Will reset the wifi adapter after 5 seconds.
251 pub async fn finish(self) -> Result<(), Error> {
252 let this = self.control;
253 let req = proto::CtrlMsg_Req_OTAEnd {};
254 ioctl!(this, ReqOtaEnd, RespOtaEnd, req, resp);
255 // Ensures that run loop awaits reset
256 this.shared.ota_done();
257 // Wait for re-init
258 this.init().await?;
259 Ok(())
260 }
261}
262
219// WHY IS THIS A STRING? WHYYYY 263// WHY IS THIS A STRING? WHYYYY
220fn parse_mac(mac: &str) -> Result<[u8; 6], Error> { 264fn parse_mac(mac: &str) -> Result<[u8; 6], Error> {
221 fn nibble_from_hex(b: u8) -> Result<u8, Error> { 265 fn nibble_from_hex(b: u8) -> Result<u8, Error> {
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
index a516f80c7..7f462d528 100644
--- a/embassy-net-esp-hosted/src/ioctl.rs
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -24,6 +24,7 @@ pub struct Shared(RefCell<SharedInner>);
24struct SharedInner { 24struct SharedInner {
25 ioctl: IoctlState, 25 ioctl: IoctlState,
26 is_init: bool, 26 is_init: bool,
27 is_ota: bool,
27 control_waker: WakerRegistration, 28 control_waker: WakerRegistration,
28 runner_waker: WakerRegistration, 29 runner_waker: WakerRegistration,
29} 30}
@@ -33,6 +34,7 @@ impl Shared {
33 Self(RefCell::new(SharedInner { 34 Self(RefCell::new(SharedInner {
34 ioctl: IoctlState::Done { resp_len: 0 }, 35 ioctl: IoctlState::Done { resp_len: 0 },
35 is_init: false, 36 is_init: false,
37 is_ota: false,
36 control_waker: WakerRegistration::new(), 38 control_waker: WakerRegistration::new(),
37 runner_waker: WakerRegistration::new(), 39 runner_waker: WakerRegistration::new(),
38 })) 40 }))
@@ -99,11 +101,26 @@ impl Shared {
99 } 101 }
100 } 102 }
101 103
104 // ota
105 pub fn ota_done(&self) {
106 let mut this = self.0.borrow_mut();
107 this.is_ota = true;
108 this.is_init = false;
109 this.runner_waker.wake();
110 }
111
112 // check if ota is in progress
113 pub fn is_ota(&self) -> bool {
114 let this = self.0.borrow();
115 this.is_ota
116 }
117
102 // // // // // // // // // // // // // // // // // // // // 118 // // // // // // // // // // // // // // // // // // // //
103 119
104 pub fn init_done(&self) { 120 pub fn init_done(&self) {
105 let mut this = self.0.borrow_mut(); 121 let mut this = self.0.borrow_mut();
106 this.is_init = true; 122 this.is_init = true;
123 this.is_ota = false;
107 this.control_waker.wake(); 124 this.control_waker.wake();
108 } 125 }
109 126
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index d882af8cf..7236e73e8 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -234,6 +234,11 @@ where
234 tx_buf[..PayloadHeader::SIZE].fill(0); 234 tx_buf[..PayloadHeader::SIZE].fill(0);
235 } 235 }
236 Either4::Fourth(()) => { 236 Either4::Fourth(()) => {
237 // Extend the deadline if OTA
238 if self.shared.is_ota() {
239 self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP;
240 continue;
241 }
237 panic!("heartbeat from esp32 stopped") 242 panic!("heartbeat from esp32 stopped")
238 } 243 }
239 } 244 }
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
index 74c67bd61..09bec8984 100644
--- a/embassy-net-esp-hosted/src/proto.rs
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -16,7 +16,7 @@ Switch to a proper script when https://github.com/YuhanLiin/micropb/issues/30 is
16 // Special config for things that need to be larger 16 // Special config for things that need to be larger
17 g.configure( 17 g.configure(
18 ".CtrlMsg_Req_OTAWrite.ota_data", 18 ".CtrlMsg_Req_OTAWrite.ota_data",
19 micropb_gen::Config::new().max_bytes(1024), 19 micropb_gen::Config::new().max_bytes(256),
20 ); 20 );
21 g.configure( 21 g.configure(
22 ".CtrlMsg_Event_ESPInit.init_data", 22 ".CtrlMsg_Event_ESPInit.init_data",
@@ -4296,28 +4296,28 @@ impl ::micropb::MessageEncode for CtrlMsg_Resp_OTABegin {
4296#[derive(Debug, Default, PartialEq, Clone)] 4296#[derive(Debug, Default, PartialEq, Clone)]
4297#[cfg_attr(feature = "defmt", derive(defmt::Format))] 4297#[cfg_attr(feature = "defmt", derive(defmt::Format))]
4298pub struct CtrlMsg_Req_OTAWrite { 4298pub struct CtrlMsg_Req_OTAWrite {
4299 pub r#ota_data: ::micropb::heapless::Vec<u8, 1024>, 4299 pub r#ota_data: ::micropb::heapless::Vec<u8, 256>,
4300} 4300}
4301impl CtrlMsg_Req_OTAWrite { 4301impl CtrlMsg_Req_OTAWrite {
4302 ///Return a reference to `ota_data` 4302 ///Return a reference to `ota_data`
4303 #[inline] 4303 #[inline]
4304 pub fn r#ota_data(&self) -> &::micropb::heapless::Vec<u8, 1024> { 4304 pub fn r#ota_data(&self) -> &::micropb::heapless::Vec<u8, 256> {
4305 &self.r#ota_data 4305 &self.r#ota_data
4306 } 4306 }
4307 ///Return a mutable reference to `ota_data` 4307 ///Return a mutable reference to `ota_data`
4308 #[inline] 4308 #[inline]
4309 pub fn mut_ota_data(&mut self) -> &mut ::micropb::heapless::Vec<u8, 1024> { 4309 pub fn mut_ota_data(&mut self) -> &mut ::micropb::heapless::Vec<u8, 256> {
4310 &mut self.r#ota_data 4310 &mut self.r#ota_data
4311 } 4311 }
4312 ///Set the value of `ota_data` 4312 ///Set the value of `ota_data`
4313 #[inline] 4313 #[inline]
4314 pub fn set_ota_data(&mut self, value: ::micropb::heapless::Vec<u8, 1024>) -> &mut Self { 4314 pub fn set_ota_data(&mut self, value: ::micropb::heapless::Vec<u8, 256>) -> &mut Self {
4315 self.r#ota_data = value.into(); 4315 self.r#ota_data = value.into();
4316 self 4316 self
4317 } 4317 }
4318 ///Builder method that sets the value of `ota_data`. Useful for initializing the message. 4318 ///Builder method that sets the value of `ota_data`. Useful for initializing the message.
4319 #[inline] 4319 #[inline]
4320 pub fn init_ota_data(mut self, value: ::micropb::heapless::Vec<u8, 1024>) -> Self { 4320 pub fn init_ota_data(mut self, value: ::micropb::heapless::Vec<u8, 256>) -> Self {
4321 self.r#ota_data = value.into(); 4321 self.r#ota_data = value.into();
4322 self 4322 self
4323 } 4323 }