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;
10pub mod rf;
11mod rpc;
12mod transport;
13
14mod esp_hosted_proto;
15mod esp_errors;
16
17use micropb::{MessageDecode, MessageEncode, PbDecoder, PbEncoder};
18
19use defmt::{Format, println};
20
21pub use header::PayloadHeader;
22use num_enum::TryFromPrimitive;
23pub use proto_data::*;
24pub use rpc::InterfaceType;
25pub use rf::*;
26
27pub use esp_hosted_proto::Rpc as RpcP;
28pub use esp_hosted_proto::RpcId as RpcIdP;
29pub use esp_hosted_proto::RpcType as RpcTypeP;
30pub use esp_hosted_proto::*;
31
32
33pub use crate::header::HEADER_SIZE;
34use crate::{
35    header::{PL_HEADER_SIZE},
36    proto_data::RpcId,
37    rpc::{RPC_MIN_SIZE, Rpc, setup_rpc},
38};
39// use crate::esp_errors::EspCode;
40
41pub use crate::rpc::*;
42
43#[macro_export]
44macro_rules! parse_le {
45    ($bytes:expr, $t:ty, $range:expr) => {{ <$t>::from_le_bytes($bytes[$range].try_into().unwrap()) }};
46}
47
48#[macro_export]
49macro_rules! copy_le {
50    ($dest:expr, $src:expr, $range:expr) => {{ $dest[$range].copy_from_slice(&$src.to_le_bytes()) }};
51}
52
53const AP_BUF_MAX: usize = 100;
54const BLE_BUF_MAX: usize = 100;
55
56const ESP_ERR_HOSTED_BASE: u16 = 0x2f00;
57
58const MORE_FRAGMENT: u8 = 1 << 0; // todo type and if we use it.
59
60const FRAME_LEN_TX: usize = HEADER_SIZE + RPC_MIN_SIZE + 300; // todo: A/R
61// const DATA_LEN_TX: usize = 200; // todo: A/R
62
63static mut TX_BUF: [u8; FRAME_LEN_TX] = [0; FRAME_LEN_TX];
64// static mut DATA_BUF: [u8; DATA_LEN_TX] = [0; DATA_LEN_TX];
65
66/// A simple error enum for our host-side protocol
67#[derive(Format)]
68pub enum EspError {
69    // #[cfg(feature = "hal")]
70    // Uart(UartError),
71    /// e.g. uart, spi etc.
72    Comms,
73    UnexpectedResponse(u8),
74    CrcMismatch,
75    Timeout,
76    InvalidData,
77    // todo: Put back. flash limit problem.
78    // Esp(EspCode),
79}
80
81// #[cfg(feature = "hal")]
82// impl From<UartError> for EspError {
83//     fn from(e: UartError) -> Self {
84//         EspError::Uart(e)
85//     }
86// }
87
88
89pub fn cfg_heartbeat<W>(mut write: W, uid: u32, cfg: &RpcReqConfigHeartbeat) -> Result<(), EspError>
90// todo: Typedef this if able. (Unstable feature)
91where
92    W: FnMut(&[u8]) -> Result<(), EspError>,
93{
94    let rpc = Rpc::new_req(RpcId::ReqConfigHeartbeat, uid);
95
96    let mut data = [0; 5]; // Seems to be 4 in for small duration values.
97    let data_size = cfg.to_bytes(&mut data);
98
99    unsafe {
100        let frame_len = setup_rpc(&mut TX_BUF, &rpc, &data[..data_size]);
101        write(&TX_BUF[..frame_len])?;
102    }
103
104    Ok(())
105}
106
107pub struct ParsedMsg<'a> {
108    pub header: PayloadHeader,
109    pub rpc: Rpc,
110    pub data: &'a[u8],
111    pub rpc_proto: RpcP,
112}
113
114/// Parse the payload header, and separate the RPC bytes from the whole message. Accepts
115/// the whole message received.
116// pub fn parse_msg(buf: &[u8]) -> Result<(PayloadHeader, Rpc, &[u8], RpcP), EspError> {
117pub fn parse_msg(buf: &[u8]) -> Result<ParsedMsg, EspError> {
118    let header = PayloadHeader::from_bytes(&buf[..HEADER_SIZE])?;
119    let total_size = header.len as usize + PL_HEADER_SIZE;
120
121    if total_size > buf.len() {
122        return Err(EspError::InvalidData);
123    }
124
125    let rpc_buf = &buf[HEADER_SIZE..total_size];
126
127    let (rpc, data_start_i, data_len_rpc) = Rpc::from_bytes(rpc_buf)?;
128
129    // Parsing the proto data directly.
130    let mut decoder = PbDecoder::new(rpc_buf);
131
132    let mut rpc_proto = RpcP::default();
133    rpc_proto.decode(&mut decoder, rpc_buf.len()).map_err(|_| EspError::InvalidData)?;
134
135    let data = &rpc_buf[data_start_i..];
136
137    if data.len() == 2 {
138        // todo: Ideally we return an error, but I'm not sure how to confirm that this
139        // todo value truly is just for errors.
140        let err = decode_varint(data)?.0 as u16;
141
142        // todo: Flash limit problem.
143        // if let Ok(e) = TryInto::<EspCode>::try_into(err) {
144        // println!("Esp error: {:?}", e);
145    }
146
147    Ok(ParsedMsg { header, rpc, data, rpc_proto    })
148}