mirror of
https://github.com/stakwork/sphinx-key.git
synced 2025-12-17 07:14:23 +01:00
update all esp-idf and embedded-svc deps, build and test
This commit is contained in:
12
README.md
12
README.md
@@ -8,6 +8,14 @@ A Lightning Hardware Wallet based on [Validating Lightning Signer](https://gitla
|
|||||||
|
|
||||||
`cargo build --release`
|
`cargo build --release`
|
||||||
|
|
||||||
|
Find your port (`ls /dev/tty.*`)
|
||||||
|
|
||||||
|
`PORT=/dev/tty.usbserial-1420`
|
||||||
|
|
||||||
|
`espflash $PORT target/riscv32imc-esp-espidf/release/sphinx-key-factory`
|
||||||
|
|
||||||
|
`esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-key-factory`
|
||||||
|
|
||||||
### build
|
### build
|
||||||
|
|
||||||
`cd ../sphinx-key`
|
`cd ../sphinx-key`
|
||||||
@@ -24,10 +32,6 @@ The wifi SSID and password needs to be in env to build the firmware. SSID must b
|
|||||||
|
|
||||||
`esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-key`
|
`esptool.py --chip esp32c3 elf2image target/riscv32imc-esp-espidf/release/sphinx-key`
|
||||||
|
|
||||||
Find your port (`ls /dev/tty.*`)
|
|
||||||
|
|
||||||
`PORT=/dev/tty.usbserial-1420`
|
|
||||||
|
|
||||||
`esptool.py --chip esp32c3 -p $PORT -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x10000 target/riscv32imc-esp-espidf/release/sphinx-key.bin`
|
`esptool.py --chip esp32c3 -p $PORT -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x10000 target/riscv32imc-esp-espidf/release/sphinx-key.bin`
|
||||||
|
|
||||||
### monitor
|
### monitor
|
||||||
|
|||||||
875
factory/Cargo.lock
generated
875
factory/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,11 +8,11 @@ edition = "2021"
|
|||||||
pio = ["esp-idf-sys/pio"]
|
pio = ["esp-idf-sys/pio"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
esp-idf-sys = { version = "0.31.8", features = ["binstart"] }
|
esp-idf-sys = { version = "0.32.1", features = ["binstart"] }
|
||||||
esp-idf-svc = { version = "0.42.3", features = ["experimental", "alloc"] }
|
esp-idf-svc = { version = "0.45.0", features = ["experimental", "alloc"] }
|
||||||
esp-idf-hal = "0.38.1"
|
esp-idf-hal = "0.40.1"
|
||||||
|
embedded-svc = "0.24.0"
|
||||||
embedded-hal = "0.2.7"
|
embedded-hal = "0.2.7"
|
||||||
embedded-svc = "0.22.1"
|
|
||||||
anyhow = { version = "1.0.65", features = ["backtrace"] }
|
anyhow = { version = "1.0.65", features = ["backtrace"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
|||||||
@@ -1,33 +1,35 @@
|
|||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
use esp_idf_hal::delay::Ets;
|
use esp_idf_hal::delay::Ets;
|
||||||
|
use esp_idf_hal::delay::FreeRtos;
|
||||||
use esp_idf_hal::peripherals::Peripherals;
|
use esp_idf_hal::peripherals::Peripherals;
|
||||||
use esp_idf_hal::rmt::config::TransmitConfig;
|
use esp_idf_hal::rmt::config::TransmitConfig;
|
||||||
use esp_idf_hal::rmt::{FixedLengthSignal, PinState, Pulse, Transmit};
|
use esp_idf_hal::rmt::*;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub fn set_ota_led() {
|
pub fn set_ota_led() -> anyhow::Result<()> {
|
||||||
let peripherals = Peripherals::take().unwrap();
|
let peripherals = Peripherals::take().unwrap();
|
||||||
let led = peripherals.pins.gpio0.into_output().unwrap();
|
let led = peripherals.pins.gpio0;
|
||||||
let channel = peripherals.rmt.channel0;
|
let channel = peripherals.rmt.channel0;
|
||||||
let config = TransmitConfig::new().clock_divider(1);
|
let config = TransmitConfig::new().clock_divider(1);
|
||||||
let mut tx = Transmit::new(led, channel, &config).unwrap();
|
let mut tx = TxRmtDriver::new(channel, led, &config).unwrap();
|
||||||
|
|
||||||
let rgb = 0xffa500; // Orange
|
neopixel(
|
||||||
|
RGB {
|
||||||
|
r: 255,
|
||||||
|
g: 55,
|
||||||
|
b: 00,
|
||||||
|
},
|
||||||
|
&mut tx,
|
||||||
|
)?;
|
||||||
|
FreeRtos::delay_ms(10);
|
||||||
|
|
||||||
let ticks_hz = tx.counter_clock().unwrap();
|
Ok(())
|
||||||
let t0h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(350)).unwrap();
|
}
|
||||||
let t0l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(800)).unwrap();
|
|
||||||
let t1h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(700)).unwrap();
|
|
||||||
let t1l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(600)).unwrap();
|
|
||||||
|
|
||||||
let mut signal = FixedLengthSignal::<24>::new();
|
struct RGB {
|
||||||
for i in 0..24 {
|
r: u8,
|
||||||
let bit = 2_u32.pow(i) & rotate_rgb(rgb) != 0;
|
g: u8,
|
||||||
let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) };
|
b: u8,
|
||||||
signal.set(i as usize, &(high_pulse, low_pulse)).unwrap();
|
|
||||||
}
|
|
||||||
tx.start_blocking(&signal).unwrap();
|
|
||||||
Ets.delay_ms(10u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ns(nanos: u64) -> Duration {
|
fn ns(nanos: u64) -> Duration {
|
||||||
@@ -39,3 +41,26 @@ fn rotate_rgb(rgb: u32) -> u32 {
|
|||||||
let blue = (rgb & b_mask) << 16;
|
let blue = (rgb & b_mask) << 16;
|
||||||
blue | (rgb >> 8)
|
blue | (rgb >> 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> anyhow::Result<()> {
|
||||||
|
// e.g. rgb: (1,2,4)
|
||||||
|
// G R B
|
||||||
|
// 7 0 7 0 7 0
|
||||||
|
// 00000010 00000001 00000100
|
||||||
|
let color: u32 = ((rgb.g as u32) << 16) | ((rgb.r as u32) << 8) | rgb.b as u32;
|
||||||
|
let ticks_hz = tx.counter_clock()?;
|
||||||
|
let t0h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(350))?;
|
||||||
|
let t0l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(800))?;
|
||||||
|
let t1h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(700))?;
|
||||||
|
let t1l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(600))?;
|
||||||
|
let mut signal = FixedLengthSignal::<24>::new();
|
||||||
|
for i in (0..24).rev() {
|
||||||
|
let p = 2_u32.pow(i);
|
||||||
|
let bit = p & color != 0;
|
||||||
|
let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) };
|
||||||
|
signal.set(23 - i as usize, &(high_pulse, low_pulse))?;
|
||||||
|
}
|
||||||
|
tx.start_blocking(&signal)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use esp_idf_sys::c_types::c_char;
|
use core::ffi::c_char;
|
||||||
use esp_idf_sys::{
|
use esp_idf_sys::{
|
||||||
esp, esp_vfs_fat_sdmmc_mount_config_t, esp_vfs_fat_sdspi_mount, gpio_num_t, sdmmc_card_t,
|
esp, esp_vfs_fat_sdmmc_mount_config_t, esp_vfs_fat_sdspi_mount, gpio_num_t, sdmmc_card_t,
|
||||||
sdmmc_host_t, sdspi_device_config_t, spi_bus_config_t, spi_bus_initialize, spi_host_device_t,
|
sdmmc_host_t, sdspi_device_config_t, spi_bus_config_t, spi_bus_initialize, spi_host_device_t,
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
|
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
|
||||||
|
|
||||||
use embedded_svc::storage::StorageBase;
|
// use embedded_svc::storage::StorageBase;
|
||||||
use esp_idf_svc::nvs::EspNvsStorage;
|
use esp_idf_svc::nvs::EspNvs;
|
||||||
use esp_idf_svc::nvs::*;
|
use esp_idf_svc::nvs::*;
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let default_nvs = Arc::new(EspDefaultNvs::new()?);
|
// NvsDefault::new();
|
||||||
let mut store =
|
let default_nvs = EspDefaultNvsPartition::take()?;
|
||||||
EspNvsStorage::new_default(default_nvs.clone(), "sphinx", true).expect("no storage");
|
let mut store = EspNvs::new(default_nvs.clone(), "sphinx", true).expect("no storage");
|
||||||
store.remove("config").expect("couldnt remove config 1");
|
store.remove("config").expect("couldnt remove config 1");
|
||||||
store.remove("seed").expect("couldnt remove seed 1");
|
store.remove("seed").expect("couldnt remove seed 1");
|
||||||
store.remove("nonce").expect("couldnt remove nonce 1");
|
store.remove("nonce").expect("couldnt remove nonce 1");
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ use serde::Deserialize;
|
|||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
|
||||||
// use embedded_svc::http::server::registry::Registry;
|
// use embedded_svc::http::server::registry::Registry;
|
||||||
use embedded_svc::http::server::*;
|
// use embedded_svc::http::server::*;
|
||||||
|
#[allow(deprecated)]
|
||||||
use embedded_svc::httpd::registry::Registry;
|
use embedded_svc::httpd::registry::Registry;
|
||||||
use embedded_svc::httpd::Result;
|
use embedded_svc::httpd::Result;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ pub struct Params {
|
|||||||
pub config: String,
|
pub config: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables, deprecated)]
|
||||||
pub fn config_server(
|
pub fn config_server(
|
||||||
mutex: Arc<(Mutex<Option<(Config, [u8; 32])>>, Condvar)>,
|
mutex: Arc<(Mutex<Option<(Config, [u8; 32])>>, Condvar)>,
|
||||||
) -> Result<idf::Server> {
|
) -> Result<idf::Server> {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ use crate::core::events::Event as CoreEvent;
|
|||||||
use sphinx_signer::sphinx_glyph::topics;
|
use sphinx_signer::sphinx_glyph::topics;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use embedded_svc::mqtt::client::utils::ConnState;
|
|
||||||
use embedded_svc::mqtt::client::{Connection, Event, Message as MqttMessage, MessageImpl, QoS};
|
use embedded_svc::mqtt::client::{Connection, Event, Message as MqttMessage, MessageImpl, QoS};
|
||||||
use embedded_svc::utils::mqtt::client::Connection as MqttConnection;
|
use embedded_svc::utils::mqtt::client::ConnState;
|
||||||
use embedded_svc::utils::mutex::Condvar;
|
// use embedded_svc::utils::mqtt::client::Connection as MqttConnection;
|
||||||
|
// use embedded_svc::utils::mutex::Condvar;
|
||||||
use esp_idf_svc::mqtt::client::*;
|
use esp_idf_svc::mqtt::client::*;
|
||||||
use esp_idf_sys::EspError;
|
use esp_idf_sys::EspError;
|
||||||
use esp_idf_sys::{self};
|
use esp_idf_sys::{self};
|
||||||
@@ -35,7 +35,7 @@ pub fn make_client(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let b = format!("mqtt://{}", broker);
|
let b = format!("mqtt://{}", broker);
|
||||||
let (mut client, mut connection) = EspMqttClient::new_with_conn(b, &conf)?;
|
let (client, mut connection) = EspMqttClient::new_with_conn(b, &conf)?;
|
||||||
// let cc = EspMqttClient::new_with_conn(b, &conf)?;
|
// let cc = EspMqttClient::new_with_conn(b, &conf)?;
|
||||||
|
|
||||||
info!("MQTT client started");
|
info!("MQTT client started");
|
||||||
@@ -91,7 +91,7 @@ pub fn make_client(
|
|||||||
//info!("MQTT connection loop exit");
|
//info!("MQTT connection loop exit");
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(cc)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn start_listening(
|
// pub fn start_listening(
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ use std::time::Duration;
|
|||||||
|
|
||||||
pub fn sync_time() {
|
pub fn sync_time() {
|
||||||
let sntp = EspSntp::new_default().unwrap();
|
let sntp = EspSntp::new_default().unwrap();
|
||||||
println!("SNTP initialized");
|
loop {
|
||||||
while sntp.get_sync_status() != Completed {
|
let status = sntp.get_sync_status();
|
||||||
println!("Waiting for sntp sync...");
|
println!("SNTP status {:?}", status);
|
||||||
|
if status == Completed {
|
||||||
|
break;
|
||||||
|
}
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use sphinx_signer::sphinx_glyph::control::Config;
|
use sphinx_signer::sphinx_glyph::control::Config;
|
||||||
|
|
||||||
use esp_idf_svc::netif::*;
|
use esp_idf_svc::netif::*;
|
||||||
use esp_idf_svc::nvs::EspDefaultNvs;
|
use esp_idf_svc::nvs::EspDefaultNvsPartition;
|
||||||
use esp_idf_svc::ping;
|
use esp_idf_svc::ping;
|
||||||
// use esp_idf_svc::sysloop::*;
|
// use esp_idf_svc::sysloop::*;
|
||||||
use esp_idf_svc::eventloop::EspSystemEventLoop;
|
use esp_idf_svc::eventloop::EspSystemEventLoop;
|
||||||
@@ -9,20 +9,19 @@ use esp_idf_svc::wifi::*;
|
|||||||
|
|
||||||
use embedded_svc::httpd::Result;
|
use embedded_svc::httpd::Result;
|
||||||
use embedded_svc::ipv4;
|
use embedded_svc::ipv4;
|
||||||
use embedded_svc::ping::Ping;
|
// use embedded_svc::ping::Ping;
|
||||||
use embedded_svc::wifi::Wifi;
|
// use embedded_svc::wifi::Wifi;
|
||||||
use embedded_svc::wifi::*;
|
use embedded_svc::wifi::*;
|
||||||
|
|
||||||
use esp_idf_hal::peripheral;
|
use esp_idf_hal::peripheral;
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::sync::Arc;
|
// use std::thread;
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub fn start_client(
|
pub fn start_client(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: Arc<EspDefaultNvs>,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Result<Box<EspWifi<'static>>> {
|
) -> Result<Box<EspWifi<'static>>> {
|
||||||
// let netif_stack = Arc::new(EspNetifStack::new()?);
|
// let netif_stack = Arc::new(EspNetifStack::new()?);
|
||||||
@@ -30,7 +29,7 @@ pub fn start_client(
|
|||||||
|
|
||||||
let sysloop = EspSystemEventLoop::take()?;
|
let sysloop = EspSystemEventLoop::take()?;
|
||||||
|
|
||||||
let mut wifi = Box::new(EspWifi::new(modem, sysloop, Some(default_nvs))?);
|
let mut wifi = Box::new(EspWifi::new(modem, sysloop.clone(), Some(default_nvs))?);
|
||||||
let ap_infos = wifi.scan()?;
|
let ap_infos = wifi.scan()?;
|
||||||
let ssid = config.ssid.as_str();
|
let ssid = config.ssid.as_str();
|
||||||
let pass = config.pass.as_str();
|
let pass = config.pass.as_str();
|
||||||
@@ -57,32 +56,57 @@ pub fn start_client(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))?;
|
}))?;
|
||||||
|
|
||||||
info!("...Wifi client configuration set, get status");
|
wifi.start()?;
|
||||||
match wifi.wait_status_with_timeout(Duration::from_secs(20), |status| !status.is_transitional())
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => warn!("Unexpected Wifi status: {:?}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
let status = wifi.get_status();
|
info!("...Wifi client configuration set, get status");
|
||||||
println!("=> wifi STATUS {:?}", status);
|
// match wifi.wait_status_with_timeout(Duration::from_secs(20), |status| !status.is_transitional())
|
||||||
println!("=> is transitional? {:?}", status.is_transitional());
|
// {
|
||||||
if let Status(
|
// Ok(_) => (),
|
||||||
ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done(ip_settings))),
|
// Err(e) => warn!("Unexpected Wifi status: {:?}", e),
|
||||||
ApStatus::Stopped,
|
// };
|
||||||
) = status
|
|
||||||
|
if !WifiWait::new(&sysloop)?
|
||||||
|
.wait_with_timeout(Duration::from_secs(20), || wifi.is_started().unwrap())
|
||||||
{
|
{
|
||||||
info!("Wifi started!");
|
warn!("Wifi did not start");
|
||||||
ping(&ip_settings)?;
|
|
||||||
} else {
|
|
||||||
thread::sleep(Duration::from_secs(13));
|
|
||||||
// bail!("Unexpected Client Wifi status: {:?}", status);
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"Unexpected Client Wifi status: {:?}",
|
|
||||||
status
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("Connecting wifi...");
|
||||||
|
|
||||||
|
wifi.connect()?;
|
||||||
|
|
||||||
|
if !EspNetifWait::new::<EspNetif>(wifi.sta_netif(), &sysloop)?.wait_with_timeout(
|
||||||
|
Duration::from_secs(20),
|
||||||
|
|| {
|
||||||
|
wifi.is_connected().unwrap()
|
||||||
|
&& wifi.sta_netif().get_ip_info().unwrap().ip != std::net::Ipv4Addr::new(0, 0, 0, 0)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
warn!("Wifi did not connect or did not receive a DHCP lease");
|
||||||
|
}
|
||||||
|
|
||||||
|
let ip_info = wifi.sta_netif().get_ip_info()?;
|
||||||
|
|
||||||
|
info!("Wifi DHCP info: {:?}", ip_info);
|
||||||
|
// let status = wifi.get_status();
|
||||||
|
// println!("=> wifi STATUS {:?}", status);
|
||||||
|
// println!("=> is transitional? {:?}", status.is_transitional());
|
||||||
|
// if let Status(
|
||||||
|
// ClientStatus::Started(ClientConnectionStatus::Connected(ClientIpStatus::Done(ip_settings))),
|
||||||
|
// ApStatus::Stopped,
|
||||||
|
// ) = status
|
||||||
|
// {
|
||||||
|
// info!("Wifi started!");
|
||||||
|
// ping(&ip_settings)?;
|
||||||
|
// } else {
|
||||||
|
// thread::sleep(Duration::from_secs(13));
|
||||||
|
// // bail!("Unexpected Client Wifi status: {:?}", status);
|
||||||
|
// return Err(anyhow::anyhow!(
|
||||||
|
// "Unexpected Client Wifi status: {:?}",
|
||||||
|
// status
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
info!("wifi::start_client Ok(())");
|
info!("wifi::start_client Ok(())");
|
||||||
|
|
||||||
Ok(wifi)
|
Ok(wifi)
|
||||||
@@ -90,12 +114,12 @@ pub fn start_client(
|
|||||||
|
|
||||||
pub fn start_access_point(
|
pub fn start_access_point(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: Arc<EspDefaultNvs>,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
) -> Result<Box<EspWifi<'static>>> {
|
) -> Result<Box<EspWifi<'static>>> {
|
||||||
let sysloop = EspSystemEventLoop::take()?;
|
let sysloop = EspSystemEventLoop::take()?;
|
||||||
// let netif_stack = Arc::new(EspNetifStack::new()?);
|
// let netif_stack = Arc::new(EspNetifStack::new()?);
|
||||||
// let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
|
// let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
|
||||||
let mut wifi = Box::new(EspWifi::new(modem, sysloop, default_nvs)?);
|
let mut wifi = Box::new(EspWifi::new(modem, sysloop.clone(), Some(default_nvs))?);
|
||||||
|
|
||||||
let ssid: &'static str = env!("SSID");
|
let ssid: &'static str = env!("SSID");
|
||||||
let password: &'static str = env!("PASS");
|
let password: &'static str = env!("PASS");
|
||||||
@@ -111,24 +135,34 @@ pub fn start_access_point(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))?;
|
}))?;
|
||||||
|
|
||||||
info!("Wifi configuration set, about to get status");
|
wifi.start()?;
|
||||||
wifi.wait_status_with_timeout(Duration::from_secs(20), |status| !status.is_transitional())
|
|
||||||
.map_err(|e| anyhow::anyhow!("Unexpected Wifi status: {:?}", e))?;
|
info!("Wifi configuration set, about to get status");
|
||||||
|
if !WifiWait::new(&sysloop)?
|
||||||
|
.wait_with_timeout(Duration::from_secs(20), || wifi.is_started().unwrap())
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!("Wifi did not start"));
|
||||||
|
}
|
||||||
|
|
||||||
let status = wifi.get_status();
|
|
||||||
if let Status(ClientStatus::Stopped, ApStatus::Started(ApIpStatus::Done)) = status {
|
|
||||||
info!(
|
info!(
|
||||||
"Wifi started!\n \nWIFI NAME: {}\nWIFI PASSWORD: {}\n",
|
"Wifi started!\n \nWIFI NAME: {}\nWIFI PASSWORD: {}\n",
|
||||||
ssid, password
|
ssid, password
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return Err(anyhow::anyhow!("Unexpected AP Wifi status: {:?}", status));
|
// let status = wifi.get_status();
|
||||||
}
|
// if let Status(ClientStatus::Stopped, ApStatus::Started(ApIpStatus::Done)) = status {
|
||||||
|
// info!(
|
||||||
|
// "Wifi started!\n \nWIFI NAME: {}\nWIFI PASSWORD: {}\n",
|
||||||
|
// ssid, password
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// return Err(anyhow::anyhow!("Unexpected AP Wifi status: {:?}", status));
|
||||||
|
// }
|
||||||
|
|
||||||
Ok(wifi)
|
Ok(wifi)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ping(ip_settings: &ipv4::ClientSettings) -> Result<()> {
|
fn _ping(ip_settings: &ipv4::ClientSettings) -> Result<()> {
|
||||||
info!("About to do some pings for {:?}", ip_settings);
|
info!("About to do some pings for {:?}", ip_settings);
|
||||||
|
|
||||||
let ping_summary =
|
let ping_summary =
|
||||||
|
|||||||
@@ -43,11 +43,11 @@ arp -a
|
|||||||
|
|
||||||
pub fn start_wifi_client(
|
pub fn start_wifi_client(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: Arc<EspDefaultNvs>,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Result<Box<EspWifi>> {
|
) -> Result<Box<EspWifi>> {
|
||||||
let wifi = conn::wifi::start_client(modem, default_nvs, config)?;
|
let wifi = conn::wifi::start_client(modem, default_nvs, config)?;
|
||||||
println!("CLIENT CONNECTED!!!!!! {:?}", wifi.get_status());
|
println!("CLIENT CONNECTED!!!!!! {:?}", wifi.is_connected());
|
||||||
Ok(wifi)
|
Ok(wifi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])
|
|||||||
|
|
||||||
pub fn start_config_server_and_wait(
|
pub fn start_config_server_and_wait(
|
||||||
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
|
||||||
default_nvs: Arc<EspDefaultNvs>,
|
default_nvs: EspDefaultNvsPartition,
|
||||||
) -> Result<(Box<EspWifi<'static>>, Config, [u8; 32])> {
|
) -> Result<(Box<EspWifi<'static>>, Config, [u8; 32])> {
|
||||||
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use embedded_svc::storage::RawStorage;
|
use embedded_svc::storage::RawStorage;
|
||||||
use embedded_svc::storage::StorageBase;
|
use esp_idf_svc::nvs::{EspDefaultNvs, EspDefaultNvsPartition};
|
||||||
use esp_idf_svc::nvs::EspDefaultNvs;
|
|
||||||
use esp_idf_svc::nvs::EspNvsStorage;
|
|
||||||
use sphinx_signer::lightning_signer::bitcoin::Network;
|
use sphinx_signer::lightning_signer::bitcoin::Network;
|
||||||
use sphinx_signer::sphinx_glyph::control::{Config, ControlPersist, Controller, FlashKey, Policy};
|
use sphinx_signer::sphinx_glyph::control::{Config, ControlPersist, Controller, FlashKey, Policy};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -18,11 +16,12 @@ pub fn controller_from_seed(
|
|||||||
Controller::new_with_persister(sk, pk, flash)
|
Controller::new_with_persister(sk, pk, flash)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FlashPersister(pub EspNvsStorage);
|
// EspDefaultNvsPartition
|
||||||
|
pub struct FlashPersister(pub EspDefaultNvs);
|
||||||
|
|
||||||
impl FlashPersister {
|
impl FlashPersister {
|
||||||
pub fn new(nvs: Arc<EspDefaultNvs>) -> Self {
|
pub fn new(nvs: EspDefaultNvsPartition) -> Self {
|
||||||
let store = EspNvsStorage::new_default(nvs, "sphinx", true).expect("no storage");
|
let store = EspDefaultNvs::new(nvs, "sphinx", true).expect("no storage");
|
||||||
Self(store)
|
Self(store)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,12 +33,12 @@ impl ControlPersist for FlashPersister {
|
|||||||
if let None = existing {
|
if let None = existing {
|
||||||
return Err(anyhow!("no existing nonce"));
|
return Err(anyhow!("no existing nonce"));
|
||||||
}
|
}
|
||||||
let r: [u8; 8] = existing.unwrap().0.try_into()?;
|
let r: [u8; 8] = existing.unwrap().try_into()?;
|
||||||
Ok(u64::from_be_bytes(r))
|
Ok(u64::from_be_bytes(r))
|
||||||
}
|
}
|
||||||
fn set_nonce(&mut self, nonce: u64) -> Result<()> {
|
fn set_nonce(&mut self, nonce: u64) -> Result<()> {
|
||||||
let n = nonce.to_be_bytes();
|
let n = nonce.to_be_bytes();
|
||||||
self.0.put_raw(FlashKey::Nonce.as_str(), &n[..])?;
|
self.0.set_raw(FlashKey::Nonce.as_str(), &n[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn read_config(&self) -> Result<Config> {
|
fn read_config(&self) -> Result<Config> {
|
||||||
@@ -48,11 +47,11 @@ impl ControlPersist for FlashPersister {
|
|||||||
if let None = existing {
|
if let None = existing {
|
||||||
return Err(anyhow!("no existing config"));
|
return Err(anyhow!("no existing config"));
|
||||||
}
|
}
|
||||||
Ok(rmp_serde::from_slice(existing.unwrap().0)?)
|
Ok(rmp_serde::from_slice(existing.unwrap())?)
|
||||||
}
|
}
|
||||||
fn write_config(&mut self, conf: Config) -> Result<()> {
|
fn write_config(&mut self, conf: Config) -> Result<()> {
|
||||||
let conf1 = rmp_serde::to_vec(&conf)?;
|
let conf1 = rmp_serde::to_vec(&conf)?;
|
||||||
self.0.put_raw(FlashKey::Config.as_str(), &conf1[..])?;
|
self.0.set_raw(FlashKey::Config.as_str(), &conf1[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn remove_config(&mut self) -> Result<()> {
|
fn remove_config(&mut self) -> Result<()> {
|
||||||
@@ -65,11 +64,11 @@ impl ControlPersist for FlashPersister {
|
|||||||
if let None = s {
|
if let None = s {
|
||||||
return Err(anyhow!("no existing seed"));
|
return Err(anyhow!("no existing seed"));
|
||||||
}
|
}
|
||||||
let r: [u8; 32] = s.unwrap().0.try_into()?;
|
let r: [u8; 32] = s.unwrap().try_into()?;
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
fn write_seed(&mut self, s: [u8; 32]) -> Result<()> {
|
fn write_seed(&mut self, s: [u8; 32]) -> Result<()> {
|
||||||
self.0.put_raw(FlashKey::Seed.as_str(), &s[..])?;
|
self.0.set_raw(FlashKey::Seed.as_str(), &s[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn remove_seed(&mut self) -> Result<()> {
|
fn remove_seed(&mut self) -> Result<()> {
|
||||||
@@ -82,11 +81,11 @@ impl ControlPersist for FlashPersister {
|
|||||||
if let None = existing {
|
if let None = existing {
|
||||||
return Err(anyhow!("no existing config"));
|
return Err(anyhow!("no existing config"));
|
||||||
}
|
}
|
||||||
Ok(rmp_serde::from_slice(existing.unwrap().0)?)
|
Ok(rmp_serde::from_slice(existing.unwrap())?)
|
||||||
}
|
}
|
||||||
fn write_policy(&mut self, pol: Policy) -> Result<()> {
|
fn write_policy(&mut self, pol: Policy) -> Result<()> {
|
||||||
let pol1 = rmp_serde::to_vec(&pol)?;
|
let pol1 = rmp_serde::to_vec(&pol)?;
|
||||||
self.0.put_raw(FlashKey::Policy.as_str(), &pol1[..])?;
|
self.0.set_raw(FlashKey::Policy.as_str(), &pol1[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn remove_policy(&mut self) -> Result<()> {
|
fn remove_policy(&mut self) -> Result<()> {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ use std::sync::Arc;
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use embedded_svc::httpd::Result;
|
use embedded_svc::httpd::Result;
|
||||||
use embedded_svc::mqtt::client::Client;
|
// use embedded_svc::mqtt::client::Client;
|
||||||
use embedded_svc::mqtt::client::{MessageImpl, Publish};
|
use embedded_svc::mqtt::client::MessageImpl;
|
||||||
use embedded_svc::utils::mqtt::client::ConnState;
|
use embedded_svc::utils::mqtt::client::ConnState;
|
||||||
use esp_idf_svc::mqtt::client::*;
|
use esp_idf_svc::mqtt::client::*;
|
||||||
use esp_idf_sys;
|
use esp_idf_sys;
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ fn main() -> Result<()> {
|
|||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
let peripherals = Peripherals::take().unwrap();
|
let peripherals = Peripherals::take().unwrap();
|
||||||
let pins = peripherals.pins;
|
let _pins = peripherals.pins;
|
||||||
|
|
||||||
let (led_tx, led_rx) = mpsc::channel();
|
let (led_tx, _led_rx) = mpsc::channel();
|
||||||
// LED control thread
|
// LED control thread
|
||||||
// led_control_loop(pins.gpio0, peripherals.rmt.channel0, led_rx);
|
// led_control_loop(pins.gpio0, peripherals.rmt.channel0, led_rx);
|
||||||
|
|
||||||
@@ -53,7 +53,9 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
println!("SD card mounted!");
|
println!("SD card mounted!");
|
||||||
|
|
||||||
let default_nvs = Arc::new(EspDefaultNvs::new("sphinx", "sphinx", true)?);
|
// let default_nav_partition = EspDefaultNvs.take().unwrap();
|
||||||
|
let default_nvs = EspDefaultNvsPartition::take()?;
|
||||||
|
// let default_nvs = Arc::new();
|
||||||
let mut flash = FlashPersister::new(default_nvs.clone());
|
let mut flash = FlashPersister::new(default_nvs.clone());
|
||||||
if let Ok(exist) = flash.read_config() {
|
if let Ok(exist) = flash.read_config() {
|
||||||
let seed = flash.read_seed().expect("no seed...");
|
let seed = flash.read_seed().expect("no seed...");
|
||||||
@@ -63,15 +65,16 @@ fn main() -> Result<()> {
|
|||||||
exist
|
exist
|
||||||
);
|
);
|
||||||
led_tx.send(Status::ConnectingToWifi).unwrap();
|
led_tx.send(Status::ConnectingToWifi).unwrap();
|
||||||
let _wifi = loop {
|
let wifi_ = start_wifi_client(peripherals.modem, default_nvs.clone(), &exist)?;
|
||||||
if let Ok(wifi) = start_wifi_client(peripherals.modem, default_nvs.clone(), &exist) {
|
// let _wifi = loop {
|
||||||
println!("Wifi connected!");
|
// if let Ok(wifi) = start_wifi_client(peripherals.modem, default_nvs.clone(), &exist) {
|
||||||
break wifi;
|
// println!("Wifi connected!");
|
||||||
} else {
|
// break wifi;
|
||||||
println!("Failed to connect to wifi. Make sure the details are correct, trying again in 5 seconds...");
|
// } else {
|
||||||
thread::sleep(Duration::from_secs(5));
|
// println!("Failed to connect to wifi. Make sure the details are correct, trying again in 5 seconds...");
|
||||||
}
|
// thread::sleep(Duration::from_secs(5));
|
||||||
};
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
led_tx.send(Status::SyncingTime).unwrap();
|
led_tx.send(Status::SyncingTime).unwrap();
|
||||||
conn::sntp::sync_time();
|
conn::sntp::sync_time();
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
use crate::core::events::Status;
|
use crate::core::events::Status;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use embedded_svc::http::client::Client;
|
use embedded_svc::http::client::Client;
|
||||||
use embedded_svc::http::client::Request;
|
|
||||||
use embedded_svc::http::client::Response;
|
|
||||||
use embedded_svc::http::Status as HttpStatus;
|
use embedded_svc::http::Status as HttpStatus;
|
||||||
use embedded_svc::io::Read;
|
use embedded_svc::io::Read;
|
||||||
use embedded_svc::ota::Ota;
|
// use embedded_svc::ota::Ota;
|
||||||
|
|
||||||
use esp_idf_svc::http::client::Configuration as EspHttpClientConfiguration;
|
use esp_idf_svc::http::client::Configuration;
|
||||||
use esp_idf_svc::http::client::EspHttpConnection;
|
use esp_idf_svc::http::client::EspHttpConnection;
|
||||||
use esp_idf_svc::http::client::FollowRedirectsPolicy::FollowNone;
|
use esp_idf_svc::http::client::FollowRedirectsPolicy::FollowNone;
|
||||||
use esp_idf_svc::ota::EspOta;
|
use esp_idf_svc::ota::EspOta;
|
||||||
@@ -35,17 +33,17 @@ fn factory_reset() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_update(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
|
fn get_update(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Result<()> {
|
||||||
let configuration = EspHttpClientConfiguration {
|
let configuration = Configuration {
|
||||||
buffer_size: Some(BUFFER_LEN),
|
buffer_size: Some(BUFFER_LEN),
|
||||||
buffer_size_tx: Some(BUFFER_LEN / 3),
|
buffer_size_tx: Some(BUFFER_LEN / 3),
|
||||||
follow_redirects_policy: FollowNone,
|
follow_redirects_policy: FollowNone,
|
||||||
use_global_ca_store: true,
|
use_global_ca_store: true,
|
||||||
crt_bundle_attach: None,
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut client = EspHttpConnection::new(&configuration)?;
|
let mut client = Client::wrap(EspHttpConnection::new(&configuration)?);
|
||||||
let full_url = params_to_url(params);
|
let full_url = params_to_url(params);
|
||||||
let mut response = client.get(&full_url)?.submit()?;
|
let mut reader = client.get(&full_url)?.submit()?;
|
||||||
let mut reader = response.reader();
|
// let mut reader = response.reader();
|
||||||
|
|
||||||
let _ = remove_file(UPDATE_BIN_PATH);
|
let _ = remove_file(UPDATE_BIN_PATH);
|
||||||
let file = File::create(UPDATE_BIN_PATH)?;
|
let file = File::create(UPDATE_BIN_PATH)?;
|
||||||
@@ -85,14 +83,14 @@ pub fn update_sphinx_key(params: OtaParams, led_tx: mpsc::Sender<Status>) -> Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_ota_message(params: OtaParams) -> Result<()> {
|
pub fn validate_ota_message(params: OtaParams) -> Result<()> {
|
||||||
let configuration = EspHttpClientConfiguration {
|
let configuration = Configuration {
|
||||||
buffer_size: Some(BUFFER_LEN / 3),
|
buffer_size: Some(BUFFER_LEN / 3),
|
||||||
buffer_size_tx: Some(BUFFER_LEN / 3),
|
buffer_size_tx: Some(BUFFER_LEN / 3),
|
||||||
follow_redirects_policy: FollowNone,
|
follow_redirects_policy: FollowNone,
|
||||||
use_global_ca_store: true,
|
use_global_ca_store: true,
|
||||||
crt_bundle_attach: None,
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut client = EspHttpConnection::new(&configuration)?;
|
let mut client = Client::wrap(EspHttpConnection::new(&configuration)?);
|
||||||
let full_url = params_to_url(params);
|
let full_url = params_to_url(params);
|
||||||
info!("Pinging this url for an update: {}", full_url);
|
info!("Pinging this url for an update: {}", full_url);
|
||||||
let response = client.get(&full_url)?.submit()?;
|
let response = client.get(&full_url)?.submit()?;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::core::events::Status;
|
use crate::core::events::Status;
|
||||||
use embedded_hal::delay::blocking::DelayUs;
|
// use embedded_hal::delay::blocking::DelayUs;
|
||||||
use esp_idf_hal::delay::Ets;
|
use esp_idf_hal::delay::FreeRtos;
|
||||||
use esp_idf_hal::rmt::config::TransmitConfig;
|
use esp_idf_hal::rmt::config::TransmitConfig;
|
||||||
use esp_idf_hal::rmt::{FixedLengthSignal, PinState, Pulse, Transmit};
|
use esp_idf_hal::rmt::{FixedLengthSignal, PinState, Pulse, TxRmtDriver};
|
||||||
use esp_idf_hal::{gpio, rmt};
|
use esp_idf_hal::{gpio, rmt};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
@@ -33,9 +33,11 @@ fn states() -> BTreeMap<Status, (Color, Time)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn led_control_loop(gpio0: gpio::Gpio0, channel0: rmt::CHANNEL0, rx: mpsc::Receiver<Status>) {
|
pub fn led_control_loop(gpio0: gpio::Gpio0, channel0: rmt::CHANNEL0, rx: mpsc::Receiver<Status>) {
|
||||||
let led = gpio0.into_output().unwrap();
|
let led = gpio0;
|
||||||
let config = TransmitConfig::new().clock_divider(1);
|
let config = TransmitConfig::new().clock_divider(1);
|
||||||
let transmit = Arc::new(Mutex::new(Transmit::new(led, channel0, &config).unwrap()));
|
let transmit = Arc::new(Mutex::new(
|
||||||
|
TxRmtDriver::new(channel0, led, &config).unwrap(),
|
||||||
|
));
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut led = Led::new(0x000001, 100);
|
let mut led = Led::new(0x000001, 100);
|
||||||
let states = states();
|
let states = states();
|
||||||
@@ -65,10 +67,7 @@ impl Led {
|
|||||||
self.blink_length = blink_length;
|
self.blink_length = blink_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blink(
|
pub fn blink(&mut self, transmit: Arc<Mutex<TxRmtDriver>>) {
|
||||||
&mut self,
|
|
||||||
transmit: Arc<Mutex<Transmit<gpio::Gpio0<gpio::Output>, rmt::CHANNEL0>>>,
|
|
||||||
) {
|
|
||||||
// Prepare signal
|
// Prepare signal
|
||||||
let mut tx = transmit.lock().unwrap();
|
let mut tx = transmit.lock().unwrap();
|
||||||
let ticks_hz = tx.counter_clock().unwrap();
|
let ticks_hz = tx.counter_clock().unwrap();
|
||||||
@@ -85,7 +84,7 @@ impl Led {
|
|||||||
}
|
}
|
||||||
// Set high and wait
|
// Set high and wait
|
||||||
tx.start_blocking(&signal).unwrap();
|
tx.start_blocking(&signal).unwrap();
|
||||||
Ets.delay_ms(self.blink_length).unwrap();
|
FreeRtos::delay_ms(self.blink_length);
|
||||||
// Set low
|
// Set low
|
||||||
let mut signal = FixedLengthSignal::<24>::new();
|
let mut signal = FixedLengthSignal::<24>::new();
|
||||||
for i in 0..24 {
|
for i in 0..24 {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// pub mod led;
|
pub mod led;
|
||||||
pub mod sd;
|
pub mod sd;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use esp_idf_sys::c_types::c_char;
|
// use esp_idf_sys::c_types::c_char;
|
||||||
|
use core::ffi::c_char;
|
||||||
use esp_idf_sys::{
|
use esp_idf_sys::{
|
||||||
esp, esp_vfs_fat_sdmmc_mount_config_t, esp_vfs_fat_sdspi_mount, gpio_num_t, sdmmc_card_t,
|
esp, esp_vfs_fat_sdmmc_mount_config_t, esp_vfs_fat_sdspi_mount, gpio_num_t, sdmmc_card_t,
|
||||||
sdmmc_host_t, sdspi_device_config_t, spi_bus_config_t, spi_bus_initialize, spi_host_device_t,
|
sdmmc_host_t, sdspi_device_config_t, spi_bus_config_t, spi_bus_initialize, spi_host_device_t,
|
||||||
|
|||||||
Reference in New Issue
Block a user