aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-esp-hosted/src/lib.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-06-09 03:36:48 +0200
committerDario Nieuwenhuis <[email protected]>2023-06-22 21:12:10 +0200
commit6c123596b7d48ee66ea93e8b1515e91231e9bced (patch)
tree7f657d78d2fac5a24982d74b909789d60a2dfee7 /embassy-net-esp-hosted/src/lib.rs
parent1f2be2dac5eeed739d2866b9b63ca06fdd84c276 (diff)
wip: esp-hosted net driver.
Diffstat (limited to 'embassy-net-esp-hosted/src/lib.rs')
-rw-r--r--embassy-net-esp-hosted/src/lib.rs300
1 files changed, 300 insertions, 0 deletions
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
new file mode 100644
index 000000000..2cf05a7df
--- /dev/null
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -0,0 +1,300 @@
1#![no_std]
2
3use control::Control;
4use embassy_futures::select::{select3, Either3};
5use embassy_net_driver_channel as ch;
6use embassy_time::{Duration, Instant, Timer};
7use embedded_hal::digital::{InputPin, OutputPin};
8use embedded_hal_async::digital::Wait;
9use embedded_hal_async::spi::SpiDevice;
10use ioctl::IoctlState;
11
12use crate::ioctl::PendingIoctl;
13
14mod proto;
15
16// must be first
17mod fmt;
18
19mod control;
20mod ioctl;
21
22const MTU: usize = 1514;
23
24macro_rules! impl_bytes {
25 ($t:ident) => {
26 impl $t {
27 pub const SIZE: usize = core::mem::size_of::<Self>();
28
29 #[allow(unused)]
30 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
31 unsafe { core::mem::transmute(*self) }
32 }
33
34 #[allow(unused)]
35 pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
36 let alignment = core::mem::align_of::<Self>();
37 assert_eq!(
38 bytes.as_ptr().align_offset(alignment),
39 0,
40 "{} is not aligned",
41 core::any::type_name::<Self>()
42 );
43 unsafe { core::mem::transmute(bytes) }
44 }
45
46 #[allow(unused)]
47 pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
48 let alignment = core::mem::align_of::<Self>();
49 assert_eq!(
50 bytes.as_ptr().align_offset(alignment),
51 0,
52 "{} is not aligned",
53 core::any::type_name::<Self>()
54 );
55
56 unsafe { core::mem::transmute(bytes) }
57 }
58 }
59 };
60}
61
62#[repr(C, packed)]
63#[derive(Clone, Copy, Debug, Default)]
64struct PayloadHeader {
65 /// InterfaceType on lower 4 bits, number on higher 4 bits.
66 if_type_and_num: u8,
67
68 /// Flags.
69 ///
70 /// bit 0: more fragments.
71 flags: u8,
72
73 len: u16,
74 offset: u16,
75 checksum: u16,
76 seq_num: u16,
77 reserved2: u8,
78
79 /// Packet type for HCI or PRIV interface, reserved otherwise
80 hci_priv_packet_type: u8,
81}
82impl_bytes!(PayloadHeader);
83
84#[repr(u8)]
85enum InterfaceType {
86 Sta = 0,
87 Ap = 1,
88 Serial = 2,
89 Hci = 3,
90 Priv = 4,
91 Test = 5,
92}
93
94const MAX_SPI_BUFFER_SIZE: usize = 1600;
95
96pub struct State {
97 ioctl_state: IoctlState,
98 ch: ch::State<MTU, 4, 4>,
99}
100
101impl State {
102 pub fn new() -> Self {
103 Self {
104 ioctl_state: IoctlState::new(),
105 ch: ch::State::new(),
106 }
107 }
108}
109
110pub type NetDriver<'a> = ch::Device<'a, MTU>;
111
112pub async fn new<'a, SPI, IN, OUT>(
113 state: &'a mut State,
114 spi: SPI,
115 handshake: IN,
116 ready: IN,
117 reset: OUT,
118) -> (NetDriver<'a>, Control<'a>, Runner<'a, SPI, IN, OUT>)
119where
120 SPI: SpiDevice,
121 IN: InputPin + Wait,
122 OUT: OutputPin,
123{
124 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
125 let state_ch = ch_runner.state_runner();
126
127 let mut runner = Runner {
128 ch: ch_runner,
129 ioctl_state: &state.ioctl_state,
130 next_seq: 1,
131 handshake,
132 ready,
133 reset,
134 spi,
135 };
136 runner.init().await;
137
138 (device, Control::new(state_ch, &state.ioctl_state), runner)
139}
140
141pub struct Runner<'a, SPI, IN, OUT> {
142 ch: ch::Runner<'a, MTU>,
143 ioctl_state: &'a IoctlState,
144
145 next_seq: u16,
146
147 spi: SPI,
148 handshake: IN,
149 ready: IN,
150 reset: OUT,
151}
152
153impl<'a, SPI, IN, OUT> Runner<'a, SPI, IN, OUT>
154where
155 SPI: SpiDevice,
156 IN: InputPin + Wait,
157 OUT: OutputPin,
158{
159 async fn init(&mut self) {}
160
161 pub async fn run(mut self) -> ! {
162 debug!("resetting...");
163 self.reset.set_low().unwrap();
164 Timer::after(Duration::from_millis(100)).await;
165 self.reset.set_high().unwrap();
166 Timer::after(Duration::from_millis(1000)).await;
167
168 let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
169 let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
170
171 loop {
172 self.handshake.wait_for_high().await.unwrap();
173
174 let ioctl = self.ioctl_state.wait_pending();
175 let tx = self.ch.tx_buf();
176 let ev = async { self.ready.wait_for_high().await.unwrap() };
177
178 match select3(ioctl, tx, ev).await {
179 Either3::First(PendingIoctl { buf, req_len }) => {
180 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
181 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
182 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
183
184 let mut header = PayloadHeader {
185 if_type_and_num: InterfaceType::Serial as _,
186 len: (req_len + 14) as _,
187 offset: PayloadHeader::SIZE as _,
188 seq_num: self.next_seq,
189 ..Default::default()
190 };
191 self.next_seq = self.next_seq.wrapping_add(1);
192
193 // Calculate checksum
194 tx_buf[0..12].copy_from_slice(&header.to_bytes());
195 header.checksum = checksum(&tx_buf[..26 + req_len]);
196 tx_buf[0..12].copy_from_slice(&header.to_bytes());
197
198 debug!("====== SENDING IOCTL");
199 }
200 Either3::Second(packet) => {
201 tx_buf[12..][..packet.len()].copy_from_slice(packet);
202
203 let mut header = PayloadHeader {
204 if_type_and_num: InterfaceType::Sta as _,
205 len: packet.len() as _,
206 offset: PayloadHeader::SIZE as _,
207 seq_num: self.next_seq,
208 ..Default::default()
209 };
210 self.next_seq = self.next_seq.wrapping_add(1);
211
212 // Calculate checksum
213 tx_buf[0..12].copy_from_slice(&header.to_bytes());
214 header.checksum = checksum(&tx_buf[..12 + packet.len()]);
215 tx_buf[0..12].copy_from_slice(&header.to_bytes());
216
217 self.ch.tx_done();
218 }
219 Either3::Third(()) => {
220 tx_buf[..PayloadHeader::SIZE].fill(0);
221 }
222 }
223
224 if tx_buf[0] != 0 {
225 trace!("tx: {:02x}", &tx_buf[..40]);
226 }
227
228 self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
229 let delay_until = Instant::now() + Duration::from_millis(1);
230 self.handle_rx(&mut rx_buf);
231 Timer::at(delay_until).await;
232 }
233 }
234
235 fn handle_rx(&mut self, buf: &mut [u8]) {
236 trace!("rx: {:02x}", &buf[..40]);
237
238 let buf_len = buf.len();
239 let h = PayloadHeader::from_bytes_mut((&mut buf[..PayloadHeader::SIZE]).try_into().unwrap());
240
241 if h.len == 0 || h.offset as usize != PayloadHeader::SIZE {
242 return;
243 }
244
245 let payload_len = h.len as usize;
246 if buf_len < PayloadHeader::SIZE + payload_len {
247 warn!("rx: len too big");
248 return;
249 }
250
251 let if_type_and_num = h.if_type_and_num;
252 let want_checksum = h.checksum;
253 h.checksum = 0;
254 let got_checksum = checksum(&buf[..PayloadHeader::SIZE + payload_len]);
255 if want_checksum != got_checksum {
256 warn!("rx: bad checksum. Got {:04x}, want {:04x}", got_checksum, want_checksum);
257 return;
258 }
259
260 let payload = &mut buf[PayloadHeader::SIZE..][..payload_len];
261
262 match if_type_and_num & 0x0f {
263 // STA
264 0 => match self.ch.try_rx_buf() {
265 Some(buf) => {
266 buf[..payload.len()].copy_from_slice(payload);
267 self.ch.rx_done(payload.len())
268 }
269 None => warn!("failed to push rxd packet to the channel."),
270 },
271 // serial
272 2 => {
273 debug!("serial rx: {:02x}", payload);
274 if payload.len() < 14 {
275 warn!("serial rx: too short");
276 return;
277 }
278 if &payload[..12] != b"\x01\x08\x00ctrlResp\x02" {
279 warn!("serial rx: bad tlv");
280 return;
281 }
282 let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize;
283 if payload.len() < 14 + len {
284 warn!("serial rx: too short 2");
285 return;
286 }
287 self.ioctl_state.ioctl_done(&payload[14..][..len]);
288 }
289 _ => warn!("unknown iftype {}", if_type_and_num),
290 }
291 }
292}
293
294fn checksum(buf: &[u8]) -> u16 {
295 let mut res = 0u16;
296 for &b in buf {
297 res = res.wrapping_add(b as _);
298 }
299 res
300}