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-sync 0.7.2",
"embassy-time",
"futures",
"nrf-softdevice",
"panic-halt",
"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-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"] }
futures = { version = "0.3", default-features = false, features = [] }
[[bin]]
name = "odesa"

View File

@ -5,7 +5,7 @@ mod fmt;
use core::mem;
use core::ops::{AddAssign, SubAssign};
use defmt::Format;
use defmt::{error, Format};
#[cfg(not(feature = "defmt"))]
use panic_halt as _;
#[cfg(feature = "defmt")]
@ -16,18 +16,20 @@ use defmt::info;
use embassy_executor::Spawner;
use embassy_futures::join::{join3, join4};
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::{bind_interrupts, saadc, Peri};
use embassy_nrf::{bind_interrupts, interrupt, saadc, Peri};
use embassy_nrf::peripherals::SAADC;
use embassy_nrf::saadc::{ChannelConfig, Gain, Reference, Saadc};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_sync::signal::Signal;
use embassy_time::{with_timeout, Duration, Timer};
use futures::future::{select, Either};
use futures::pin_mut;
use nrf_softdevice::{raw, Softdevice};
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)]
enum SysAction {
@ -145,9 +147,11 @@ async fn main(spawner: Spawner) {
let server = Server::new(sd).expect("failed to enable softdevice");
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.reference = Reference::INTERNAL;
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_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(actions_task()).expect("failed to spawn actions 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()
.flags(&[Flag::GeneralDiscovery, Flag::LE_Only])
.services_16(ServiceList::Complete, &[ServiceUuid16::BATTERY])
@ -185,11 +189,9 @@ async fn gatt_task(server: Server, sd: &'static Softdevice) {
info!("advertising done!");
// Run the GATT server on the connection. This returns when the connection gets disconnected.
//
// Event enums (ServerEvent's) are generated by nrf_softdevice::gatt_server
// proc macro when applied to the Server struct above
let e = gatt_server::run(&conn, &server, |e| match e {
let battery_fut = battery_task(&mut saadc, &server, &conn);
let gatt_fut = gatt_server::run(&conn, &server, |e| match e {
ServerEvent::Bas(e) => match e {
BatteryServiceEvent::BatteryLevelCccdWrite { 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)
}
},
})
.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(mut saadc: Saadc<'static, 1>) {
async fn battery_task<'a>(saadc: &'a mut Saadc<'_, 1>, server: &'a Server, connection: &'a Connection) {
const REFERENCE: f32 = 3.6;
let mut measurements = [0i16; 4];
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 percent = battery_mv_to_percent(total);
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]
async fn radar_task() {
const MAX_TIME: usize = 24;
const MAX_TIME: usize = 480;
let mut time = MAX_TIME;
loop {
let action = {