tweaking to fix misc. fake pic errors

This commit is contained in:
2024-11-03 15:29:40 -05:00
parent 045237d44f
commit 26cd5584e9
5 changed files with 223 additions and 75 deletions

View File

@ -147,6 +147,8 @@ impl BleServer {
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| { .on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
on_bluetooth_cmd(&sender, args, Commands::BluetoothDown {data: Button::Released}) on_bluetooth_cmd(&sender, args, Commands::BluetoothDown {data: Button::Released})
})); }));
let button_down_name = button_down.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
button_down_name.lock().set_value(b"Command Down");
// --- Button Stop Bluetooth GATT -------------------------------------------------------- // --- Button Stop Bluetooth GATT --------------------------------------------------------
let button_stop = lift_service.lock().create_characteristic( let button_stop = lift_service.lock().create_characteristic(
UUID_BUTTON_STOP, UUID_BUTTON_STOP,
@ -156,6 +158,8 @@ impl BleServer {
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| { .on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
on_bluetooth_cmd(&sender, args, Commands::BluetoothStop {data: Button::Released}) on_bluetooth_cmd(&sender, args, Commands::BluetoothStop {data: Button::Released})
})); }));
let button_stop_name = button_stop.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
button_stop_name.lock().set_value(b"Command Stop");
// --- Button Aux Bluetooth GATT -------------------------------------------------------- // --- Button Aux Bluetooth GATT --------------------------------------------------------
let button_aux = lift_service.lock().create_characteristic( let button_aux = lift_service.lock().create_characteristic(
UUID_BUTTON_AUX, UUID_BUTTON_AUX,
@ -165,6 +169,8 @@ impl BleServer {
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| { .on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
on_bluetooth_cmd(&sender, args, Commands::BluetoothAux {data: Button::Released}) on_bluetooth_cmd(&sender, args, Commands::BluetoothAux {data: Button::Released})
})); }));
let button_aux_name = button_aux.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
button_aux_name.lock().set_value(b"Command Aux");
// --- Button Learn Bluetooth GATT -------------------------------------------------------- // --- Button Learn Bluetooth GATT --------------------------------------------------------
let button_learn = lift_service.lock().create_characteristic( let button_learn = lift_service.lock().create_characteristic(
UUID_BUTTON_LEARN, UUID_BUTTON_LEARN,
@ -174,6 +180,8 @@ impl BleServer {
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| { .on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
on_bluetooth_cmd(&sender, args, Commands::BluetoothLearn {data: Button::Released}) on_bluetooth_cmd(&sender, args, Commands::BluetoothLearn {data: Button::Released})
})); }));
let button_learn_name = button_learn.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
button_learn_name.lock().set_value(b"Command Learn");
// --- Button Auto Bluetooth GATT -------------------------------------------------------- // --- Button Auto Bluetooth GATT --------------------------------------------------------
let button_auto = lift_service.lock().create_characteristic( let button_auto = lift_service.lock().create_characteristic(
UUID_BUTTON_AUTO, UUID_BUTTON_AUTO,
@ -183,6 +191,8 @@ impl BleServer {
.on_write(closure!(clone sender, |args: &mut OnWriteArgs| { .on_write(closure!(clone sender, |args: &mut OnWriteArgs| {
on_bluetooth_cmd(&sender, args, Commands::BluetoothAuto {data: Button::Released}) on_bluetooth_cmd(&sender, args, Commands::BluetoothAuto {data: Button::Released})
})); }));
let button_auto_name = button_auto.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
button_auto_name.lock().set_value(b"Command Learn");
// --- Device Name Bluetooth GATT -------------------------------------------------------- // --- Device Name Bluetooth GATT --------------------------------------------------------
let device_name = lift_service.lock().create_characteristic( let device_name = lift_service.lock().create_characteristic(
UUID_BLUETOOTH_NAME, UUID_BLUETOOTH_NAME,
@ -197,21 +207,29 @@ impl BleServer {
UUID_STATUS_LIMITS, UUID_STATUS_LIMITS,
NimbleProperties::READ | NimbleProperties::INDICATE, NimbleProperties::READ | NimbleProperties::INDICATE,
); );
let status_limits_name = status_limits.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
status_limits_name.lock().set_value(b"Status of limits");
// --- Status Motor Bluetooth GATT -------------------------------------------------------- // --- Status Motor Bluetooth GATT --------------------------------------------------------
let status_motor = lift_service.lock().create_characteristic( let status_motor = lift_service.lock().create_characteristic(
UUID_STATUS_MOTOR, UUID_STATUS_MOTOR,
NimbleProperties::READ | NimbleProperties::INDICATE, NimbleProperties::READ | NimbleProperties::INDICATE,
); );
let status_motor_name = status_limits.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
status_motor_name.lock().set_value(b"Status of motors");
// --- Status Status Bluetooth GATT -------------------------------------------------------- // --- Status Status Bluetooth GATT --------------------------------------------------------
let status_status = lift_service.lock().create_characteristic( let status_status = lift_service.lock().create_characteristic(
UUID_STATUS_STATUS, UUID_STATUS_STATUS,
NimbleProperties::READ | NimbleProperties::INDICATE, NimbleProperties::READ | NimbleProperties::INDICATE,
); );
let status_status_name = status_limits.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
status_status_name.lock().set_value(b"Status flags");
// --- Status Reason Bluetooth GATT -------------------------------------------------------- // --- Status Reason Bluetooth GATT --------------------------------------------------------
let status_reason = lift_service.lock().create_characteristic( let status_reason = lift_service.lock().create_characteristic(
UUID_STATUS_REASON, UUID_STATUS_REASON,
NimbleProperties::READ | NimbleProperties::INDICATE, NimbleProperties::READ | NimbleProperties::INDICATE,
); );
let status_reason_name = status_limits.lock().create_descriptor(BleUuid::Uuid16(0x2901), DescriptorProperties::READ);
status_reason_name.lock().set_value(b"Status reason");
// Default to not pairable // Default to not pairable
self.advertise_unpairable()?; self.advertise_unpairable()?;

View File

@ -100,6 +100,7 @@ impl<Q: PartialEq, S: Clone> MessageTimer<Q, S> {
Err(_) => { Err(_) => {
trace!("Timeout reached"); trace!("Timeout reached");
self.send_q.send(self.done.clone()).await.expect("Failed to send timeout"); self.send_q.send(self.done.clone()).await.expect("Failed to send timeout");
self.state = State::Stopped;
} }
} }
} }

View File

@ -23,14 +23,14 @@ use ::{
//time::Duration, // could also use core::time::Duration? //time::Duration, // could also use core::time::Duration?
}, },
core::time::Duration, core::time::Duration,
std::sync::Arc,
}; };
use async_channel::Sender; use async_channel::Sender;
use log::*; //{trace, debug, info, warn, error} use log::*; //{trace, debug, info, warn, error}
use gem_remotes_lib::{ use gem_remotes_lib::{
Button, Button, Commands, LimitStatus, EMPTY_LIMITS
Commands
}; };
#[derive(Command)] #[derive(Command)]
@ -61,10 +61,37 @@ pub enum Menu{//<'a> {
/// 0 for not pressed, 1 for pressed /// 0 for not pressed, 1 for pressed
data: u8, data: u8,
}, },
/// Send a bluetooth characteristic: Limits /// Send a bluetooth characteristic: Aux
BluetoothTopLimit { data: u8 }, BluetoothAux {
/// Send a bluetooth characteristic: Limits /// 0 for not pressed, 1 for pressed
BluetoothBottomLimit { data: u8 }, data: u8,
},
/// Send command from Fake PIC to toggle Aux
FPicAux,
/// Send command from Fake PIC to toggle Auto
FPicAuto,
/// Send command from Fake PIC to trigger learn mode
FPicLearn,
/// Send command from Fake PIC that is button press Up
FPicUp,
/// Send command from Fake PIC that is button press Down
FPicDown,
/// Send command from Fake PIC that is button press Stop (Can also be used as Up or Down release)
FPicStop,
/// Send command from Fake PIC to toggle Panic
FPicPanic,
/// Send command from Fake PIC to engage Lockout
FPicLockout,
/// Clear limit for first limit
FPicLimitClear1,
/// Activate top limit for first limit
FPicLimitTop1,
/// Activate bottom limit for first limit
FPicLimitBottom1,
/// Set hardware fault (Reason will be given as "test fault")
FPicFault,
/// Have the fake PIC output its internal state
FPicOutput,
/// Send a bluetooth characteristic: Wifi SSID /// Send a bluetooth characteristic: Wifi SSID
//BluetoothWifiSsid { ssid: &'a str }, //BluetoothWifiSsid { ssid: &'a str },
@ -132,25 +159,81 @@ pub fn process_menu(
} }
} }
Menu::BluetoothLearn { data } => { Menu::BluetoothLearn { data } => {
cli.writer() let but = input_to_button(data);
.write_str("TODO: simulate bluetooth characteristic change")?; match but {
let _ = data; Some(d) => {
println!("Sending PicRecvUp command");
let _ = dispatch.send_blocking(Commands::BluetoothLearn{data: d});
}
None => {println!("Incorrect value; enter 0 or 1")}
}
} }
Menu::BluetoothAuto { data } => { Menu::BluetoothAuto { data } => {
cli.writer() let but = input_to_button(data);
.write_str("TODO: simulate bluetooth characteristic change")?; match but {
let _ = data; Some(d) => {
println!("Sending PicRecvUp command");
let _ = dispatch.send_blocking(Commands::BluetoothAuto{data: d});
} }
Menu::BluetoothTopLimit { data } => { None => {println!("Incorrect value; enter 0 or 1")}
cli.writer()
.write_str("TODO: simulate bluetooth characteristic change")?;
let _ = data;
} }
Menu::BluetoothBottomLimit { data } => {
cli.writer()
.write_str("TODO: simulate bluetooth characteristic change")?;
let _ = data;
} }
Menu::BluetoothAux { data } => {
let but = input_to_button(data);
match but {
Some(d) => {
println!("Sending PicRecvUp command");
let _ = dispatch.send_blocking(Commands::BluetoothAux{data: d});
}
None => {println!("Incorrect value; enter 0 or 1")}
}
}
Menu::FPicAux => {
let _ = dispatch.send_blocking(Commands::FPicToggleAux);
}
Menu::FPicAuto => {
let _ = dispatch.send_blocking(Commands::FPicToggleAuto);
}
Menu::FPicLearn => {
let _ = dispatch.send_blocking(Commands::FPicPressLearn);
}
Menu::FPicUp => {
let _ = dispatch.send_blocking(Commands::FPicPressUp);
}
Menu::FPicDown => {
let _ = dispatch.send_blocking(Commands::FPicPressDown);
}
Menu::FPicStop => {
let _ = dispatch.send_blocking(Commands::FPicPressStop);
}
Menu::FPicPanic => {
let _ = dispatch.send_blocking(Commands::FPicTogglePanic);
}
Menu::FPicLockout => {
let _ = dispatch.send_blocking(Commands::FPicLockout);
}
Menu::FPicFault => {
let _ = dispatch.send_blocking(Commands::FPicFault { data: Arc::new("Test Fault".to_string()) });
}
Menu::FPicOutput => {
let _ = dispatch.send_blocking(Commands::FPicOutput);
}
Menu::FPicLimitClear1 => {
let mut lim = EMPTY_LIMITS;
lim.only_starboard_bow = LimitStatus::NotActive;
let _ = dispatch.send_blocking(Commands::FPicLimit { data: lim });
}
Menu::FPicLimitTop1 => {
let mut lim = EMPTY_LIMITS;
lim.only_starboard_bow = LimitStatus::TopActive;
let _ = dispatch.send_blocking(Commands::FPicLimit { data: lim });
}
Menu::FPicLimitBottom1 => {
let mut lim = EMPTY_LIMITS;
lim.only_starboard_bow = LimitStatus::BottomActive;
let _ = dispatch.send_blocking(Commands::FPicLimit { data: lim });
}
/*Menu::BluetoothWifiSsid { ssid } => { /*Menu::BluetoothWifiSsid { ssid } => {
cli.writer() cli.writer()
.write_str("TODO: simulate bluetooth characteristic change")?; .write_str("TODO: simulate bluetooth characteristic change")?;

View File

@ -26,6 +26,7 @@ pub enum Commands {
FPicLockout, FPicLockout,
FPicFault {data: Arc<String>}, // String is cause. Send empty string to clear fault. FPicFault {data: Arc<String>}, // String is cause. Send empty string to clear fault.
FPicLimit {data: Limits}, FPicLimit {data: Limits},
FPicOutput,
// TODO: real hardware buttons - consider re-sending occasionally when pressed, so that transitions like holding up -> stopping -> holding down -> stopped -> (should go down but gets no new notice) work. // TODO: real hardware buttons - consider re-sending occasionally when pressed, so that transitions like holding up -> stopping -> holding down -> stopped -> (should go down but gets no new notice) work.

View File

@ -49,6 +49,7 @@ impl FakePic {
Commands::PairTimerExpired, Commands::PairTimerExpired,
Commands::StopTimerExpired, Commands::StopTimerExpired,
Commands::ButtonTimerExpired, Commands::ButtonTimerExpired,
Commands::FPicOutput,
]; ];
FakePic { FakePic {
motor_state: Motors{ motor_state: Motors{
@ -99,11 +100,11 @@ impl FakePic {
Ok(()) Ok(())
} }
pub async fn press_up(&mut self) -> Result<()> { pub async fn press_up(&mut self) -> Result<()> {
if self.status_state.union(Statuses::PANIC).is_empty() || self.status_state.union(Statuses::LOCKOUT).is_empty(){ if !self.status_state.intersection(Statuses::PANIC| Statuses::LOCKOUT).is_empty() {
warn!("Ignoring commands while in panic or lockout mode!") warn!("Ignoring commands while in panic or lockout mode!")
} }
if self.motor_state.are_cooldown() { else if self.motor_state.are_cooldown() {
info!("Ignoring commands while motors cool down") warn!("Ignoring commands while motors cool down")
} }
else if self.motor_state.going_down() { else if self.motor_state.going_down() {
warn!("Reversing from down to up; entering cooldown!"); warn!("Reversing from down to up; entering cooldown!");
@ -120,11 +121,11 @@ impl FakePic {
Ok(()) Ok(())
} }
pub async fn press_down(&mut self) -> Result<()> { pub async fn press_down(&mut self) -> Result<()> {
if self.status_state.union(Statuses::PANIC).is_empty() || self.status_state.union(Statuses::LOCKOUT).is_empty() { if !self.status_state.intersection(Statuses::PANIC| Statuses::LOCKOUT).is_empty() {
warn!("Ignoring commands while in panic or lockout mode!") warn!("Ignoring commands while in panic or lockout mode!")
} }
else if self.motor_state.are_cooldown() { else if self.motor_state.are_cooldown() {
info!("Ignoring commands while motors cool down") warn!("Ignoring commands while motors cool down")
} }
else if self.motor_state.going_up() { else if self.motor_state.going_up() {
warn!("Reversing from up to down; entering cooldown!"); warn!("Reversing from up to down; entering cooldown!");
@ -143,18 +144,25 @@ impl FakePic {
pub async fn press_stop(&mut self) -> Result<()> { pub async fn press_stop(&mut self) -> Result<()> {
self.motor_state.stop(); self.motor_state.stop();
self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?; self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?;
//self.send_q.send(Commands::ButtonTimerClear).await?; // Stop waiting on button timeouts
Ok(()) Ok(())
} }
pub async fn toggle_panic(&mut self) -> Result<()> { pub async fn toggle_panic(&mut self) -> Result<()> {
self.status_state ^= Statuses::PANIC; self.status_state = self.status_state.symmetric_difference(Statuses::PANIC);
if self.status_state.intersection(Statuses::PANIC).is_empty(){
warn!("Clearing Panic status")
} else {
warn!("Entering panic status")
}
self.motor_state.stop(); self.motor_state.stop();
self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?; self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?;
self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?; //self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?;
Ok(()) Ok(())
} }
pub async fn lockout(&mut self) -> Result<()> { pub async fn lockout(&mut self) -> Result<()> {
self.status_state &= Statuses::LOCKOUT; // No toggle; lockout can only be cleared by reboot per spec self.status_state &= Statuses::LOCKOUT; // No toggle; lockout can only be cleared by reboot per spec
self.motor_state.stop(); self.motor_state.stop();
warn!("Locking out all movement controls until device is reset!");
self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?; self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?;
self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?; self.send_q.send(Commands::BluetoothStatusMotor { data: self.motor_state }).await?;
Ok(()) Ok(())
@ -167,6 +175,7 @@ impl FakePic {
} }
self.fault_cause = cause; self.fault_cause = cause;
self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?; self.send_q.send(Commands::BluetoothStatusStatus { data: self.status_state }).await?;
self.send_q.send(Commands::BluetoothStatusReason { data: Arc::new(self.fault_cause.clone())}).await?;
Ok(()) Ok(())
} }
pub async fn change_limit(&mut self, limits: Limits) -> Result<()> { pub async fn change_limit(&mut self, limits: Limits) -> Result<()> {
@ -182,55 +191,91 @@ impl FakePic {
// === Handle events from event manager ===================================================== // === Handle events from event manager =====================================================
pub async fn run(&mut self) -> Result<()> { pub async fn run(&mut self) -> Result<()> {
loop {
let cmd = self.recv_q.recv().await.expect("PIC simulator failed waiting for messages"); let cmd = self.recv_q.recv().await.expect("PIC simulator failed waiting for messages");
match cmd { match cmd {
// Commands from testing and user // Commands from testing and user
Commands::FPicToggleAux => {self.toggle_aux().await} Commands::FPicToggleAux => {self.toggle_aux().await?}
Commands::FPicToggleAuto => {self.toggle_auto().await} Commands::FPicToggleAuto => {self.toggle_auto().await?}
Commands::FPicPressLearn => {self.press_learn().await} Commands::FPicPressLearn => {self.press_learn().await?}
Commands::FPicPressUp => {self.press_up().await} Commands::FPicPressUp => {self.press_up().await?}
Commands::FPicPressDown => {self.press_down().await} Commands::FPicPressDown => {self.press_down().await?}
Commands::FPicPressStop => {self.press_stop().await} Commands::FPicPressStop => {self.press_stop().await?}
Commands::FPicTogglePanic => {self.toggle_panic().await} Commands::FPicTogglePanic => {self.toggle_panic().await?}
Commands::FPicLockout => {self.lockout().await} Commands::FPicLockout => {self.lockout().await?}
Commands::FPicFault{data} => {self.fault(data.to_string()).await} Commands::FPicFault{data} => {self.fault(data.to_string()).await?}
Commands::FPicLimit { data } => {self.change_limit(data).await} Commands::FPicLimit { data } => {self.change_limit(data).await?}
// Commands from bluetooth // Commands from bluetooth
Commands::BluetoothAuto { data } => { Commands::BluetoothAuto { data } => {
if data.is_pressed() { if data.is_pressed() {
self.toggle_auto().await?; self.toggle_auto().await?;
} Ok(()) }
} }
Commands::BluetoothAux { data } => { Commands::BluetoothAux { data } => {
if data.is_pressed() { if data.is_pressed() {
self.toggle_aux().await?; self.toggle_aux().await?;
} Ok(()) }
} }
Commands::BluetoothLearn { data } => { Commands::BluetoothLearn { data } => {
if data.is_pressed() { if data.is_pressed() {
self.press_learn().await?; self.press_learn().await?;
} Ok(()) }
} }
Commands::BluetoothUp { data } => { Commands::BluetoothUp { data } => {
if data.is_pressed() { if data.is_pressed() {
self.press_up().await?; self.press_up().await?;
} else { } else {
self.press_stop().await?; // Releasing up is equivalent to stop self.press_stop().await?; // Releasing up is equivalent to stop
} Ok(()) }
} }
Commands::BluetoothDown { data } => { Commands::BluetoothDown { data } => {
if data.is_pressed() { if data.is_pressed() {
self.press_down().await?; self.press_down().await?;
} else { } else {
self.press_stop().await?; // Releasing down is equivalent to stop self.press_stop().await?; // Releasing down is equivalent to stop
} Ok(())
} }
Commands::BluetoothStop { .. } => {self.press_stop().await} // Stopping on release of stop button is a noop but safe. }
Commands::BluetoothStop { .. } => {self.press_stop().await?} // Stopping on release of stop button is a noop but safe.
// Commands from timers // Commands from timers
Commands::PairTimerExpired => {self.exit_learn().await} Commands::PairTimerExpired => {self.exit_learn().await?}
Commands::StopTimerExpired => {self.exit_cooldown().await} Commands::StopTimerExpired => {self.exit_cooldown().await?}
Commands::ButtonTimerExpired => {self.press_stop().await} Commands::ButtonTimerExpired => {self.press_stop().await?}
_ => {warn!("Unknown command received by Fake PIC simulator!"); Ok(())} Commands::FPicOutput => {
warn!("== Fake PIC internal state ==---------------");
if self.status_state.intersection(Statuses::LOCKOUT).is_empty() {
info!("Lockout flag: Off");
} else {
error!("Lockout flag: On");
}
if self.status_state.intersection(Statuses::PANIC).is_empty() {
info!("Panic flag: Off");
} else {
warn!("Panic flag: On");
}
if self.status_state.intersection(Statuses::FAULT).is_empty() {
info!("Fault flag: Off");
} else {
warn!("Fault flag: On");
}
if self.status_state.intersection(Statuses::LEARN).is_empty() {
info!("Learn flag: Off");
} else {
info!("Learn flag: On");
}
if self.status_state.intersection(Statuses::AUTO).is_empty() {
info!("Auto flag: Off");
} else {
info!("Auto flag: On");
}
if self.status_state.intersection(Statuses::AUX).is_empty() {
info!("Aux flag: Off");
} else {
warn!("Aux flag: On");
}
warn!("==------------------------------------------");
}
_ => {warn!("Unknown command received by Fake PIC simulator!");}
}
} }
} }