seeed_erpc/
lib.rs

1#![no_std]
2use heapless::String;
3use no_std_net::Ipv4Addr;
4
5#[macro_use]
6extern crate bitflags;
7
8mod codec;
9mod ids;
10
11/// Encapsulates errors that might occur when issuing or processing eRPCs.
12#[derive(Debug, Clone, PartialEq)]
13pub enum Err<E> {
14    /// Parsing via the nom crate indicated an error
15    Parsing(nom::Err<()>),
16    /// The CRC was wrong
17    CRCMismatch,
18    /// There was an issue while transmitting
19    TXErr,
20    /// The response we were given to parse was for a different (callback,
21    /// probably) RPC.
22    NotOurs,
23    /// There was an RPC-specific error.
24    RPCErr(E),
25    /// Too much data was present in the response
26    ResponseOverrun,
27    Unknown,
28}
29
30impl<E> From<nom::Err<()>> for Err<E> {
31    fn from(nom_err: nom::Err<()>) -> Self {
32        Err::Parsing::<E>(nom_err)
33    }
34}
35
36pub use codec::{FrameHeader, Header};
37
38/// Describes an RPC used by the system.
39pub trait RPC {
40    type ReturnValue;
41    type Error;
42
43    fn header(&self, seq: u32) -> Header;
44    fn args(&self, _buff: &mut heapless::Vec<u8, 64>) {}
45
46    fn parse(&mut self, data: &[u8]) -> Result<Self::ReturnValue, Err<Self::Error>>;
47}
48
49mod system_rpcs;
50mod tcpip_rpcs;
51mod wifi_rpcs;
52
53/// The RPCs which can be called to control the wifi.
54pub mod rpcs {
55    pub use crate::system_rpcs::*;
56    pub use crate::tcpip_rpcs::*;
57    pub use crate::wifi_rpcs::*;
58}
59
60/// Specifies a layer 3 interface to be affected by the command.
61#[derive(Debug, Clone, Copy)]
62#[repr(u32)]
63pub enum L3Interface {
64    Station = 0,
65    AP = 1,
66}
67
68/// Possible modes of the Wifi PHY.
69#[derive(Debug, Copy, Clone)]
70#[repr(u32)]
71pub enum WifiMode {
72    None = 0,
73    Station = 1,
74    AP = 2,
75    StationAndAP = 3,
76    Promiscuous = 4,
77    P2P = 5,
78}
79
80/// Describes the high-level type of a network.
81#[derive(Debug, Copy, Clone)]
82#[allow(dead_code)]
83#[repr(u32)]
84pub enum BssType {
85    Infra = 0,
86    Adhoc = 1,
87    Any = 2,
88    Unknown = core::u32::MAX,
89}
90
91impl From<u32> for BssType {
92    fn from(orig: u32) -> Self {
93        match orig {
94            0 => return BssType::Infra,
95            1 => return BssType::Adhoc,
96            2 => return BssType::Any,
97            _ => return BssType::Unknown,
98        };
99    }
100}
101
102bitflags! {
103    /// Specifies the security features of a network.
104    pub struct Security: u32 {
105        const WEP_ENABLED = 1;
106        const TKIP_ENABLED = 2;
107        const AES_ENABLED = 4;
108        const AES_CMAC_ENABLED = 0x10;
109        const SHARED_ENABLED = 0x00008000;
110        const WPA_SECURITY = 0x00200000;
111        const WPA2_SECURITY = 0x00400000;
112        const WPA3_SECURITY = 0x00800000;
113        const WPS_ENABLED = 0x10000000;
114        const WEP_PSK = Self::WEP_ENABLED.bits;
115        const WEP_SHARED = Self::WEP_ENABLED.bits | Self::SHARED_ENABLED.bits;
116        const WPA_TKIP_PSK = Self::WPA_SECURITY.bits | Self::TKIP_ENABLED.bits;
117        const WPA_AES_PSK = Self::WPA_SECURITY.bits | Self::AES_ENABLED.bits;
118        const WPA2_AES_PSK  = Self::WPA2_SECURITY.bits | Self::AES_ENABLED.bits;
119        const WPA2_TKIP_PSK = Self::WPA2_SECURITY.bits | Self::TKIP_ENABLED.bits;
120        const WPA2_MIXED_PSK = Self::WPA2_SECURITY.bits | Self::AES_ENABLED.bits | Self::TKIP_ENABLED.bits;
121        const WPA_WPA2_MIXED = Self::WPA_SECURITY.bits | Self::WPA2_SECURITY.bits;
122        const WPA2_AES_CMAC = Self::WPA2_SECURITY.bits | Self::AES_CMAC_ENABLED.bits;
123        const WPS_OPEN = Self::WPS_ENABLED.bits;
124        const WPS_SECURE = Self::WPS_ENABLED.bits | Self::AES_ENABLED.bits;
125        const WPS3_AES_PSK = Self::WPA3_SECURITY.bits | Self::AES_ENABLED.bits;
126    }
127}
128
129/// Valid WPS modes.
130#[derive(Debug, Copy, Clone)]
131#[allow(dead_code)]
132#[repr(u32)]
133pub enum WPS {
134    Default = 0x0000,
135    UserSpecifed = 0x0001,
136    MachineSpecified = 0x0002,
137    Rekey = 0x0003,
138    Pushbutton = 0x0004,
139    RegistrarSpecified = 0x0005,
140    None = 0x0006,
141    Wsc = 0x0007,
142    Unknown = 0xffff,
143}
144
145impl From<u32> for WPS {
146    fn from(orig: u32) -> Self {
147        match orig {
148            0 => return WPS::Default,
149            1 => return WPS::UserSpecifed,
150            2 => return WPS::MachineSpecified,
151            3 => return WPS::Rekey,
152            4 => return WPS::Pushbutton,
153            5 => return WPS::RegistrarSpecified,
154            6 => return WPS::None,
155            7 => return WPS::Wsc,
156            _ => return WPS::Unknown,
157        };
158    }
159}
160
161/// Valid wifi bands.
162#[derive(Debug, Copy, Clone, PartialEq)]
163#[allow(dead_code)]
164#[repr(u32)]
165pub enum Band {
166    _5Ghz = 0,
167    _24Ghz = 1,
168    Unknown = 0xffff,
169}
170
171impl From<u32> for Band {
172    fn from(orig: u32) -> Self {
173        match orig {
174            0 => return Band::_5Ghz,
175            1 => return Band::_24Ghz,
176            _ => return Band::Unknown,
177        };
178    }
179}
180
181/// The machine-readable network name (6-bytes).
182#[derive(Copy, Clone)]
183#[repr(packed)]
184pub struct BSSID(pub [u8; 6]);
185
186impl core::fmt::Debug for BSSID {
187    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
188        let table = b"0123456789abcdef";
189
190        let mut out = [0u8; 12 + 6 - 1];
191        for i in 0..(12 + 6 - 1) {
192            let b = self.0[i / 3];
193            out[i] = match (i + 1) % 3 {
194                0 => ':' as u8,
195                1 => table[(b >> 4) as usize],
196                2 => table[(b & 0xf) as usize],
197                _ => '?' as u8,
198            }
199        }
200
201        f.write_str(core::str::from_utf8(&out).unwrap())
202    }
203}
204
205/// A human-readable network name.
206#[derive(Copy, Clone)]
207#[repr(packed)]
208pub struct SSID {
209    len: u8,
210    value: [u8; 33],
211}
212
213impl core::fmt::Debug for SSID {
214    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215        // Unused unsafe warning is erroneous: needed for safe_packed_borrows
216        #[allow(unused_unsafe)]
217        unsafe {
218            f.write_str(core::str::from_utf8(&self.value[..self.len as usize]).unwrap())
219        }
220    }
221}
222
223impl<const N: usize> Into<String<N>> for SSID {
224    fn into(self) -> String<N> {
225        let mut out = String::new();
226        // Unused unsafe warning is erroneous: needed for safe_packed_borrows
227        #[allow(unused_unsafe)]
228        unsafe {
229            for i in 0..self.len as usize {
230                out.push(self.value[i] as char).ok();
231            }
232        }
233        out
234    }
235}
236
237/// Describes layer 3 (IP) configuration.
238#[derive(Debug, Clone)]
239pub struct IPInfo {
240    pub ip: Ipv4Addr,
241    pub netmask: Ipv4Addr,
242    pub gateway: Ipv4Addr,
243}