This commit is contained in:
Sebastian Hugentobler 2024-09-24 22:40:35 +02:00
parent e2c5b7400f
commit ff7849043f
Signed by: shu
GPG Key ID: BB32CF3CA052C2F0
11 changed files with 138 additions and 62 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ target
result result
mosquitto mosquitto
s140_*_softdevice.hex s140_*_softdevice.hex
.direnv/

45
display/Cargo.lock generated
View File

@ -29,12 +29,14 @@ dependencies = [
"cortex-m-rt", "cortex-m-rt",
"defmt", "defmt",
"defmt-rtt", "defmt-rtt",
"ekv",
"embassy-embedded-hal", "embassy-embedded-hal",
"embassy-executor", "embassy-executor",
"embassy-nrf", "embassy-nrf",
"embassy-sync 0.6.0",
"embassy-time", "embassy-time",
"embedded-hal-async", "embedded-hal-async",
"embedded-storage-async",
"futures",
"nrf-softdevice", "nrf-softdevice",
"panic-probe", "panic-probe",
] ]
@ -261,23 +263,14 @@ dependencies = [
"litrs", "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]] [[package]]
name = "embassy-embedded-hal" name = "embassy-embedded-hal"
version = "0.1.0" 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 = [ dependencies = [
"defmt", "defmt",
"embassy-futures 0.1.1 (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.5.0 (git+https://github.com/embassy-rs/embassy.git?rev=3c52ef60b19468a8700d612699c869f0bdcae339)", "embassy-sync 0.6.0",
"embassy-time", "embassy-time",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
@ -290,7 +283,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-executor" name = "embassy-executor"
version = "0.5.0" 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 = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
@ -304,7 +297,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-executor-macros" name = "embassy-executor-macros"
version = "0.4.1" 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 = [ dependencies = [
"darling 0.20.8", "darling 0.20.8",
"proc-macro2", "proc-macro2",
@ -321,12 +314,12 @@ checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067"
[[package]] [[package]]
name = "embassy-futures" name = "embassy-futures"
version = "0.1.1" 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]] [[package]]
name = "embassy-hal-internal" name = "embassy-hal-internal"
version = "0.1.0" 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 = [ dependencies = [
"cortex-m", "cortex-m",
"critical-section", "critical-section",
@ -337,7 +330,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-nrf" name = "embassy-nrf"
version = "0.1.0" 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 = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"cfg-if", "cfg-if",
@ -348,7 +341,7 @@ dependencies = [
"document-features", "document-features",
"embassy-embedded-hal", "embassy-embedded-hal",
"embassy-hal-internal", "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",
"embassy-time-driver", "embassy-time-driver",
"embassy-usb-driver", "embassy-usb-driver",
@ -389,8 +382,8 @@ dependencies = [
[[package]] [[package]]
name = "embassy-sync" name = "embassy-sync"
version = "0.5.0" version = "0.6.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 = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
@ -403,7 +396,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-time" name = "embassy-time"
version = "0.3.0" 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 = [ dependencies = [
"cfg-if", "cfg-if",
"critical-section", "critical-section",
@ -421,7 +414,7 @@ dependencies = [
[[package]] [[package]]
name = "embassy-time-driver" name = "embassy-time-driver"
version = "0.1.0" 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 = [ dependencies = [
"document-features", "document-features",
] ]
@ -429,12 +422,12 @@ dependencies = [
[[package]] [[package]]
name = "embassy-time-queue-driver" name = "embassy-time-queue-driver"
version = "0.1.0" 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]] [[package]]
name = "embassy-usb-driver" name = "embassy-usb-driver"
version = "0.1.0" 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 = [ dependencies = [
"defmt", "defmt",
] ]
@ -651,7 +644,7 @@ dependencies = [
"critical-section", "critical-section",
"defmt", "defmt",
"embassy-futures 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "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",
"embedded-storage-async", "embedded-storage-async",
"fixed", "fixed",

View File

@ -7,26 +7,31 @@ edition = "2021"
[dependencies.embassy-nrf] [dependencies.embassy-nrf]
version = "0.1.0" version = "0.1.0"
git = "https://github.com/embassy-rs/embassy.git" git = "https://github.com/embassy-rs/embassy.git"
rev = "3c52ef60b19468a8700d612699c869f0bdcae339" rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf"
features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"]
[dependencies.embassy-embedded-hal] [dependencies.embassy-embedded-hal]
version = "0.1.0" version = "0.1.0"
git = "https://github.com/embassy-rs/embassy.git" git = "https://github.com/embassy-rs/embassy.git"
rev = "3c52ef60b19468a8700d612699c869f0bdcae339" rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf"
[dependencies.embassy-executor] [dependencies.embassy-executor]
version = "0.5.0" version = "0.5.0"
git = "https://github.com/embassy-rs/embassy.git" 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"] features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"]
[dependencies.embassy-time] [dependencies.embassy-time]
version = "0.3.0" version = "0.3.0"
git = "https://github.com/embassy-rs/embassy.git" git = "https://github.com/embassy-rs/embassy.git"
rev = "3c52ef60b19468a8700d612699c869f0bdcae339" rev = "cf0d227cca92a80e85575154d380d1ff73fb32cf"
features = ["defmt", "defmt-timestamp-uptime"] 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] [dependencies.nrf-softdevice]
version = "0.1.0" version = "0.1.0"
git = "https://github.com/embassy-rs/nrf-softdevice.git" 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" cortex-m-rt = "0.7.3"
embedded-hal-async = "1.0.0" embedded-hal-async = "1.0.0"
embedded-storage-async = "0.4.1"
ekv = { version = "0.1.0", git = "https://github.com/embassy-rs/ekv.git", rev = "571a9c8863e9644682ebd41343eaf0444ea4bf87", features = [ futures = { version = "0.3.30", default-features = false }
"crc",
"page-size-4096",
"align-4",
"max-page-count-2048",
]}

View File

@ -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],
}

View File

@ -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::BatteryService;
use crate::ble::battery_service::BatteryServiceEvent; use crate::ble::battery_service::BatteryServiceEvent;
@ -9,6 +12,7 @@ use nrf_softdevice::ble::DisconnectedError;
#[nrf_softdevice::gatt_server] #[nrf_softdevice::gatt_server]
pub struct Server { pub struct Server {
pub bas: BatteryService, pub bas: BatteryService,
pub config: ConfigService,
} }
pub async fn run(conn: &Connection, server: &Server) -> DisconnectedError { 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) 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 .await
} }

48
display/src/flash.rs Normal file
View File

@ -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)
}
}

View File

@ -24,8 +24,6 @@ const DISPLAY_ON: u8 = 0x04;
const SCROLL_LEFT: u8 = 0x18; const SCROLL_LEFT: u8 = 0x18;
const BLINK_ON: u8 = 0x01;
const CURSOR_ON: u8 = 0x02;
const BLINK_OFF: u8 = 0x00; const BLINK_OFF: u8 = 0x00;
const CURSOR_OFF: u8 = 0x00; const CURSOR_OFF: u8 = 0x00;
@ -96,7 +94,7 @@ impl<'a> Lcd<'a> {
self.i2c.write(self.address, &[BACKLIGHT]).await?; self.i2c.write(self.address, &[BACKLIGHT]).await?;
delay.delay_ms(10).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?; .await?;
self.set_cursor(0, LINE_OFFSETS[Lines::First as usize]) self.set_cursor(0, LINE_OFFSETS[Lines::First as usize])

View File

@ -1,10 +1,18 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::cell::Cell;
use ble::gatt::Server;
use cortex_m::interrupt::Mutex;
use defmt_rtt as _; use defmt_rtt as _;
use embassy_nrf as _; use embassy_nrf as _;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_time::Delay; use embassy_time::Delay;
use embedded_hal_async::delay::DelayNs; use embedded_hal_async::delay::DelayNs;
use flash::Config;
use futures::pin_mut;
use nrf_softdevice::{Flash, Softdevice};
use panic_probe as _; use panic_probe as _;
use crate::lcd::Lcd; use crate::lcd::Lcd;
@ -14,19 +22,18 @@ use embassy_executor::Spawner;
pub mod ble { pub mod ble {
pub mod advertisment; pub mod advertisment;
pub mod battery_service; pub mod battery_service;
pub mod config_service;
pub mod gatt; pub mod gatt;
pub mod softdevice;
} }
pub mod flash;
pub mod lcd; pub mod lcd;
pub mod peripherals; pub mod peripherals;
pub mod softdevice;
const DEVICE_NAME: &str = "alert-me display"; const DEVICE_NAME: &str = "alert-me display";
#[embassy_executor::task] #[embassy_executor::task]
async fn ble(spawner: Spawner) { async fn ble(sd: &'static Softdevice, server: Server) {
let (sd, server) = ble::softdevice::run(spawner, DEVICE_NAME);
loop { loop {
let conn = ble::advertisment::run(sd, DEVICE_NAME).await; let conn = ble::advertisment::run(sd, DEVICE_NAME).await;
let error = ble::gatt::run(&conn, &server).await; let error = ble::gatt::run(&conn, &server).await;
@ -35,7 +42,7 @@ async fn ble(spawner: Spawner) {
} }
#[embassy_executor::task] #[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 {}; let mut d = Delay {};
loop { loop {
lcd.scroll_buffer() lcd.scroll_buffer()
@ -55,16 +62,13 @@ async fn main(spawner: Spawner) {
peripherals.P0_03, peripherals.P0_03,
peripherals.P0_04, peripherals.P0_04,
); );
lcd.init() lcd.init().await.expect("Failed to initialize lcd");
.await let (sd, server) = softdevice::run(spawner, DEVICE_NAME).expect("Failed to run softdevice");
.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();
unwrap!(spawner.spawn(ble(spawner))); let flash = Flash::take(sd);
unwrap!(spawner.spawn(tick(lcd, 300))); pin_mut!(flash);
let config = flash::Config::new(flash);
unwrap!(spawner.spawn(ble(sd, server)));
unwrap!(spawner.spawn(tick(sd, lcd, 500)));
} }

View File

@ -3,7 +3,7 @@ use core::mem;
use crate::ble::gatt::Server; use crate::ble::gatt::Server;
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use nrf_softdevice::{raw, Softdevice}; use nrf_softdevice::{ble::gatt_server::RegisterError, raw, Softdevice};
#[embassy_executor::task] #[embassy_executor::task]
async fn softdevice_task(sd: &'static Softdevice) -> ! { 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 config = configure(device_name);
let sd = Softdevice::enable(&config); let sd = Softdevice::enable(&config);
let server = unwrap!(Server::new(sd)); let server = Server::new(sd)?;
unwrap!(spawner.spawn(softdevice_task(sd))); unwrap!(spawner.spawn(softdevice_task(sd)));
info!("softdevice started"); info!("softdevice started");
(sd, server) Ok((sd, server))
} }

View File

@ -74,7 +74,7 @@
with fenix.packages.${system}; with fenix.packages.${system};
fromToolchainFile { fromToolchainFile {
file = ./rust-toolchain.toml; file = ./rust-toolchain.toml;
sha256 = "sha256-yrQPCdDVYQlF7MSAZP+R4DKigWY3PSTs0Re42v7CDNs="; sha256 = "sha256-efF87P7mtVVzZ6KRvRYLKOk4KrDcCuA0Kv9luRrjBzI=";
}; };
in in
with pkgs; with pkgs;