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}