ssh_stamp_hal/config.rs
1// SPDX-FileCopyrightText: 2026 Roman Valls Guimera <brainstorm@nopcode.org>
2// SPDX-FileCopyrightText: 2026 Julio Beltran Ortega <jubeormk1@gmail.com>
3// SPDX-FileCopyrightText: 2026 Anthony Tambasco <anthony.tambasco@fastmail.com>
4//
5// SPDX-License-Identifier: GPL-3.0-or-later
6
7//! Hardware configuration types.
8
9use core::str::FromStr;
10use heapless::String;
11
12/// UART parity bit setting.
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14pub enum Parity {
15 /// No parity bit (default).
16 #[default]
17 None,
18 /// Even parity.
19 Even,
20 /// Odd parity.
21 Odd,
22}
23
24impl FromStr for Parity {
25 type Err = ();
26
27 /// Parses a parity setting from a string value.
28 ///
29 /// Accepts `"none"`/`"n"`, `"even"`/`"e"` or `"odd"`/`"o"` (case-insensitive).
30 fn from_str(value: &str) -> Result<Self, Self::Err> {
31 if value.eq_ignore_ascii_case("none") || value.eq_ignore_ascii_case("n") {
32 Ok(Self::None)
33 } else if value.eq_ignore_ascii_case("even") || value.eq_ignore_ascii_case("e") {
34 Ok(Self::Even)
35 } else if value.eq_ignore_ascii_case("odd") || value.eq_ignore_ascii_case("o") {
36 Ok(Self::Odd)
37 } else {
38 Err(())
39 }
40 }
41}
42
43impl From<u8> for Parity {
44 /// Resolves a `Parity` from its on-wire `u8` representation.
45 ///
46 /// Unknown values fall back to `None` (the default).
47 fn from(value: u8) -> Self {
48 match value {
49 1 => Self::Even,
50 2 => Self::Odd,
51 _ => Self::None,
52 }
53 }
54}
55
56/// UART line parameters for the SSH-to-serial bridge.
57///
58/// Persisted in the device config and applied when the bridge's UART is
59/// brought up, so changes take effect on the next boot. Values are kept
60/// target-agnostic; each port maps them onto its own UART driver types.
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub struct UartParams {
63 /// Baud rate in bits per second.
64 pub baud: u32,
65 /// Data bits per frame (5-8).
66 pub data_bits: u8,
67 /// Parity bit setting.
68 pub parity: Parity,
69 /// Stop bits per frame (1 or 2).
70 pub stop_bits: u8,
71}
72
73impl Default for UartParams {
74 /// The classic 115200 8N1.
75 fn default() -> Self {
76 Self {
77 baud: 115_200,
78 data_bits: 8,
79 parity: Parity::None,
80 stop_bits: 1,
81 }
82 }
83}
84
85/// UART peripheral configuration.
86///
87/// Pin numbers (`tx_pin`, `rx_pin`) are target-specific and must be set by
88/// the port binary before use. There are no cross-platform default values;
89/// each port crate defines pin assignments in its `src/bin/` entry point.
90/// See the `ssh-stamp-esp32` binary's module documentation for ESP32 defaults.
91#[derive(Clone, Debug, Default)]
92pub struct UartConfig {
93 pub tx_pin: u8,
94 pub rx_pin: u8,
95 pub cts_pin: Option<u8>,
96 pub rts_pin: Option<u8>,
97 pub params: UartParams,
98}
99
100/// `WiFi` band mode for the access point.
101///
102/// Selects whether the AP operates on 2.4GHz, 5GHz, or both.
103/// Only the ESP32-C5 supports 5GHz; other chips ignore the setting
104/// and always operate on 2.4GHz.
105#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
106pub enum BandMode {
107 /// 2.4 GHz only (default, supported by all ESP32 variants).
108 #[default]
109 Band2_4G,
110 /// 5 GHz only (ESP32-C5 only).
111 Band5G,
112 /// Dual-band 2.4 GHz + 5 GHz (ESP32-C5 only).
113 Auto,
114}
115
116impl FromStr for BandMode {
117 type Err = ();
118
119 /// Parses a `WiFi` band mode from a string value.
120 ///
121 /// Accepts `"2.4g"`, `"2g"`, `"24g"`, `"5g"`, or `"auto"` (case-insensitive).
122 fn from_str(value: &str) -> Result<Self, Self::Err> {
123 if value.eq_ignore_ascii_case("2.4g")
124 || value.eq_ignore_ascii_case("2g")
125 || value.eq_ignore_ascii_case("24g")
126 {
127 Ok(Self::Band2_4G)
128 } else if value.eq_ignore_ascii_case("5g") {
129 Ok(Self::Band5G)
130 } else if value.eq_ignore_ascii_case("auto") {
131 Ok(Self::Auto)
132 } else {
133 Err(())
134 }
135 }
136}
137
138impl From<u8> for BandMode {
139 /// Resolves a `BandMode` from its on-wire `u8` representation.
140 ///
141 /// Unknown values fall back to `Band2_4G` (the default).
142 fn from(value: u8) -> Self {
143 match value {
144 1 => Self::Band5G,
145 2 => Self::Auto,
146 _ => Self::Band2_4G,
147 }
148 }
149}
150
151/// `WiFi` access point configuration.
152///
153/// Contains settings for running the device as a `WiFi` access point.
154#[derive(Clone, Debug)]
155pub struct WifiApConfigStatic {
156 /// Wifi Mode - Access Point (ap) or Station (sta) Mode. Access Point by default.
157 /// Network name (SSID), max 32 characters.
158 pub ap_ssid: String<32>,
159 pub sta_ssid: String<32>,
160 /// Mandatory `WiFi` password, max 63 characters.
161 /// We don't want None here as it would present an open network,
162 /// which is not something we want to support.
163 pub ap_password: String<63>,
164 pub sta_password: String<63>,
165 /// `WiFi` channel (1-14 for 2.4GHz, 36+ for 5GHz).
166 pub channel: u8,
167 /// `WiFi` band mode (2.4GHz / 5GHz / Auto). Ignored on chips without 5GHz.
168 pub band: BandMode,
169 /// MAC address for the access point interface.
170 pub mac: [u8; 6],
171}
172
173impl Default for WifiApConfigStatic {
174 fn default() -> Self {
175 Self {
176 ap_ssid: String::new(),
177 ap_password: String::new(),
178 sta_ssid: String::new(),
179 sta_password: String::new(),
180 channel: 1,
181 band: BandMode::default(),
182 mac: [0; 6],
183 }
184 }
185}