Skip to main content

device_envoy_esp/wifi_auto/
fields.rs

1//! A device abstraction for extra setup fields used by [`WifiAutoEsp`](crate::wifi_auto::WifiAutoEsp).
2//!
3//! See the [`WifiAutoEsp` struct example](crate::wifi_auto::WifiAutoEsp) for the full setup.
4//!
5//! This module provides ready-to-use field types that can be passed to
6//! [`WifiAutoEsp::new`](crate::wifi_auto::WifiAutoEsp::new) for collecting additional
7//! configuration beyond WiFi credentials.
8//!
9//! There are two levels of customization:
10//!
11//! 1. Use built-in helpers like [`TextField`] and [`TimezoneField`].
12//! 2. Define your own field type by implementing [`WifiAutoField`]. See example there.
13//!
14//! # Example
15//!
16//! ```rust,no_run
17//! # #![no_std]
18//! # #![no_main]
19//! use device_envoy_esp::{
20//!     Error, Result,
21//!     button::{ButtonEsp, PressedTo},
22//!     flash_block::FlashBlockEsp,
23//!     wifi_auto::{WifiAuto as _, WifiAutoEvent, WifiAutoEsp},
24//!     wifi_auto::fields::{TextField, TextFieldStatic, TimezoneField, TimezoneFieldStatic},
25//! };
26//!
27//! async fn example(
28//!     spawner: embassy_executor::Spawner,
29//!     p: esp_hal::peripherals::Peripherals,
30//! ) -> Result<()> {
31//!     let mut button6 = ButtonEsp::new(p.GPIO6, PressedTo::Ground);
32//!     let [wifi_flash, website_flash, timezone_flash] = FlashBlockEsp::new_array::<3>(p.FLASH)?;
33//!
34//!     static WEBSITE_STATIC: TextFieldStatic<32> = TextField::new_static();
35//!     let website_field = TextField::new(
36//!         &WEBSITE_STATIC,
37//!         website_flash,
38//!         "website",
39//!         "Website",
40//!         "google.com",
41//!     );
42//!
43//!     static TIMEZONE_STATIC: TimezoneFieldStatic = TimezoneField::new_static();
44//!     let timezone_field = TimezoneField::new(&TIMEZONE_STATIC, timezone_flash);
45//!
46//!     let wifi_auto = WifiAutoEsp::new(
47//!         p.WIFI,
48//!         wifi_flash,
49//!         "DeviceEnvoySetup",
50//!         [website_field, timezone_field],
51//!         spawner,
52//!     )?;
53//!
54//!     let _stack = wifi_auto
55//!         .connect(&mut button6, |wifi_auto_event| async move {
56//!             match wifi_auto_event {
57//!                 WifiAutoEvent::CaptivePortalReady => {}
58//!                 WifiAutoEvent::Connecting { .. } => {}
59//!                 WifiAutoEvent::ConnectionFailed => {}
60//!             }
61//!             Ok(())
62//!         })
63//!         .await?;
64//!
65//!     let _website = website_field.text()?.unwrap_or_default();
66//!     let _offset_minutes = timezone_field
67//!         .offset_minutes()?
68//!         .ok_or(Error::MissingCustomWifiAutoField)?;
69//!
70//!     Ok(())
71//! }
72//! ```
73
74#![allow(
75    unsafe_code,
76    reason = "unsafe impl Sync is sound: single-threaded Embassy executor, no concurrent access"
77)]
78
79#[cfg(target_os = "none")]
80use crate::flash_block::FlashBlockEsp;
81use crate::Error;
82use device_envoy_core::__impl_wifi_auto_fields;
83use device_envoy_core::wifi_auto::{FormData, HtmlBuffer, WifiAutoField};
84
85__impl_wifi_auto_fields!(
86    flash_block = FlashBlockEsp,
87    error = Error,
88    wifi_auto_field = WifiAutoField,
89    form_data = FormData<'_>,
90    html_buffer = HtmlBuffer,
91    flash_cfg = target_os = "none"
92);
93
94#[cfg(target_os = "none")]
95impl TimezoneField {
96    /// Initialize a timezone field backed by a flash block.
97    ///
98    /// See the [WifiAutoEsp struct example](crate::wifi_auto::WifiAutoEsp) for usage.
99    pub fn new(
100        timezone_field_static: &'static TimezoneFieldStatic,
101        timezone_flash_block: FlashBlockEsp,
102    ) -> &'static Self {
103        Self::new_with_flash(timezone_field_static, timezone_flash_block)
104    }
105}
106
107#[cfg(not(target_os = "none"))]
108impl TimezoneField {
109    /// Initialize a timezone field backed by in-memory state.
110    ///
111    /// See the [WifiAutoEsp struct example](crate::wifi_auto::WifiAutoEsp) for usage.
112    pub fn new(timezone_field_static: &'static TimezoneFieldStatic) -> &'static Self {
113        Self::new_in_memory(timezone_field_static)
114    }
115}
116
117#[cfg(target_os = "none")]
118impl<const N: usize> TextField<N> {
119    /// Initialize a text field backed by a flash block.
120    ///
121    /// See the [WifiAutoEsp struct example](crate::wifi_auto::WifiAutoEsp) for usage.
122    pub fn new(
123        text_field_static: &'static TextFieldStatic<N>,
124        text_flash_block: FlashBlockEsp,
125        field_name: &'static str,
126        label: &'static str,
127        default_value: &'static str,
128    ) -> &'static Self {
129        Self::new_with_flash(
130            text_field_static,
131            text_flash_block,
132            field_name,
133            label,
134            default_value,
135        )
136    }
137}
138
139#[cfg(not(target_os = "none"))]
140impl<const N: usize> TextField<N> {
141    /// Initialize a text field backed by in-memory state.
142    ///
143    /// See the [WifiAutoEsp struct example](crate::wifi_auto::WifiAutoEsp) for usage.
144    pub fn new(
145        text_field_static: &'static TextFieldStatic<N>,
146        field_name: &'static str,
147        label: &'static str,
148        default_value: &'static str,
149    ) -> &'static Self {
150        Self::new_in_memory(text_field_static, field_name, label, default_value)
151    }
152}