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}
103
104/// Parse the payload header, and separate the RPC bytes from the whole message. Accepts
105/// the whole message received.
106pub fn parse_msg(buf: &[u8]) -> Result<ParsedMsg, EspError> {
107    let header = PayloadHeader::from_bytes(&buf[..HEADER_SIZE])?;
108    let total_size = header.len as usize + PL_HEADER_SIZE;
109
110    if total_size > buf.len() {
111        return Err(EspError::Capacity);
112    }
113
114    let rpc_buf = &buf[HEADER_SIZE..total_size];
115    let (rpc, data_start_i, _data_len_rpc) = Rpc::from_bytes(rpc_buf)?;
116    let data = &rpc_buf[data_start_i..];
117
118    // todo: Temp to get troubleshooting data to the micropb GH.
119    println!("RPC BUF: {:?}", rpc_buf);
120    // println!("\n\n\n\nParsing msg..."); // todo tmep
121
122    // Parsing the proto data from the generated mod.
123    let mut decoder = PbDecoder::new(rpc_buf);
124    let mut rpc_proto = RpcP::default();
125
126    // todo: Until we sort out decode errors on repeated fields with micropb.
127    // rpc_proto
128    //     .decode(&mut decoder, rpc_buf.len())
129    //     .map_err(|_| EspError::Proto)?;
130
131    // Workaround to fall back to our native API, setting MicroPB's parse result to None, vice returning an error.
132    let mut rpc_proto_ = None;
133    match rpc_proto.decode(&mut decoder, rpc_buf.len()) {
134        Ok(_) => rpc_proto_ = Some(rpc_proto),
135        Err(e) => {
136            match e {
137                micropb::DecodeError::ZeroField => println!("ZF"),
138                micropb::DecodeError::UnexpectedEof => println!("Ueof"),
139                micropb::DecodeError::Deprecation => println!("Dep"),
140                micropb::DecodeError::UnknownWireType => println!("UWT"),
141                micropb::DecodeError::VarIntLimit => println!("Varlint"),
142                micropb::DecodeError::CustomField => println!("CustomF"),
143                micropb::DecodeError::Utf8 => println!("Utf"),
144                micropb::DecodeError::Capacity => {
145                    // println!("RPC buf len: {} Msg size (micropb): {}", rpc_buf.len(), rpc_proto.compute_size());
146                    println!("MIcropb capacity error");
147                }
148                micropb::DecodeError::WrongLen => println!("WrongLen"),
149                micropb::DecodeError::Reader(e2) => println!("Reader"),
150                _ => println!("Other"),
151            }
152            println!("Micropb decode error on: {:?}", rpc.msg_type);
153        }
154    }
155
156    Ok(ParsedMsg {
157        header,
158        rpc,
159        data,
160        rpc_raw: rpc_proto_,
161    })
162}