diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 03c81f8..f2d3cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target result mosquitto s140_*_softdevice.hex +.direnv/ diff --git a/display/Cargo.lock b/display/Cargo.lock index 4487a1c..eb05b3b 100644 --- a/display/Cargo.lock +++ b/display/Cargo.lock @@ -29,12 +29,14 @@ dependencies = [ "cortex-m-rt", "defmt", "defmt-rtt", - "ekv", "embassy-embedded-hal", "embassy-executor", "embassy-nrf", + "embassy-sync 0.6.0", "embassy-time", "embedded-hal-async", + "embedded-storage-async", + "futures", "nrf-softdevice", "panic-probe", ] @@ -261,23 +263,14 @@ dependencies = [ "litrs", ] -[[package]] -name = "ekv" -version = "0.1.0" -source = "git+https://github.com/embassy-rs/ekv.git?rev=571a9c8863e9644682ebd41343eaf0444ea4bf87#571a9c8863e9644682ebd41343eaf0444ea4bf87" -dependencies = [ - "embassy-sync 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "heapless", -] - [[package]] name = "embassy-embedded-hal" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "defmt", - "embassy-futures 0.1.1 (git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339)", - "embassy-sync 0.5.0 (git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339)", + "embassy-futures 0.1.1 (git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf)", + "embassy-sync 0.6.0", "embassy-time", "embedded-hal 0.2.7", "embedded-hal 1.0.0", @@ -290,7 +283,7 @@ dependencies = [ [[package]] name = "embassy-executor" version = "0.5.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "cortex-m", "critical-section", @@ -304,7 +297,7 @@ dependencies = [ [[package]] name = "embassy-executor-macros" version = "0.4.1" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "darling 0.20.8", "proc-macro2", @@ -321,12 +314,12 @@ checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" [[package]] name = "embassy-futures" version = "0.1.1" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" [[package]] name = "embassy-hal-internal" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "cortex-m", "critical-section", @@ -337,7 +330,7 @@ dependencies = [ [[package]] name = "embassy-nrf" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "bitflags 2.5.0", "cfg-if", @@ -348,7 +341,7 @@ dependencies = [ "document-features", "embassy-embedded-hal", "embassy-hal-internal", - "embassy-sync 0.5.0 (git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339)", + "embassy-sync 0.6.0", "embassy-time", "embassy-time-driver", "embassy-usb-driver", @@ -389,8 +382,8 @@ dependencies = [ [[package]] name = "embassy-sync" -version = "0.5.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +version = "0.6.0" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "cfg-if", "critical-section", @@ -403,7 +396,7 @@ dependencies = [ [[package]] name = "embassy-time" version = "0.3.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "cfg-if", "critical-section", @@ -421,7 +414,7 @@ dependencies = [ [[package]] name = "embassy-time-driver" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "document-features", ] @@ -429,12 +422,12 @@ dependencies = [ [[package]] name = "embassy-time-queue-driver" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" [[package]] name = "embassy-usb-driver" version = "0.1.0" -source = "git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339#3c52ef60b19468a8700d612699c869f0bdcae339" +source = "git+https://github.com/embassy-rs/embassy.git?rev=cf0d227cca92a80e85575154d380d1ff73fb32cf#cf0d227cca92a80e85575154d380d1ff73fb32cf" dependencies = [ "defmt", ] @@ -651,7 +644,7 @@ dependencies = [ "critical-section", "defmt", "embassy-futures 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "embassy-sync 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "embassy-sync 0.5.0", "embedded-storage", "embedded-storage-async", "fixed", diff --git a/display/Cargo.toml b/display/Cargo.toml index 4759211..d9f7966 100644 --- a/display/Cargo.toml +++ b/display/Cargo.toml @@ -7,26 +7,31 @@ edition = "2021" [dependencies.embassy-nrf] version = "0.1.0" git = "https://github.com/embassy-rs/embassy.git" -rev = "3c52ef60b19468a8700d612699c869f0bdcae339" +rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf" features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] [dependencies.embassy-embedded-hal] version = "0.1.0" git = "https://github.com/embassy-rs/embassy.git" -rev = "3c52ef60b19468a8700d612699c869f0bdcae339" +rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf" [dependencies.embassy-executor] version = "0.5.0" git = "https://github.com/embassy-rs/embassy.git" -rev = "3c52ef60b19468a8700d612699c869f0bdcae339" +rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf" features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] [dependencies.embassy-time] version = "0.3.0" git = "https://github.com/embassy-rs/embassy.git" -rev = "3c52ef60b19468a8700d612699c869f0bdcae339" +rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf" features = ["defmt", "defmt-timestamp-uptime"] +[dependencies.embassy-sync] +version = "0.6.0" +git = "https://github.com/embassy-rs/embassy.git" +rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf" + [dependencies.nrf-softdevice] version = "0.1.0" git = "https://github.com/embassy-rs/nrf-softdevice.git" @@ -43,10 +48,5 @@ cortex-m = { version = "0.7.7", features = ["inline-asm"] } cortex-m-rt = "0.7.3" embedded-hal-async = "1.0.0" - -ekv = { version = "0.1.0", git = "https://github.com/embassy-rs/ekv.git", rev = "571a9c8863e9644682ebd41343eaf0444ea4bf87", features = [ - "crc", - "page-size-4096", - "align-4", - "max-page-count-2048", -]} +embedded-storage-async = "0.4.1" +futures = { version = "0.3.30", default-features = false } diff --git a/display/src/ble/config_service.rs b/display/src/ble/config_service.rs new file mode 100644 index 0000000..6ee44ff --- /dev/null +++ b/display/src/ble/config_service.rs @@ -0,0 +1,12 @@ +const MAX_STRING_LENGTH: usize = 128; + +#[nrf_softdevice::gatt_service(uuid = "437dc41e-d899-40ac-9c83-188c8c4d9fe7")] +pub struct ConfigService { + #[characteristic(uuid = "e7b9ebd9-57e0-4821-8fa3-55e22cd7b705", read, write)] + #[description = "WiFi SSID"] + pub wifi_ssid: [u8; MAX_STRING_LENGTH], + #[characteristic(uuid = "1bcc70df-179e-4853-bb74-c22380f491a3", read, write)] + pub wifi_pw: [u8; MAX_STRING_LENGTH], + #[characteristic(uuid = "3c9e4967-f792-4903-a968-490271cb7eeb", read, write)] + pub mqtt_broker: [u8; MAX_STRING_LENGTH], +} diff --git a/display/src/ble/gatt.rs b/display/src/ble/gatt.rs index 780b27d..bf0cbc8 100644 --- a/display/src/ble/gatt.rs +++ b/display/src/ble/gatt.rs @@ -1,3 +1,6 @@ +use crate::ble::config_service::ConfigService; +use crate::ble::config_service::ConfigServiceEvent; + use crate::ble::battery_service::BatteryService; use crate::ble::battery_service::BatteryServiceEvent; @@ -9,6 +12,7 @@ use nrf_softdevice::ble::DisconnectedError; #[nrf_softdevice::gatt_server] pub struct Server { pub bas: BatteryService, + pub config: ConfigService, } pub async fn run(conn: &Connection, server: &Server) -> DisconnectedError { @@ -19,6 +23,17 @@ pub async fn run(conn: &Connection, server: &Server) -> DisconnectedError { info!("battery notifications: {}", notifications) } }, + ServerEvent::Config(e) => match e { + ConfigServiceEvent::WifiSsidWrite(val) => { + info!("new ssid: {}", val); + } + ConfigServiceEvent::WifiPwWrite(val) => { + info!("new pw: {}", val); + } + ConfigServiceEvent::MqttBrokerWrite(val) => { + info!("new broker: {}", val); + } + }, }) .await } diff --git a/display/src/flash.rs b/display/src/flash.rs new file mode 100644 index 0000000..8ec142f --- /dev/null +++ b/display/src/flash.rs @@ -0,0 +1,48 @@ +use core::pin::Pin; + +use embedded_storage_async::nor_flash::{NorFlash, ReadNorFlash}; +use nrf_softdevice::{Flash, FlashError}; + +const MAX_STRING_LENGTH: u32 = 128; +const CONFIG_START: u32 = 0x80000; + +pub enum ConfigItem { + Ssid, + WifiPw, + MqtBroker, +} + +pub struct Config<'a> { + flash: Pin<&'a mut Flash>, +} + +impl<'a> Config<'a> { + pub fn new(flash: Pin<&'a mut Flash>) -> Config<'a> { + Self { flash } + } + + pub async fn write( + &mut self, + config_item: ConfigItem, + value: &[u8; MAX_STRING_LENGTH as usize], + ) -> Result<(), FlashError> { + let from = CONFIG_START + MAX_STRING_LENGTH * config_item as u32; + let to = from + MAX_STRING_LENGTH; + + self.flash.as_mut().erase(from, to).await?; + self.flash.as_mut().write(from, value).await?; + + Ok(()) + } + + pub async fn read( + &mut self, + config_item: ConfigItem, + ) -> Result<[u8; MAX_STRING_LENGTH as usize], FlashError> { + let offset = CONFIG_START + MAX_STRING_LENGTH * config_item as u32; + let mut buffer: [u8; MAX_STRING_LENGTH as usize] = [0; MAX_STRING_LENGTH as usize]; + self.flash.as_mut().read(offset, &mut buffer).await?; + + Ok(buffer) + } +} diff --git a/display/src/lcd.rs b/display/src/lcd.rs index 5256c61..0d32003 100644 --- a/display/src/lcd.rs +++ b/display/src/lcd.rs @@ -24,8 +24,6 @@ const DISPLAY_ON: u8 = 0x04; const SCROLL_LEFT: u8 = 0x18; -const BLINK_ON: u8 = 0x01; -const CURSOR_ON: u8 = 0x02; const BLINK_OFF: u8 = 0x00; const CURSOR_OFF: u8 = 0x00; @@ -96,7 +94,7 @@ impl<'a> Lcd<'a> { self.i2c.write(self.address, &[BACKLIGHT]).await?; delay.delay_ms(10).await; - self.cmd(DISPLAY_CONTROL | DISPLAY_ON | CURSOR_ON | BLINK_ON, 0) + self.cmd(DISPLAY_CONTROL | DISPLAY_ON | CURSOR_OFF | BLINK_OFF, 0) .await?; self.set_cursor(0, LINE_OFFSETS[Lines::First as usize]) diff --git a/display/src/main.rs b/display/src/main.rs index c316c7e..7dfed18 100644 --- a/display/src/main.rs +++ b/display/src/main.rs @@ -1,10 +1,18 @@ #![no_std] #![no_main] +use core::cell::Cell; + +use ble::gatt::Server; +use cortex_m::interrupt::Mutex; use defmt_rtt as _; use embassy_nrf as _; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time::Delay; use embedded_hal_async::delay::DelayNs; +use flash::Config; +use futures::pin_mut; +use nrf_softdevice::{Flash, Softdevice}; use panic_probe as _; use crate::lcd::Lcd; @@ -14,19 +22,18 @@ use embassy_executor::Spawner; pub mod ble { pub mod advertisment; pub mod battery_service; + pub mod config_service; pub mod gatt; - pub mod softdevice; } - +pub mod flash; pub mod lcd; pub mod peripherals; +pub mod softdevice; const DEVICE_NAME: &str = "alert-me display"; #[embassy_executor::task] -async fn ble(spawner: Spawner) { - let (sd, server) = ble::softdevice::run(spawner, DEVICE_NAME); - +async fn ble(sd: &'static Softdevice, server: Server) { loop { let conn = ble::advertisment::run(sd, DEVICE_NAME).await; let error = ble::gatt::run(&conn, &server).await; @@ -35,7 +42,7 @@ async fn ble(spawner: Spawner) { } #[embassy_executor::task] -async fn tick(mut lcd: lcd::Lcd<'static>, delay: u32) { +async fn tick(sd: &'static Softdevice, mut lcd: lcd::Lcd<'static>, delay: u32) { let mut d = Delay {}; loop { lcd.scroll_buffer() @@ -55,16 +62,13 @@ async fn main(spawner: Spawner) { peripherals.P0_03, peripherals.P0_04, ); - lcd.init() - .await - .unwrap_or_else(|e| error!("Failed to initialize lcd: {}", e)); - lcd.write("Hello, horse :)", lcd::Lines::First) - .await - .unwrap(); - lcd.write("I am an electronic horse!", lcd::Lines::Second) - .await - .unwrap(); + lcd.init().await.expect("Failed to initialize lcd"); + let (sd, server) = softdevice::run(spawner, DEVICE_NAME).expect("Failed to run softdevice"); - unwrap!(spawner.spawn(ble(spawner))); - unwrap!(spawner.spawn(tick(lcd, 300))); + let flash = Flash::take(sd); + pin_mut!(flash); + let config = flash::Config::new(flash); + + unwrap!(spawner.spawn(ble(sd, server))); + unwrap!(spawner.spawn(tick(sd, lcd, 500))); } diff --git a/display/src/ble/softdevice.rs b/display/src/softdevice.rs similarity index 87% rename from display/src/ble/softdevice.rs rename to display/src/softdevice.rs index 98a244a..42f139c 100644 --- a/display/src/ble/softdevice.rs +++ b/display/src/softdevice.rs @@ -3,7 +3,7 @@ use core::mem; use crate::ble::gatt::Server; use defmt::{info, unwrap}; use embassy_executor::Spawner; -use nrf_softdevice::{raw, Softdevice}; +use nrf_softdevice::{ble::gatt_server::RegisterError, raw, Softdevice}; #[embassy_executor::task] async fn softdevice_task(sd: &'static Softdevice) -> ! { @@ -46,13 +46,17 @@ fn configure(device_name: &str) -> nrf_softdevice::Config { } } -pub fn run<'a>(spawner: Spawner, device_name: &str) -> (&'a Softdevice, Server) { +pub fn run<'a>( + spawner: Spawner, + device_name: &str, +) -> Result<(&'a Softdevice, Server), RegisterError> { let config = configure(device_name); let sd = Softdevice::enable(&config); - let server = unwrap!(Server::new(sd)); + let server = Server::new(sd)?; + unwrap!(spawner.spawn(softdevice_task(sd))); info!("softdevice started"); - (sd, server) + Ok((sd, server)) } diff --git a/flake.nix b/flake.nix index e9f5dfa..b920e2b 100644 --- a/flake.nix +++ b/flake.nix @@ -74,7 +74,7 @@ with fenix.packages.${system}; fromToolchainFile { file = ./rust-toolchain.toml; - sha256 = "sha256-yrQPCdDVYQlF7MSAZP+R4DKigWY3PSTs0Re42v7CDNs="; + sha256 = "sha256-efF87P7mtVVzZ6KRvRYLKOk4KrDcCuA0Kv9luRrjBzI="; }; in with pkgs;