Skip to main content

ssh_stamp/
platform.rs

1// SPDX-FileCopyrightText: 2026 Roman Valls Guimera <brainstorm@nopcode.org>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5//! Platform services abstraction.
6//!
7//! The HSM and SSH handlers call into the running platform for three
8//! things that can't be expressed as a pure HAL trait (because they touch
9//! app-layer state like [`SSHStampConfig`] or the serial bridge):
10//!
11//! * persisting the SSH-stamp config to non-volatile storage,
12//! * resetting the device,
13//! * minting an [`OtaActions`] writer for the SFTP OTA session,
14//! * signalling the serial bridge that SSH is ready and the UART task
15//!   should wake up.
16//!
17//! Each platform crate provides one impl (for ESP32: `EspPlatform`).
18//! Consumers take `&impl PlatformServices` so the same app code runs on
19//! every MCU port.
20
21use core::future::Future;
22
23use ssh_stamp_hal::{HalError, OtaActions};
24
25use crate::config::SSHStampConfig;
26
27/// Platform-owned services the app layer cannot provide on its own.
28///
29/// # Contract
30///
31/// * [`Self::save_config`] must be durable: after it returns `Ok(())` the
32///   config must survive a reboot.
33/// * [`Self::reset`] must not return.
34/// * [`Self::ota_writer`] may be called multiple times; each call yields
35///   a fresh writer suitable for a single OTA session.
36/// * [`Self::activate_uart`] signals the platform's buffered UART task
37///   (if any) that it is OK to start streaming. Idempotent.
38pub trait PlatformServices {
39    /// OTA writer type this platform provides. Must live for the whole
40    /// SFTP session, so `'static` is required.
41    type OtaWriter: OtaActions + 'static;
42
43    /// Buffered CAN type this platform provides. The CAN pump task owns
44    /// it for the lifetime of the device, so `'static` is required.
45    #[cfg(feature = "can")]
46    type Can: crate::can::BufferedCan + 'static;
47
48    /// Access the platform's buffered CAN interface for the SSH `can`
49    /// subsystem bridge.
50    #[cfg(feature = "can")]
51    fn can(&self) -> &'static Self::Can;
52
53    /// Persist the full config to non-volatile storage.
54    ///
55    /// # Errors
56    ///
57    /// Returns `HalError::Flash` on write / erase failure.
58    fn save_config(&self, config: &SSHStampConfig) -> impl Future<Output = Result<(), HalError>>;
59
60    /// Reset the device. Does not return.
61    fn reset(&self) -> !;
62
63    /// Construct a fresh OTA writer for a new SFTP OTA session.
64    fn ota_writer(&self) -> Self::OtaWriter;
65
66    /// Signal the platform's buffered UART task that SSH is ready and
67    /// UART transfer may start. Idempotent.
68    fn activate_uart(&self);
69}