Initial restructuring after _actual_ spec added
This commit is contained in:
@ -1,6 +1,19 @@
|
||||
/*
|
||||
BLE Server
|
||||
|
||||
This module is responsible for:
|
||||
- Setting up the bluetooth GAP profile
|
||||
- Setting up the GATT characteristics
|
||||
- Managing the advertising and pairing modes
|
||||
- Taking writeable GATT characteristics and putting them in the event q
|
||||
- taking status events from the q and putting them in the read GATT characteristics
|
||||
|
||||
TODO: Consider splitting up these tasks.
|
||||
|
||||
*/
|
||||
|
||||
use log::*; //{trace, debug, info, warn, error}
|
||||
use esp32_nimble::{enums::*, uuid128, BLEAdvertisementData, BLEDevice, BLEServer, NimbleProperties, OnWriteArgs};
|
||||
use esp32_nimble::{enums::*, uuid128, BLEAdvertisementData, BLEDevice, BLEServer, DescriptorProperties, NimbleProperties, OnWriteArgs};
|
||||
use esp32_nimble::utilities::BleUuid;
|
||||
use anyhow::Result;
|
||||
use closure::closure;
|
||||
@ -14,6 +27,9 @@ use gem_remotes_lib::{
|
||||
DispatchSendQ,
|
||||
Commands,
|
||||
Button,
|
||||
EMPTY_MOTORS,
|
||||
EMPTY_LIMITS,
|
||||
Statuses,
|
||||
};
|
||||
|
||||
// TODO HARDWARE: test these values to see if they are suitable
|
||||
@ -37,10 +53,26 @@ const DEVICE_NAME: &str = "Gem Remotes";
|
||||
const UUID_SERVICE_PAIR: BleUuid = BleUuid::from_uuid128([0xB4, 0x09, 0x8D, 0xE0, 0x61, 0x08, 0x66, 0xBA, 0x61, 0x4B, 0x3C, 0xF1, 0x5A, 0xAD, 0x66, 0x99]);
|
||||
const UUID_SERVICE_LIFT: BleUuid = uuid128!("c1400000-8dda-45a3-959b-d23a0f8f53d7");
|
||||
|
||||
// Command Characteristics
|
||||
const UUID_BUTTON_UP: BleUuid = uuid128!("c1401121-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BUTTON_DOWN: BleUuid = uuid128!("c1401122-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BUTTON_STOP: BleUuid = uuid128!("c1401123-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BLUETOOTH_NAME: BleUuid = uuid128!("c1401224-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BUTTON_AUX: BleUuid = uuid128!("c1401124-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BUTTON_LEARN: BleUuid = uuid128!("c1401223-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BUTTON_AUTO: BleUuid = uuid128!("c1401225-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_BLUETOOTH_NAME: BleUuid = uuid128!("c1411224-8dda-45a3-959b-d23a0f8f53d7");
|
||||
|
||||
// Status Characteristics
|
||||
const UUID_STATUS_LIMITS: BleUuid = uuid128!("c1401321-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_STATUS_MOTOR: BleUuid = uuid128!("c1401322-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_STATUS_STATUS: BleUuid = uuid128!("c1401323-8dda-45a3-959b-d23a0f8f53d7");
|
||||
const UUID_STATUS_REASON: BleUuid = uuid128!("c1401324-8dda-45a3-959b-d23a0f8f53d7");
|
||||
|
||||
// Expanded Services
|
||||
const UUID_EXPANDED_SSID: BleUuid = uuid128!("c1411221-8dda-45a3-959b-d23a0f8f53d7"); //IMPLIMENT
|
||||
const UUID_EXPANDED_WIFI_PASS: BleUuid = uuid128!("c1411222-8dda-45a3-959b-d23a0f8f53d7"); //IMPLIMENT
|
||||
const UUID_EXPANDED_LOG_TRIGGER: BleUuid = uuid128!("c1401421-8dda-45a3-959b-d23a0f8f53d7"); //IMPLIMENT
|
||||
const UUID_EXPANDED_LOG_DATA: BleUuid = uuid128!("c1401422-8dda-45a3-959b-d23a0f8f53d7"); //IMPLIMENT
|
||||
|
||||
const BLE_BUTTON_RELEASE: u8 = 0;
|
||||
const BLE_BUTTON_PRESS: u8 = 1;
|
||||
@ -56,13 +88,15 @@ pub struct BleServer {
|
||||
impl BleServer {
|
||||
pub fn new(dp: &mut Dispatch) -> Self {
|
||||
let cmds = vec![
|
||||
Commands::NotifyMotorDown { data: Button::Released },
|
||||
Commands::NotifyMotorStop { data: Button::Released },
|
||||
Commands::NotifyMotorUp { data: Button::Released },
|
||||
Commands::PairTimerExpired,
|
||||
Commands::AllowPairing,
|
||||
Commands::EraseBleBonds,
|
||||
Commands::BluetoothName { data: Arc::new(String::new())},
|
||||
Commands::BluetoothStatusLimits { data: EMPTY_LIMITS },
|
||||
Commands::BluetoothStatusMotor { data: EMPTY_MOTORS },
|
||||
Commands::BluetoothStatusStatus { data: Statuses::empty() },
|
||||
Commands::BluetoothStatusReason { data: Arc::<String>::new("".to_string()) },
|
||||
//TODONOW! We need to add the status commands here!
|
||||
];
|
||||
let r = dp.get_callback_channel(&cmds);
|
||||
let s = dp.get_cmd_channel();
|
||||
@ -96,16 +130,18 @@ impl BleServer {
|
||||
// --- Button Up Bluetooth GATT ----------------------------------------------------------
|
||||
let button_up = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_UP,
|
||||
NimbleProperties::READ | NimbleProperties::WRITE_NO_RSP | NimbleProperties::NOTIFY,
|
||||
NimbleProperties::WRITE,
|
||||
);
|
||||
button_up.lock().set_value(&[0])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothUp {data: Button::Released})
|
||||
}));
|
||||
let button_up_name = button_up.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
|
||||
button_up_name.lock().set_value(b"Command Up");
|
||||
// --- Button Down Bluetooth GATT --------------------------------------------------------
|
||||
let button_down = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_DOWN,
|
||||
NimbleProperties::READ | NimbleProperties::WRITE_NO_RSP | NimbleProperties::NOTIFY,
|
||||
NimbleProperties::WRITE,
|
||||
);
|
||||
button_down.lock().set_value(&[0])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
@ -114,21 +150,69 @@ impl BleServer {
|
||||
// --- Button Stop Bluetooth GATT --------------------------------------------------------
|
||||
let button_stop = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_STOP,
|
||||
NimbleProperties::READ | NimbleProperties::WRITE_NO_RSP | NimbleProperties::NOTIFY,
|
||||
NimbleProperties::WRITE,
|
||||
);
|
||||
button_stop.lock().set_value(&[1])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothStop {data: Button::Released})
|
||||
}));
|
||||
// --- Button Aux Bluetooth GATT --------------------------------------------------------
|
||||
let button_aux = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_AUX,
|
||||
NimbleProperties::WRITE,
|
||||
);
|
||||
button_aux.lock().set_value(&[0])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothAux {data: Button::Released})
|
||||
}));
|
||||
// --- Button Learn Bluetooth GATT --------------------------------------------------------
|
||||
let button_learn = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_LEARN,
|
||||
NimbleProperties::WRITE | NimbleProperties::READ,
|
||||
);
|
||||
button_learn.lock().set_value(&[0])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothLearn {data: Button::Released})
|
||||
}));
|
||||
// --- Button Auto Bluetooth GATT --------------------------------------------------------
|
||||
let button_auto = lift_service.lock().create_characteristic(
|
||||
UUID_BUTTON_AUTO,
|
||||
NimbleProperties::WRITE,
|
||||
);
|
||||
button_auto.lock().set_value(&[0])
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothAuto {data: Button::Released})
|
||||
}));
|
||||
// --- Device Name Bluetooth GATT --------------------------------------------------------
|
||||
let device_name = lift_service.lock().create_characteristic(
|
||||
UUID_BLUETOOTH_NAME,
|
||||
NimbleProperties::READ | NimbleProperties::WRITE,
|
||||
NimbleProperties::WRITE | NimbleProperties::READ,
|
||||
);
|
||||
device_name.lock().set_value(self.dev_name.as_bytes())
|
||||
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
|
||||
on_bluetooth_cmd(&sender, args, Commands::BluetoothName { data: Arc::new(String::new())}.clone())
|
||||
}));
|
||||
// --- Status Limits Bluetooth GATT --------------------------------------------------------
|
||||
let status_limits = lift_service.lock().create_characteristic(
|
||||
UUID_STATUS_LIMITS,
|
||||
NimbleProperties::READ | NimbleProperties::INDICATE,
|
||||
);
|
||||
// --- Status Motor Bluetooth GATT --------------------------------------------------------
|
||||
let status_motor = lift_service.lock().create_characteristic(
|
||||
UUID_STATUS_MOTOR,
|
||||
NimbleProperties::READ | NimbleProperties::INDICATE,
|
||||
);
|
||||
// --- Status Status Bluetooth GATT --------------------------------------------------------
|
||||
let status_status = lift_service.lock().create_characteristic(
|
||||
UUID_STATUS_STATUS,
|
||||
NimbleProperties::READ | NimbleProperties::INDICATE,
|
||||
);
|
||||
// --- Status Reason Bluetooth GATT --------------------------------------------------------
|
||||
let status_reason = lift_service.lock().create_characteristic(
|
||||
UUID_STATUS_REASON,
|
||||
NimbleProperties::READ | NimbleProperties::INDICATE,
|
||||
);
|
||||
|
||||
// Default to not pairable
|
||||
self.advertise_unpairable()?;
|
||||
|
||||
@ -137,23 +221,29 @@ impl BleServer {
|
||||
let cmd =self.recv_q.recv().await.expect("Bluetooth notification queue unexpectedly closed");
|
||||
trace!("Received update to bluetooth variable {:?}", cmd);
|
||||
match cmd {
|
||||
// TODO DISCUSS: This logic (if one button is pressed others are released) could be done in app instead.
|
||||
Commands::NotifyMotorUp{data} => {
|
||||
button_up.lock().set_value(&button_to_ble_button(data)).notify();
|
||||
// Handle events that require bluetooth, such as status and pairing changes
|
||||
|
||||
//Status changes to notify app on:
|
||||
Commands::BluetoothStatusLimits{data} => {
|
||||
status_limits.lock().set_value(&data.as_bytes()).notify(); // Also handles indicate
|
||||
}
|
||||
Commands::NotifyMotorDown{data} => {
|
||||
button_down.lock().set_value(&button_to_ble_button(data)).notify();
|
||||
Commands::BluetoothStatusMotor{data} => {
|
||||
status_motor.lock().set_value(&data.as_bytes()).notify(); // Also handles indicate
|
||||
}
|
||||
Commands::NotifyMotorStop{data} => {
|
||||
button_up.lock().set_value(&button_to_ble_button(data)).notify();
|
||||
Commands::BluetoothStatusStatus{data} => {
|
||||
status_status.lock().set_value(&data.to_le_bytes()).notify(); // Also handles indicate
|
||||
}
|
||||
Commands::BluetoothStatusReason{data} => {
|
||||
status_reason.lock().set_value(data.as_str().as_bytes()).notify(); // Also handles indicate
|
||||
}
|
||||
|
||||
Commands::PairTimerExpired => {
|
||||
self.advertise_unpairable()?;
|
||||
self.send_q.send(Commands::PairTimerClear).await?;
|
||||
}
|
||||
Commands::AllowPairing => {
|
||||
self.advertise_pairable()?;
|
||||
debug!("pairing mode / non-pairing mode not currently supported");
|
||||
debug!("pairing mode / non-pairing mode not currently supported"); //TODO Really? Didn't we just test this?
|
||||
}
|
||||
Commands::EraseBleBonds => {
|
||||
ble_device.delete_all_bonds().expect("Failed trying to erase bluetooth bonding information");
|
||||
@ -233,6 +323,15 @@ fn on_bluetooth_cmd(sender: &DispatchSendQ, args: &mut OnWriteArgs, cmd: Command
|
||||
sender.send_blocking(Commands::BluetoothName { data: Arc::new(String::from_str(DEVICE_NAME).unwrap()) })
|
||||
}
|
||||
}
|
||||
Commands::BluetoothAuto { data: _ } => {
|
||||
sender.send_blocking(Commands::BluetoothAuto { data: ble_to_button(v) })
|
||||
}
|
||||
Commands::BluetoothAux { data: _ } => {
|
||||
sender.send_blocking(Commands::BluetoothAux { data: ble_to_button(v) })
|
||||
}
|
||||
Commands::BluetoothLearn { data: _ } => {
|
||||
sender.send_blocking(Commands::BluetoothLearn { data: ble_to_button(v) })
|
||||
}
|
||||
//TODO when we get name changes, truncate to 31 chars, because that's what we have anyway.
|
||||
_ => {error!("Tried to handle an unknown bluetooth command: {:?}",cmd);Ok(())}
|
||||
};
|
||||
@ -290,12 +389,5 @@ fn set_server_callbacks(server: &mut BLEServer, sender: DispatchSendQ) {
|
||||
});
|
||||
}
|
||||
|
||||
fn button_to_ble_button(but: Button) -> [u8; 1] {
|
||||
match but {
|
||||
Button::Released => {[BLE_BUTTON_RELEASE]}
|
||||
Button::Pressed => {[BLE_BUTTON_PRESS]}
|
||||
}
|
||||
}
|
||||
|
||||
//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.
|
||||
@ -1,5 +1,5 @@
|
||||
const BUTTON_HOLD_TIME_MS: u64 = 1_200;
|
||||
const STOP_SAFETY_TIME_MS: u64 = 2_000;
|
||||
const STOP_SAFETY_TIME_MS: u64 = 3_000;
|
||||
const PAIR_TIME_MS: u64 = 30_000;
|
||||
|
||||
// Crates used in release
|
||||
@ -12,7 +12,7 @@ use std::ops::Deref;
|
||||
|
||||
use gem_remotes_lib::{
|
||||
Commands,
|
||||
Controller,
|
||||
FakePic,
|
||||
Dispatch,
|
||||
};
|
||||
|
||||
@ -20,10 +20,8 @@ use gem_remotes_lib::{
|
||||
mod test_console;
|
||||
|
||||
// Release modules
|
||||
mod motor_driver;
|
||||
mod message_timer;
|
||||
mod ble_server;
|
||||
mod pair_button_driver;
|
||||
|
||||
use crate::message_timer::MessageTimer;
|
||||
//use crate::commands::Commands;
|
||||
@ -72,12 +70,8 @@ async fn main_loop() -> Result<()> {
|
||||
// Create dispatch early so it can outlive most other things
|
||||
let mut dp = Dispatch::new();
|
||||
|
||||
// Debug Drivers (TODO DEBUG: remove debug)
|
||||
let motor_driver = motor_driver::MotorDriverDebug::new();
|
||||
|
||||
// Setup of various drivers that need to out-live the executor
|
||||
let m_chan = Controller::prepare_controller(&mut dp);
|
||||
let mut motor_control = Controller::new(m_chan, dp.get_cmd_channel(), motor_driver.get_endpoint());
|
||||
let mut f_pic = FakePic::with_defaults(&mut dp);
|
||||
// Setup callback timers
|
||||
let mut button_timer = MessageTimer::<Commands, Commands>::new_on_dispatch(
|
||||
Commands::ButtonTimerRestart,
|
||||
@ -107,12 +101,11 @@ async fn main_loop() -> Result<()> {
|
||||
tasks.push(executor.spawn(test_console::start_cli(cli_endpoint)));
|
||||
|
||||
// Queueu up our async tasks
|
||||
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(f_pic.run()));
|
||||
tasks.push(executor.spawn(dp.cmd_loop()));
|
||||
|
||||
//Once we have all our tasks, await on them all to run them in parallel.
|
||||
|
||||
@ -30,6 +30,7 @@ pub struct MessageTimer <Q, S> {
|
||||
}
|
||||
|
||||
impl<Q: PartialEq, S: Clone> MessageTimer<Q, S> {
|
||||
/*
|
||||
pub fn new(
|
||||
restart: Q,
|
||||
cancel: Q,
|
||||
@ -48,6 +49,7 @@ impl<Q: PartialEq, S: Clone> MessageTimer<Q, S> {
|
||||
state: State::Stopped,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn new_on_dispatch(
|
||||
restart: Commands,
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
/// Handles the actual hardware interface with motor or its controller.
|
||||
|
||||
use log::*; //{trace, debug, info, warn, error}
|
||||
use anyhow::Result;
|
||||
use async_channel::unbounded;
|
||||
use gem_remotes_lib::{MotorCommands, MotorRecvQ, MotorSendQ};
|
||||
|
||||
|
||||
pub struct MotorDriverDebug{
|
||||
endpoint: MotorSendQ, // Endpoint to hand to dispatch or anyone else sending commands here.
|
||||
recv_q: MotorRecvQ,
|
||||
}
|
||||
|
||||
/// Debug / example version of Motor Driver.
|
||||
impl MotorDriverDebug {
|
||||
pub fn new() -> Self {
|
||||
let (s,r) = unbounded(); // TODO: reserve a reasonable amount for all unbounded?
|
||||
MotorDriverDebug {
|
||||
endpoint: s,
|
||||
recv_q: r,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_endpoint(&self) -> MotorSendQ {
|
||||
self.endpoint.clone()
|
||||
}
|
||||
|
||||
pub async fn run(&self) -> Result<()> {
|
||||
loop {
|
||||
let cmd = self.recv_q.recv()
|
||||
.await
|
||||
.expect("Unexpected failure in motor driver command queue");
|
||||
self.handle_cmd(cmd)
|
||||
.await
|
||||
.expect("Unexpected failure of motor driver notification queue");
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_cmd(&self, cmd: MotorCommands) -> Result<()> {
|
||||
match cmd {
|
||||
MotorCommands::StartUp => {self.start_up().await?;}
|
||||
MotorCommands::StartDown => {self.start_down().await?;}
|
||||
MotorCommands::Stop => {self.stop().await?;}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_up(&self) -> Result<()> {
|
||||
warn!("Starting motor, direction: Up");
|
||||
Ok(())
|
||||
}
|
||||
async fn start_down(&self) -> Result<()> {
|
||||
warn!("Starting motor, direction: Down");
|
||||
Ok(())
|
||||
}
|
||||
async fn stop(&self) -> Result<()> {
|
||||
warn!("Stopping motor");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//TODO: we should fix panic to ensure that we shut down motors before rebooting ESP!
|
||||
// Maybe by getting another endpoint and passing it to the panic handler? Add a different
|
||||
// command that doesn't just stop, but stops and stops processing any new commands.
|
||||
|
||||
//TODO: Design - are there any implications to the PIC motor driver essentially sending button
|
||||
// presses instead of commanding the motor on/off? Feedback loops? No way to know without PIC
|
||||
// code.
|
||||
@ -1,34 +0,0 @@
|
||||
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 gem_remotes_lib::{
|
||||
Commands,
|
||||
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(10_000)).await?; // no need to panic on test console driver timer failure
|
||||
//When we find a press, send PicRecvPair
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,26 +35,6 @@ use gem_remotes_lib::{
|
||||
|
||||
#[derive(Command)]
|
||||
pub enum Menu{//<'a> {
|
||||
/// Simulate the PIC controller sending aus n Up character
|
||||
PicRecvUp {
|
||||
/// 0 for not pressed, 1 for pressed
|
||||
data: u8,
|
||||
},
|
||||
|
||||
/// Simulate the PIC controller sending us a Down character
|
||||
PicRecvDown {
|
||||
/// 0 for not pressed, 1 for pressed
|
||||
data: u8,
|
||||
},
|
||||
|
||||
/// Simulate the PIC controller sending us a Stop character
|
||||
PicRecvStop {
|
||||
/// 0 for not pressed, 1 for pressed
|
||||
data: u8,
|
||||
},
|
||||
|
||||
/// Simulate the PIC controller sending a "pair" button press
|
||||
PicRecvPair,
|
||||
|
||||
/// Send a bluetooth characteristic: Up
|
||||
BluetoothUp {
|
||||
@ -121,40 +101,6 @@ pub fn process_menu(
|
||||
match command {
|
||||
// We ignore sending errors throughout because the Cli interface is only for
|
||||
// testing and debugging.
|
||||
Menu::PicRecvUp {data} => {
|
||||
let but = input_to_button(data);
|
||||
match but {
|
||||
Some(d) => {
|
||||
println!("Sending PicRecvUp command");
|
||||
let _ = dispatch.send_blocking(Commands::PicRecvUp{data: d});
|
||||
}
|
||||
None => {println!("Incorrect value; enter 0 or 1")}
|
||||
}
|
||||
}
|
||||
Menu::PicRecvDown{data} => {
|
||||
let but = input_to_button(data);
|
||||
match but {
|
||||
Some(d) => {
|
||||
println!("Sending PicRecvUp command");
|
||||
let _ = dispatch.send_blocking(Commands::PicRecvDown{data: d});
|
||||
}
|
||||
None => {println!("Incorrect value; enter 0 or 1")}
|
||||
}
|
||||
}
|
||||
Menu::PicRecvStop{data} => {
|
||||
let but = input_to_button(data);
|
||||
match but {
|
||||
Some(d) => {
|
||||
println!("Sending PicRecvUp command");
|
||||
let _ = dispatch.send_blocking(Commands::PicRecvStop{data: d});
|
||||
}
|
||||
None => {println!("Incorrect value; enter 0 or 1")}
|
||||
}
|
||||
}
|
||||
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 } => {
|
||||
let but = input_to_button(data);
|
||||
match but {
|
||||
|
||||
Reference in New Issue
Block a user