#![no_std]
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(static_mut_refs)]
pub mod header;
pub mod proto_data;
mod rpc;
mod transport;
pub mod wifi;
pub mod ble;
mod esp_errors;
pub mod proto;
mod util;
use defmt::{Format, println};
pub use esp_errors::EspCode;
pub use header::{PayloadHeader, build_frame_ble};
use micropb::{MessageDecode, PbDecoder};
pub use proto::{Rpc as RpcP, RpcId as RpcIdP, RpcType as RpcTypeP};
pub use proto_data::RpcId;
pub use transport::PacketType;
pub use crate::rpc::*;
use crate::{
header::{HEADER_SIZE, InterfaceType, PL_HEADER_SIZE},
proto_data::RpcReqConfigHeartbeat,
};
#[macro_export]
macro_rules! parse_le {
($bytes:expr, $t:ty, $range:expr) => {{ <$t>::from_le_bytes($bytes[$range].try_into().unwrap()) }};
}
#[macro_export]
macro_rules! copy_le {
($dest:expr, $src:expr, $range:expr) => {{ $dest[$range].copy_from_slice(&$src.to_le_bytes()) }};
}
const AP_BUF_MAX: usize = 100;
const BLE_BUF_MAX: usize = 100;
const ESP_ERR_HOSTED_BASE: u16 = 0x2f00;
#[derive(Format)]
pub enum EspError {
Comms,
UnexpectedResponse(u8),
CrcMismatch,
Timeout,
InvalidData,
Proto,
Capacity,
Esp(EspCode),
}
pub fn cfg_heartbeat<W>(
buf: &mut [u8],
mut write: W,
uid: u32,
cfg: &RpcReqConfigHeartbeat,
) -> Result<(), EspError>
where
W: FnMut(&[u8]) -> Result<(), EspError>,
{
let rpc = Rpc::new_req(RpcId::ReqConfigHeartbeat, uid);
let mut data = [0; 5]; let data_size = cfg.to_bytes(&mut data);
let frame_len = setup_rpc(buf, &rpc, &data[..data_size]);
write(&buf[..frame_len])?;
Ok(())
}
pub struct WifiMsg<'a> {
pub header: PayloadHeader,
pub rpc: Rpc,
pub data: &'a [u8],
pub rpc_parsed: Result<RpcP, EspError>,
}
pub struct HciMsg<'a> {
pub data: &'a [u8],
}
pub enum MsgParsed<'a> {
Wifi(WifiMsg<'a>),
Hci(HciMsg<'a>),
}
pub fn parse_msg_header_not_read(buf: &[u8]) -> Result<MsgParsed, EspError> {
if buf[0] > 8 || buf[0] == 0 {
const MAX_SHIFT: usize = 6;
for offset in 1..MAX_SHIFT {
if buf[offset..offset + 2] == [12, 0] && buf[offset + 6..offset + 9] == [0, 0, 4] {
let shift = 4 - offset;
return Ok(MsgParsed::Hci(HciMsg {
data: &buf[PL_HEADER_SIZE - shift..],
}));
}
}
for offset in 1..16 {
if offset + 3 >= buf.len() {
return Err(EspError::InvalidData);
}
if buf[offset..offset + 3] == [0, 4, 62] {
let shift = 9 - offset;
return Ok(MsgParsed::Hci(HciMsg {
data: &buf[PL_HEADER_SIZE - shift..],
}));
}
}
}
let mut header = PayloadHeader::from_bytes(&buf[..HEADER_SIZE])?;
let mut total_size = header.len as usize + PL_HEADER_SIZE;
if total_size > buf.len() {
return Err(EspError::Capacity);
}
if header.if_type == InterfaceType::Hci {
return Ok(MsgParsed::Hci(HciMsg {
data: &buf[PL_HEADER_SIZE..],
}));
}
if HEADER_SIZE >= total_size {
println!(
"Error: Invalid RPC packet. packet size: {}, buf: {:?}",
total_size,
buf[0..24]
);
return Err(EspError::InvalidData);
}
let rpc_buf = &buf[HEADER_SIZE..total_size];
let (rpc, data_start_i, _data_len_rpc) = Rpc::from_bytes(rpc_buf)?;
let data = &rpc_buf[data_start_i..];
let mut decoder = PbDecoder::new(rpc_buf);
let mut rpc_parsed = RpcP::default();
let rpc_parsed = match rpc_parsed.decode(&mut decoder, rpc_buf.len()) {
Ok(r) => Ok(rpc_parsed),
Err(e) => Err(EspError::Proto),
};
Ok(MsgParsed::Wifi(WifiMsg {
header,
rpc,
data,
rpc_parsed,
}))
}
pub fn parse_msg_header_read(buf: &[u8], header: PayloadHeader) -> Result<MsgParsed, EspError> {
let mut total_size = header.len as usize;
if total_size > buf.len() {
return Err(EspError::Capacity);
}
if header.if_type == InterfaceType::Hci {
return Ok(MsgParsed::Hci(HciMsg { data: &buf[..] }));
}
let rpc_buf = &buf[..total_size];
let (rpc, data_start_i, _data_len_rpc) = Rpc::from_bytes(rpc_buf)?;
let data = &rpc_buf[data_start_i..];
println!("RPC read: {:?}", rpc);
let mut decoder = PbDecoder::new(rpc_buf);
let mut rpc_parsed = RpcP::default();
let rpc_parsed = match rpc_parsed.decode(&mut decoder, rpc_buf.len()) {
Ok(r) => Ok(rpc_parsed),
Err(e) => Err(EspError::Proto),
};
Ok(MsgParsed::Wifi(WifiMsg {
header,
rpc,
data,
rpc_parsed,
}))
}