This commit is contained in:
Vitalii 2026-02-11 01:15:45 +02:00
parent 452abc36a5
commit b89972c5e3
Signed by: SymbX
GPG Key ID: FF51F4E4BCE459EE
3 changed files with 34 additions and 19 deletions

1
Cargo.lock generated
View File

@ -757,6 +757,7 @@ dependencies = [
"embassy-nrf", "embassy-nrf",
"embassy-sync 0.7.2", "embassy-sync 0.7.2",
"embassy-time", "embassy-time",
"futures",
"nrf-softdevice", "nrf-softdevice",
"panic-halt", "panic-halt",
"panic-probe", "panic-probe",

View File

@ -18,6 +18,7 @@ embassy-time = { version = "0.5.0", features = ["tick-hz-32_768", "defmt", "defm
panic-halt = "1.0.0" panic-halt = "1.0.0"
panic-probe = { version = "1.0.0", features = ["print-defmt"], optional = true } panic-probe = { version = "1.0.0", features = ["print-defmt"], optional = true }
nrf-softdevice = { version = "0.1.0", features = ["s140", "ble-peripheral", "nrf52840", "nrf-softdevice-s140", "critical-section-impl", "defmt", "nrf52840-pac", "critical-section", "ble-gatt-server"] } nrf-softdevice = { version = "0.1.0", features = ["s140", "ble-peripheral", "nrf52840", "nrf-softdevice-s140", "critical-section-impl", "defmt", "nrf52840-pac", "critical-section", "ble-gatt-server"] }
futures = { version = "0.3", default-features = false, features = [] }
[[bin]] [[bin]]
name = "odesa" name = "odesa"

View File

@ -5,7 +5,7 @@ mod fmt;
use core::mem; use core::mem;
use core::ops::{AddAssign, SubAssign}; use core::ops::{AddAssign, SubAssign};
use defmt::Format; use defmt::{error, Format};
#[cfg(not(feature = "defmt"))] #[cfg(not(feature = "defmt"))]
use panic_halt as _; use panic_halt as _;
#[cfg(feature = "defmt")] #[cfg(feature = "defmt")]
@ -16,18 +16,20 @@ use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::join::{join3, join4}; use embassy_futures::join::{join3, join4};
use embassy_nrf::gpio::{AnyPin, Input, OutputDrive, Pull}; use embassy_nrf::gpio::{AnyPin, Input, OutputDrive, Pull};
use embassy_nrf::interrupt::Priority; use embassy_nrf::interrupt::{InterruptExt, Priority};
use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm};
use embassy_nrf::{bind_interrupts, saadc, Peri}; use embassy_nrf::{bind_interrupts, interrupt, saadc, Peri};
use embassy_nrf::peripherals::SAADC; use embassy_nrf::peripherals::SAADC;
use embassy_nrf::saadc::{ChannelConfig, Gain, Reference, Saadc}; use embassy_nrf::saadc::{ChannelConfig, Gain, Reference, Saadc};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_sync::signal::Signal; use embassy_sync::signal::Signal;
use embassy_time::{with_timeout, Duration, Timer}; use embassy_time::{with_timeout, Duration, Timer};
use futures::future::{select, Either};
use futures::pin_mut;
use nrf_softdevice::{raw, Softdevice}; use nrf_softdevice::{raw, Softdevice};
use nrf_softdevice::ble::advertisement_builder::{Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList, ServiceUuid16}; use nrf_softdevice::ble::advertisement_builder::{Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList, ServiceUuid16};
use nrf_softdevice::ble::{peripheral, gatt_server}; use nrf_softdevice::ble::{peripheral, gatt_server, Connection};
#[derive(Copy, Clone, Eq, PartialEq, Format)] #[derive(Copy, Clone, Eq, PartialEq, Format)]
enum SysAction { enum SysAction {
@ -145,9 +147,11 @@ async fn main(spawner: Spawner) {
let server = Server::new(sd).expect("failed to enable softdevice"); let server = Server::new(sd).expect("failed to enable softdevice");
let mut channel_config = ChannelConfig::single_ended(p.P0_31.reborrow()); let mut channel_config = ChannelConfig::single_ended(p.P0_31.reborrow());
interrupt::SAADC.set_priority(Priority::P3);
channel_config.gain = Gain::GAIN1_6; channel_config.gain = Gain::GAIN1_6;
channel_config.reference = Reference::INTERNAL; channel_config.reference = Reference::INTERNAL;
let saadc = Saadc::new(p.SAADC, AdcIrqs, saadc::Config::default(), [channel_config]); let saadc = Saadc::new(p.SAADC, AdcIrqs, saadc::Config::default(), [channel_config]);
saadc.calibrate().await;
let pwm_text = SimplePwm::new_3ch(p.PWM0, p.P1_00, p.P1_04, p.P1_06, &Default::default()); let pwm_text = SimplePwm::new_3ch(p.PWM0, p.P1_00, p.P1_04, p.P1_06, &Default::default());
let pwm_heart = SimplePwm::new_3ch(p.PWM2, p.P0_17, p.P0_20, p.P0_22, &Default::default()); let pwm_heart = SimplePwm::new_3ch(p.PWM2, p.P0_17, p.P0_20, p.P0_22, &Default::default());
@ -155,13 +159,13 @@ async fn main(spawner: Spawner) {
spawner.spawn(touch_button(p.P0_08.into())).expect("failed to spawn touch task"); spawner.spawn(touch_button(p.P0_08.into())).expect("failed to spawn touch task");
spawner.spawn(actions_task()).expect("failed to spawn actions task"); spawner.spawn(actions_task()).expect("failed to spawn actions task");
spawner.spawn(softdevice_task(sd)).expect("failed to spawn softdevice task"); spawner.spawn(softdevice_task(sd)).expect("failed to spawn softdevice task");
spawner.spawn(battery_task(saadc)).expect("failed to spawn softdevice task"); // spawner.spawn(battery_task(saadc)).expect("failed to spawn softdevice task");
join4(gatt_task(server, sd), moving_radar(p.P0_06.into()), heartbeat_task(pwm_heart), light_task(pwm_text)).await; join4(gatt_task(server, saadc, sd), moving_radar(p.P0_06.into()), heartbeat_task(pwm_heart), light_task(pwm_text)).await;
} }
async fn gatt_task(server: Server, sd: &'static Softdevice) { async fn gatt_task(server: Server, mut saadc: Saadc<'static, 1>, sd: &'static Softdevice) {
static ADV_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new() static ADV_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new()
.flags(&[Flag::GeneralDiscovery, Flag::LE_Only]) .flags(&[Flag::GeneralDiscovery, Flag::LE_Only])
.services_16(ServiceList::Complete, &[ServiceUuid16::BATTERY]) .services_16(ServiceList::Complete, &[ServiceUuid16::BATTERY])
@ -185,11 +189,9 @@ async fn gatt_task(server: Server, sd: &'static Softdevice) {
info!("advertising done!"); info!("advertising done!");
// Run the GATT server on the connection. This returns when the connection gets disconnected.
// let battery_fut = battery_task(&mut saadc, &server, &conn);
// Event enums (ServerEvent's) are generated by nrf_softdevice::gatt_server let gatt_fut = gatt_server::run(&conn, &server, |e| match e {
// proc macro when applied to the Server struct above
let e = gatt_server::run(&conn, &server, |e| match e {
ServerEvent::Bas(e) => match e { ServerEvent::Bas(e) => match e {
BatteryServiceEvent::BatteryLevelCccdWrite { notifications } => { BatteryServiceEvent::BatteryLevelCccdWrite { notifications } => {
info!("battery notifications: {}", notifications) info!("battery notifications: {}", notifications)
@ -265,10 +267,19 @@ async fn gatt_task(server: Server, sd: &'static Softdevice) {
info!("text color indications: {}, notifications: {}", indications, notifications) info!("text color indications: {}, notifications: {}", indications, notifications)
} }
}, },
}) });
.await;
info!("gatt_server run exited with error: {:?}", e); pin_mut!(battery_fut);
pin_mut!(gatt_fut);
let _ = match select(battery_fut, gatt_fut).await {
Either::Left((_, _)) => {
info!("Battery encountered an error and stopped!")
}
Either::Right((e, _)) => {
info!("GATT run exited with error: {:?}", e);
}
};
} }
} }
@ -330,8 +341,7 @@ async fn touch_button(pin: Peri<'static, AnyPin>) {
} }
} }
#[embassy_executor::task] async fn battery_task<'a>(saadc: &'a mut Saadc<'_, 1>, server: &'a Server, connection: &'a Connection) {
async fn battery_task(mut saadc: Saadc<'static, 1>) {
const REFERENCE: f32 = 3.6; const REFERENCE: f32 = 3.6;
let mut measurements = [0i16; 4]; let mut measurements = [0i16; 4];
let mut index = 0; let mut index = 0;
@ -348,7 +358,10 @@ async fn battery_task(mut saadc: Saadc<'static, 1>) {
let total = (measurements.iter().sum::<i16>() / measurements.len() as i16) as u16; let total = (measurements.iter().sum::<i16>() / measurements.len() as i16) as u16;
let percent = battery_mv_to_percent(total); let percent = battery_mv_to_percent(total);
info!("Battery: {=i16}, {=u16}, {}%", voltage, total, percent); info!("Battery: {=i16}, {=u16}, {}%", voltage, total, percent);
Timer::after_millis(2000).await; if let Err(e) = server.bas.battery_level_notify(connection, &percent) {
error!("Error notifying battery level: {:?}", e);
}
Timer::after_millis(60000).await;
} }
} }
} }
@ -403,7 +416,7 @@ async fn actions_task() {
#[embassy_executor::task] #[embassy_executor::task]
async fn radar_task() { async fn radar_task() {
const MAX_TIME: usize = 24; const MAX_TIME: usize = 480;
let mut time = MAX_TIME; let mut time = MAX_TIME;
loop { loop {
let action = { let action = {