esp_hosted/lib.rs
1#![no_std]
2#![allow(dead_code)]
3#![allow(non_camel_case_types)]
4#![allow(static_mut_refs)]
5
6//! An interface for interacting with ESP-Hosted-MCU firmware, via UART.
7
8mod header;
9pub mod proto_data;
10mod rpc;
11mod transport;
12pub mod wifi;
13
14mod esp_errors;
15pub mod proto;
16mod util;
17
18use defmt::{Format, println};
19pub use header::PayloadHeader;
20use micropb::{MessageDecode, MessageEncode, PbDecoder};
21use num_enum::TryFromPrimitive;
22pub use proto::{Rpc as RpcP, RpcId as RpcIdP, RpcType as RpcTypeP, *};
23pub use proto_data::RpcId;
24
25// use crate::esp_errors::EspCode;
26pub use crate::rpc::*;
27use crate::{
28 header::{HEADER_SIZE, PL_HEADER_SIZE},
29 proto_data::RpcReqConfigHeartbeat,
30 rpc::{Rpc, setup_rpc},
31 wifi::WifiApRecord,
32};
33
34#[macro_export]
35macro_rules! parse_le {
36 ($bytes:expr, $t:ty, $range:expr) => {{ <$t>::from_le_bytes($bytes[$range].try_into().unwrap()) }};
37}
38
39#[macro_export]
40macro_rules! copy_le {
41 ($dest:expr, $src:expr, $range:expr) => {{ $dest[$range].copy_from_slice(&$src.to_le_bytes()) }};
42}
43
44const AP_BUF_MAX: usize = 100;
45const BLE_BUF_MAX: usize = 100;
46
47const ESP_ERR_HOSTED_BASE: u16 = 0x2f00;
48
49/// A simple error enum for our host-side protocol
50#[derive(Format)]
51pub enum EspError {
52 // #[cfg(feature = "hal")]
53 // Uart(UartError),
54 /// e.g. uart, spi etc.
55 Comms,
56 UnexpectedResponse(u8),
57 CrcMismatch,
58 Timeout,
59 InvalidData,
60 Proto,
61 Capacity,
62 // todo: Put back. flash limit problem.
63 // Esp(EspCode),
64}
65
66// #[cfg(feature = "hal")]
67// impl From<UartError> for EspError {
68// fn from(e: UartError) -> Self {
69// EspError::Uart(e)
70// }
71// }
72
73/// Minimum of 10s.
74pub fn cfg_heartbeat<W>(
75 buf: &mut [u8],
76 mut write: W,
77 uid: u32,
78 cfg: &RpcReqConfigHeartbeat,
79) -> Result<(), EspError>
80// todo: Typedef this if able. (Unstable feature)
81where
82 W: FnMut(&[u8]) -> Result<(), EspError>,
83{
84 let rpc = Rpc::new_req(RpcId::ReqConfigHeartbeat, uid);
85
86 let mut data = [0; 5]; // Seems to be 4 in for small duration values.
87 let data_size = cfg.to_bytes(&mut data);
88
89 // unsafe {
90 let frame_len = setup_rpc(buf, &rpc, &data[..data_size]);
91 write(&buf[..frame_len])?;
92 // }
93
94 Ok(())
95}
96
97pub struct ParsedMsg<'a> {
98 pub header: PayloadHeader,
99 pub rpc: Rpc,
100 pub data: &'a [u8],
101 // pub rpc_raw: Option<RpcP>,
102 pub rpc_parsed: RpcP,
103}
104
105/// Parse the payload header, and separate the RPC bytes from the whole message. Accepts
106/// the whole message received.
107pub fn parse_msg(buf: &[u8]) -> Result<ParsedMsg, EspError> {
108 let header = PayloadHeader::from_bytes(&buf[..HEADER_SIZE])?;
109 let total_size = header.len as usize + PL_HEADER_SIZE;
110
111 if total_size >= buf.len() {
112 return Err(EspError::Capacity);
113 }
114
115 let rpc_buf = &buf[HEADER_SIZE..total_size];
116 let (rpc, data_start_i, _data_len_rpc) = Rpc::from_bytes(rpc_buf)?;
117 let data = &rpc_buf[data_start_i..];
118
119 // todo: Temp to get troubleshooting data to the micropb GH.
120 // println!("RPC BUF: {:?}", rpc_buf);
121 // println!("\n\n\n\nParsing msg..."); // todo tmep
122
123 // Parsing the proto data from the generated mod.
124 let mut decoder = PbDecoder::new(rpc_buf);
125 let mut rpc_parsed = RpcP::default();
126
127 // todo: Until we sort out decode errors on repeated fields with micropb.
128 rpc_parsed
129 .decode(&mut decoder, rpc_buf.len())
130 .map_err(|_| EspError::Proto)?;
131
132 // // Workaround to fall back to our native API, setting MicroPB's parse result to None, vice returning an error.
133 // let mut rpc_proto_ = None;
134 // match rpc_proto.decode(&mut decoder, rpc_buf.len()) {
135 // Ok(_) => rpc_proto_ = Some(rpc_proto),
136 // Err(e) => {
137 // match e {
138 // micropb::DecodeError::ZeroField => println!("ZF"),
139 // micropb::DecodeError::UnexpectedEof => println!("Ueof"),
140 // micropb::DecodeError::Deprecation => println!("Dep"),
141 // micropb::DecodeError::UnknownWireType => println!("UWT"),
142 // micropb::DecodeError::VarIntLimit => println!("Varlint"),
143 // micropb::DecodeError::CustomField => println!("CustomF"),
144 // micropb::DecodeError::Utf8 => println!("Utf"),
145 // micropb::DecodeError::Capacity => {
146 // // println!("RPC buf len: {} Msg size (micropb): {}", rpc_buf.len(), rpc_proto.compute_size());
147 // println!("MIcropb capacity error");
148 // }
149 // micropb::DecodeError::WrongLen => println!("WrongLen"),
150 // micropb::DecodeError::Reader(e2) => println!("Reader"),
151 // _ => println!("Other"),
152 // }
153 // println!("Micropb decode error on: {:?}", rpc.msg_type);
154 // }
155 // }
156
157 Ok(ParsedMsg {
158 header,
159 rpc,
160 data,
161 // rpc_raw: rpc_proto_,
162 rpc_parsed,
163 })
164}