#![no_std]
#![no_main]
extern crate alloc;
use embassy_executor::Spawner;
use heapless::String;
use log::{debug, error, warn};
use ssh_stamp::config::{SSHStampConfig, UartPins};
use ssh_stamp::platform::PlatformServices;
use ssh_stamp::store;
use ssh_stamp::{
app,
mem_probe::{self, Checkpoint},
settings::DEFAULT_IP,
};
#[cfg(feature = "can")]
use ssh_stamp_esp32::{BufferedCan, CAN_BUF, EspCanPins, can_task};
use ssh_stamp_esp32::{
EspPlatform, EspUartPins, EspWifi, bench, entropy_source_active, flash, mac_address,
spawn_uart, start_interrupt_executor,
};
use ssh_stamp_esp32_boards::Board;
use ssh_stamp_hal::{HalError, WifiError};
use ssh_stamp_hal::{NetworkProviderHal, WifiHal};
use static_cell::StaticCell;
use sunset_async::SunsetMutex;
#[esp_rtos::main]
async fn main(spawner: Spawner) -> ! {
ssh_stamp_esp32::boot!(peripherals, rng, entropy_source, sw_int1);
#[cfg(feature = "sftp-ota")]
{
use ssh_stamp_hal::OtaActions;
ssh_stamp_esp32::EspOtaWriter::try_validating_current_ota_partition()
.await
.expect("Failed to validate the current ota partition");
}
ssh_stamp_esp32_boards::select_board!();
debug!("Active board: {}", B::NAME);
let (rx_pin, tx_pin, rx_num, tx_num) = ssh_stamp_esp32_boards::take_uart_pins!(peripherals);
let pins = EspUartPins {
rx: rx_pin,
tx: tx_pin,
};
let uart_pins = UartPins {
rx: rx_num,
tx: tx_num,
};
debug_assert!(
entropy_source_active(),
"entropy source was disabled before host key generation"
);
debug!("Loading config");
let flash_config = {
let Some(flash_storage_guard) = flash::get_flash_n_buffer() else {
panic!("Could not acquire flash storage lock");
};
let mut fb = flash_storage_guard.lock().await;
let (flash_storage, buf) = fb.split_ref_mut();
store::load_or_create(flash_storage, buf, mac_address(), uart_pins)
}
.expect(
"Stored config is present but invalid; refusing to overwrite it. \
Erase the config sector (espflash erase-region 0x9000 0x1000) to reprovision.",
);
let uart_params = flash_config.uart_params;
static CONFIG: StaticCell<SunsetMutex<SSHStampConfig>> = StaticCell::new();
let config: &'static SunsetMutex<SSHStampConfig> = CONFIG.init(SunsetMutex::new(flash_config));
mem_probe::checkpoint(Checkpoint::Boot);
let interrupt_spawner = start_interrupt_executor(sw_int1);
let uart_buf = spawn_uart(interrupt_spawner, peripherals.UART1, pins, uart_params);
#[cfg(feature = "can")]
let can_buf: &'static BufferedCan = {
ssh_stamp_esp32_boards::setup_can_transceiver!(peripherals);
let can_pins = ssh_stamp_esp32_boards::take_can_pins!(peripherals);
let can_pins = EspCanPins {
tx: can_pins.0,
rx: can_pins.1,
};
let can_buf = CAN_BUF.init_with(BufferedCan::new);
interrupt_spawner
.spawn(can_task(can_buf, peripherals.TWAI0, can_pins).expect("can_task spawn failed"));
can_buf
};
#[cfg(feature = "can")]
let platform = EspPlatform::new(can_buf);
#[cfg(not(feature = "can"))]
let platform = EspPlatform::new();
mem_probe::checkpoint(Checkpoint::PeripheralsReady);
bench::log_heap("peripherals");
debug!("Initialising radio");
let ap_config = app::prepare_ap_config(config, &platform)
.await
.expect("Failed to prepare AP config");
drop(entropy_source);
let mut wifi = EspWifi::new(spawner, peripherals.WIFI, rng, DEFAULT_IP);
wifi.configure_ap(ap_config)
.expect("Failed to configure AP");
let stack = wifi.bring_up().await;
match stack {
Ok(_) => (),
Err(ref e) => {
warn!("Failed to bring up WiFi");
if let HalError::Wifi(WifiError::StationMode) = e {
let mut config_guard = config.lock().await;
config_guard.wifi_sta_ssid = String::<32>::new();
let _ = platform.save_config(&config_guard).await;
warn!("Station Mode failed to connect. Rebooting into Access Point mode...");
platform.reset();
}
}
}
mem_probe::checkpoint(Checkpoint::WifiUp);
bench::log_heap("wifi_up");
debug_assert!(
entropy_source_active(),
"no entropy source active after WiFi came up"
);
if let Err(e) = app::run_app(stack.unwrap(), uart_buf, config, &platform).await {
error!("run_app exited with error: {e}");
}
warn!("End of main, resetting");
esp_hal::system::software_reset();
}
ssh_stamp_esp32::getrandom_backend!();
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}