use defmt::{Format, Formatter, println};
use heapless::Vec;
use micropb::{MessageEncode, PbEncoder};
use num_enum::TryFromPrimitive;
pub use crate::proto_data::RpcId;
use crate::{
EspError, RpcP,
esp_errors::EspCode,
header::build_frame_wifi,
proto_data::EventHeartbeat,
transport::{RPC_EP_NAME_EVT, RPC_EP_NAME_RSP},
wifi::WifiApRecord,
};
pub(crate) const MAX_RPC_SIZE: usize = 500;
pub(crate) const RPC_MIN_SIZE: usize = 10;
pub enum RpcPayload {
EventHeartbeat(EventHeartbeat),
EventWifiScanGetApRecord(WifiApRecord),
EventWifiScanGetApRecords(Vec<WifiApRecord, 30>),
}
impl Format for RpcPayload {
fn format(&self, _fmt: Formatter<'_>) {
}
}
#[derive(Format)]
pub struct Rpc {
pub msg_type: RpcType,
pub msg_id: RpcId,
pub uid: u32,
pub payload: Option<RpcPayload>, }
impl Rpc {
pub fn new_req(msg_id: RpcId, uid: u32) -> Self {
Self {
msg_type: RpcType::Req,
msg_id,
uid,
payload: None,
}
}
pub fn to_bytes(&self, buf: &mut [u8], data: &[u8]) -> usize {
let mut i = 0;
let data_len = data.len();
write_rpc(buf, 1, WireType::Varint, self.msg_type as u64, &mut i);
write_rpc(buf, 2, WireType::Varint, self.msg_id as u64, &mut i);
write_rpc(buf, 3, WireType::Varint, self.uid as u64, &mut i);
write_rpc(
buf,
self.msg_id as u16,
WireType::Len,
data_len as u64,
&mut i,
);
buf[i..i + data_len].copy_from_slice(data);
i += data_len;
i
}
pub fn from_bytes(buf: &[u8]) -> Result<(Self, usize, usize), EspError> {
if buf.len() < 2 {
return Err(EspError::InvalidData);
}
let msg_type = buf[1].try_into().map_err(|_| EspError::InvalidData)?;
let (rpc_id, rpc_id_size) = decode_varint(&buf[3..])?;
let msg_id = (rpc_id as u16)
.try_into()
.map_err(|_| EspError::InvalidData)?;
let mut i = 3 + rpc_id_size;
let mut uid = 0; if buf[3 + rpc_id_size] == 16 {
i += 1; let (uid_, uid_size) = decode_varint(&buf[i..])?;
uid = uid_;
i += uid_size;
}
let result = Self {
msg_type,
msg_id,
uid: uid as u32,
payload: None, };
let (_data_tag, data_tag_size) = decode_varint(&buf[i..])?;
i += data_tag_size;
let (data_len, data_len_size) = decode_varint(&buf[i..])?;
i += data_len_size;
if data_len == 3 && buf[i] == 8 {
let (err_code, _) = decode_varint(&buf[i + 1..])?;
match EspCode::try_from(err_code as u16) {
Ok(c) => {
return Err(EspError::Esp(c));
}
Err(_) => (),
}
}
Ok((result, i, data_len as usize))
}
}
#[derive(Clone, Copy, Default, PartialEq, Format, TryFromPrimitive)]
#[repr(u8)]
pub enum WireType {
#[default]
Varint = 0,
I64 = 1,
Len = 2,
I32 = 5,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
#[repr(u8)]
pub(crate) enum Rpc_WifiBw {
BW_Invalid = 0,
HT20 = 1,
HT40 = 2,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
#[repr(u8)]
pub(crate) enum Rpc_WifiPowerSave {
PS_Invalid = 0,
MIN_MODEM = 1,
MAX_MODEM = 2,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
#[repr(u8)]
pub(crate) enum Rpc_WifiSecProt {
Open = 0,
WEP = 1,
WPA_PSK = 2,
WPA2_PSK = 3,
WPA_WPA2_PSK = 4,
WPA2_ENTERPRISE = 5,
WPA3_PSK = 6,
WPA2_WPA3_PSK = 7,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
#[repr(u8)]
pub(crate) enum Rpc_Status {
Connected = 0,
Not_Connected = 1,
No_AP_Found = 2,
Connection_Fail = 3,
Invalid_Argument = 4,
Out_Of_Range = 5,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
#[repr(u8)]
pub enum RpcType {
MsgType_Invalid = 0,
Req = 1,
Resp = 2,
Event = 3,
MsgType_Max = 4,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub(crate) enum EndpointType {
EndpointName = 0x01,
Data = 0x02,
}
#[derive(Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub(crate) enum RpcEndpoint {
CtrlResp,
CtrlEvent,
}
impl RpcEndpoint {
pub fn as_bytes(&self) -> &'static [u8] {
match self {
Self::CtrlResp => RPC_EP_NAME_RSP,
Self::CtrlEvent => RPC_EP_NAME_EVT,
}
.as_bytes()
}
}
pub fn setup_rpc(buf: &mut [u8], rpc: &Rpc, data: &[u8]) -> usize {
let mut rpc_buf = [0; MAX_RPC_SIZE];
let mut i = 0;
i += rpc.to_bytes(&mut rpc_buf, data);
build_frame_wifi(buf, &rpc_buf[..i])
}
pub fn setup_rpc_proto(buf: &mut [u8], message: RpcP) -> Result<usize, EspError> {
let mut rpc_buf = Vec::<u8, MAX_RPC_SIZE>::new();
let mut encoder = PbEncoder::new(&mut rpc_buf);
message.encode(&mut encoder).map_err(|_| EspError::Proto)?;
Ok(build_frame_wifi(buf, &rpc_buf[..rpc_buf.len()]))
}
pub fn write_rpc_proto<W>(buf: &mut [u8], mut write: W, msg: RpcP) -> Result<(), EspError>
where
W: FnMut(&[u8]) -> Result<(), EspError>,
{
let frame_len = setup_rpc_proto(buf, msg)?;
write(&buf[..frame_len])?;
Ok(())
}
pub(crate) fn write_rpc(buf: &mut [u8], field: u16, wire_type: WireType, val: u64, i: &mut usize) {
let tag = encode_tag(field, wire_type);
*i += encode_varint(tag as u64, &mut buf[*i..]);
*i += encode_varint(val, &mut buf[*i..]);
}
pub(crate) fn encode_tag(field: u16, wire_type: WireType) -> u16 {
(field << 3) | (wire_type as u16)
}
pub(crate) fn decode_tag(val: u16) -> (u16, WireType) {
(
val >> 3,
((val & 0b111) as u8).try_into().unwrap_or_default(),
)
}
pub(crate) fn encode_varint(mut v: u64, out: &mut [u8]) -> usize {
let mut idx = 0;
if out.len() == 0 {
println!("Error: Empty buf when encoding a varint."); return 0;
}
loop {
let byte = (v & 0x7F) as u8;
v >>= 7;
if v == 0 {
out[idx] = byte; idx += 1;
break;
} else {
out[idx] = byte | 0x80; idx += 1;
}
}
idx
}
pub(crate) fn decode_varint(input: &[u8]) -> Result<(u64, usize), EspError> {
let mut val = 0u64;
let mut shift = 0;
for (idx, &byte) in input.iter().enumerate() {
val |= ((byte & 0x7F) as u64) << shift;
if byte & 0x80 == 0 {
return Ok((val, idx + 1));
}
shift += 7;
}
Err(EspError::InvalidData)
}