work in progress on switching to direct mode

This commit is contained in:
2024-08-24 20:53:20 -04:00
parent a53584ab82
commit 802285d0ec
5 changed files with 99 additions and 8 deletions

View File

@ -34,6 +34,9 @@ impl BleServer {
Commands::NotifyMotorDown { data: 0 },
Commands::NotifyMotorStop { data: 0 },
Commands::NotifyMotorUp { data: 0 },
Commands::PairTimerExpired,
Commands::AllowPairing,
Commands::EraseBleBonds,
];
let r = dp.get_callback_channel(&cmds);
let s = dp.get_cmd_channel();
@ -55,7 +58,7 @@ impl BleServer {
let ble_device = BLEDevice::take();
set_device_security(ble_device);
let server = ble_device.get_server();
set_server_callbacks(server);
set_server_callbacks(server, self.send_q.clone());
let _pairing_service = server.create_service(UUID_SERVICE_PAIR);
let lift_service = server.create_service(UUID_SERVICE_LIFT);
@ -94,7 +97,7 @@ impl BleServer {
let ble_advertiser = ble_device.get_advertising();
// TODO: we will need to enable / disable the ability to pair!
advertise_pairing(ble_advertiser)?;
advertise(ble_advertiser)?;
loop {
debug!("Waiting for updates that should be notified via bluetooth");
@ -111,6 +114,16 @@ impl BleServer {
Commands::NotifyMotorStop{data} => {
button_up.lock().set_value(&[data]).notify();
}
Commands::PairTimerExpired => {
advertise_to_direct(ble_advertiser).expect("Failed to exit pairing mode");
self.send_q.send(Commands::PairTimerClear).await?;
}
Commands::AllowPairing => {
advertise_to_undirected(ble_advertiser).expect("Failed to enter pairing mode");
}
Commands::EraseBleBonds => {
ble_device.delete_all_bonds().expect("Failed trying to erase bluetooth bonding information");
}
_ => {
error!("Invalid command received by bluetooth handler {:?}", cmd);
// No need to reboot as state is recoverable.
@ -150,7 +163,7 @@ fn on_bluetooth_cmd(sender: &SendQ, args: &mut OnWriteArgs, cmd: Commands) {
fn set_device_security(dev: &mut BLEDevice) {
dev.security()
// Enable all security protections
// Enable all security protections (including bond, so that bond info is saved)
.set_auth(AuthReq::all())
// Options we support for putting in pairing info.
// "NoInputOutput" means that we will have "just works" pairing
@ -159,8 +172,8 @@ fn set_device_security(dev: &mut BLEDevice) {
.resolve_rpa();
}
fn set_server_callbacks(server: &mut BLEServer) {
server.on_connect(|server, clntdesc| {
fn set_server_callbacks(server: &mut BLEServer, sender: SendQ) {
server.on_connect(move |server, clntdesc| {
// Print connected client data
info!("client connected: {:?}", clntdesc);
// Update connection parameters
@ -172,24 +185,40 @@ fn set_server_callbacks(server: &mut BLEServer) {
BLE_LATENCY,
BLE_TIMEOUT,
).unwrap();
sender.send_blocking(Commands::PairTimerClear).unwrap();
// TODO: Cancel pairing mode timeout
});
server.on_disconnect(|_desc, _reason| {
info!("Disconnected, back to advertising");
});
}
fn advertise_pairing(advertiser: &Mutex<BLEAdvertising>) -> Result<()> {
fn advertise(advertiser: &Mutex<BLEAdvertising>) -> Result<()> {
trace!("Setting up advertiser");
advertiser
.lock()
.advertisement_type(ConnMode::Und)
.set_data(
BLEAdvertisementData::new()
.name(DEVICE_NAME)
.add_service_uuid(UUID_SERVICE_PAIR)
)?;
// TODO: this appears to run in its own thread; verify.
// TODO: isn't there a restart? We'll need to switch between pairing and not.
info!("Staring Bluetooth Server");
advertiser.lock().start()?;
Ok(())
}
fn advertise_to_direct(advertiser: &Mutex<BLEAdvertising>) -> Result<()> {
advertiser.lock().stop()?;
advertiser.lock().advertisement_type(ConnMode::Dir).start()?;
Ok(())
}
fn advertise_to_undirected(advertiser: &Mutex<BLEAdvertising>) -> Result<()> {
advertiser.lock().stop()?;
advertiser.lock().advertisement_type(ConnMode::Und).start()?;
Ok(())
}
//TODO set maximum pairs to remember?
//TODO after disconnect, it returns to scanning - will it return to directed scanning? Find out when directed is working.

View File

@ -23,10 +23,15 @@ pub enum Commands {
ButtonTimerExpired,
ButtonTimerRestart,
ButtonTimerClear,
PairTimerExpired,
AllowPairing, // Also serves as the timer restart command
PairTimerClear,
NotifyMotorUp {data: u8},
NotifyMotorDown {data: u8},
NotifyMotorStop {data: u8},
EraseBleBonds,
}
#[non_exhaustive]

View File

@ -1,5 +1,6 @@
const BUTTON_HOLD_TIME_MS: u64 = 500;
const STOP_SAFETY_TIME_MS: u64 = 2000;
const PAIR_TIME_MS: u64 = 10000; //180000; TODO:Debug go back to 3 minutes from 10s
// Crates used in release
use log::*; //{trace, debug, info, warn, error}
@ -19,12 +20,15 @@ mod motor_controller;
mod motor_driver;
mod message_timer;
mod ble_server;
mod pair_button_driver;
use crate::message_timer::MessageTimer;
use crate::commands::Commands;
//TODO: limit switch driver, would be good in long run if it checked limit switches periodically (every 1s?) to ensure they are still functioning
//TODO: pair button driver, listens to PIC uart or eventually physical button, sends pairing active command and resets pairing timer.
fn main() {
// Do basic initialization
esp_idf_svc::sys::link_patches();
@ -84,6 +88,12 @@ async fn main_loop() -> Result<()> {
Commands::StopTimerExpired,
STOP_SAFETY_TIME_MS,
&mut dp);
let mut pairing_timer = MessageTimer::<Commands, Commands>::new_on_dispatch(
Commands::AllowPairing,
Commands::PairTimerClear,
Commands::PairTimerExpired,
PAIR_TIME_MS,
&mut dp);
let ble_server = ble_server::BleServer::new(&mut dp);
let executor = Executor::new();
@ -97,6 +107,7 @@ async fn main_loop() -> Result<()> {
tasks.push(executor.spawn(motor_control.run()));
tasks.push(executor.spawn(button_timer.run()));
tasks.push(executor.spawn(stopping_timer.run()));
tasks.push(executor.spawn(pairing_timer.run()));
tasks.push(executor.spawn(ble_server.run()));
tasks.push(executor.spawn(motor_driver.run()));
tasks.push(executor.spawn(dp.cmd_loop()));

View File

@ -0,0 +1,32 @@
use log::*; //{trace, debug, info, warn, error}
use anyhow::Result;
use async_channel::Sender;
use esp_idf_svc::timer::EspTaskTimerService;
use core::time::Duration;
use crate::commands::Commands;
use crate::dispatch::Dispatch;
type SendQ = Sender<Commands>;
pub struct PairButtonDriver {
_send: SendQ
}
impl PairButtonDriver {
pub fn new(dp: &mut Dispatch) -> Self {
let s = dp.get_cmd_channel();
Self { _send: s }
}
pub async fn run(&self) -> Result<()> {
let timer_service = EspTaskTimerService::new()?;
let mut async_timer = timer_service.timer_async()?;
debug!("Waiting on pairing button presses");
loop {
//TO DO: Watch for incoming pair button presses from the PIC and/or hardware buttons
async_timer.after(Duration::from_millis(10000)).await?; // no need to panic on test console driver timer failure
//When we find a press, send PicRecvPair
}
}
}

View File

@ -39,6 +39,9 @@ pub enum Menu<'a> {
/// Simulate the PIC controller sending us a Stop character
PicRecvStop,
/// Simulate the PIC controller sending a "pair" button press
PicRecvPair,
/// Send a bluetooth characteristic: Up
BluetoothUp {
/// 0 for not pressed, 1 for pressed
@ -74,11 +77,15 @@ pub enum Menu<'a> {
/// Send a bluetooth characteristic: Wifi Password
BluetoothWifiPassword { wifipass: &'a str },
/// Change log level (None: 0, .. Tracing: 5)
Log { level: u8 },
/// Abort (resets microcontroller)
Abort,
/// Erase BLE Bonding information
ClearBleBonds,
}
pub fn process_menu(
@ -101,6 +108,10 @@ pub fn process_menu(
cli.writer().write_str("Sending PicButtonStop command")?;
let _ = dispatch.send_blocking(Commands::PicRecvStop);
}
Menu::PicRecvPair => {
cli.writer().write_str("Sending PIC command and timer reset (the job of the pair button driver, once PIC interface exists)")?; //TODO: PIC get this.
let _ = dispatch.send_blocking(Commands::AllowPairing);
}
Menu::BluetoothUp { data } => {
cli.writer()
.write_str("Sending BluetoothUp")?;
@ -180,6 +191,9 @@ pub fn process_menu(
trace!("trace test");
}
Menu::Abort => {panic!("CLI user requested abort");}
Menu::ClearBleBonds => {
let _ = dispatch.send_blocking(Commands::EraseBleBonds);
}
}
Ok(())
}