Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ tokio = { version = "1.41", default-features = false, features = ["time", "rt",
log = { version = "0.4.22", default-features = false }

# used by piggui in GUI only
iced_aw = { git = "https://github.com/andrewdavidmackenzie/iced_aw.git", branch = "fix_menu_crash", version = "0.11", default-features = false, features = ["menu"] }
iced_aw = { git = "https://github.com/iced-rs/iced_aw.git", version = "0.11", default-features = false, features = ["menu"] }
iced_futures = { version = "0.13", default-features = false }
plotters-iced = { version = "0.11", default-features = false }
plotters = { version = "0.3", default-features = false, features = [
Expand Down
5 changes: 2 additions & 3 deletions src/piggui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,10 @@
KnownDevice::Porky(method, hardware_description, wifi_details),
);
}
DeviceEvent::DeviceLost(hardware_description) => {
DeviceEvent::DeviceLost(serial_number) => {

Check warning on line 434 in src/piggui.rs

View check run for this annotation

Codecov / codecov/patch

src/piggui.rs#L434

Added line #L434 was not covered by tests
self.info_row
.add_info_message(Info("USB Device Lost".to_string()));
self.known_devices
.remove(&hardware_description.details.serial);
self.known_devices.remove(&serial_number);

Check warning on line 437 in src/piggui.rs

View check run for this annotation

Codecov / codecov/patch

src/piggui.rs#L437

Added line #L437 was not covered by tests
}
DeviceEvent::Error(e) => {
self.info_row
Expand Down
156 changes: 76 additions & 80 deletions src/usb_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::hw_definition::usb_values::{
GET_HARDWARE_VALUE, GET_WIFI_VALUE, PIGGUI_REQUEST, RESET_SSID_VALUE, SET_SSID_VALUE,
};
use crate::usb_raw::USBState::{Connected, Disconnected};
use crate::views::hardware_menu::DeviceEvent;
use crate::views::hardware_menu::DiscoveryMethod::USBRaw;
use async_std::prelude::Stream;
Expand All @@ -11,7 +10,7 @@
use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
use nusb::Interface;
use serde::Deserialize;
use std::io;
use std::collections::HashMap;
use std::time::Duration;

/// [ControlIn] "command" to request the HardwareDescription
Expand Down Expand Up @@ -44,30 +43,28 @@
data: &[],
};

pub enum USBState {
/// Just starting up, we have not yet set up a channel between GUI and Listener
Disconnected,
/// The subscription is ready and will listen for config events on the channel contained
Connected(HardwareDescription),
}
/// Try and find an attached "porky" USB devices based on the vendor id and product id
/// Return a hashmap of interfaces for each one, with the serial_number as the key, enabling
/// us later to communicate with a specific device using its serial number
async fn find_porkys() -> HashMap<String, Interface> {
match nusb::list_devices() {
Ok(device_list) => {
let mut map = HashMap::<String, Interface>::new();
let interfaces = device_list
.filter(|d| d.vendor_id() == 0xbabe && d.product_id() == 0xface)
.filter_map(|device_info| device_info.open().ok())
.filter_map(|device| device.claim_interface(0).ok());

Check warning on line 56 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L49-L56

Added lines #L49 - L56 were not covered by tests

for interface in interfaces {
if let Ok(hardware_description) = get_hardware_description(&interface).await {
map.insert(hardware_description.details.serial, interface);
}

Check warning on line 61 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L58-L61

Added lines #L58 - L61 were not covered by tests
}

/// Try and find an attached "porky" USB device based on the vendor id and product id
// TODO take a specific (optional) serial number?
// TODO if no serial number, return a vec of matching ones
fn find_porky() -> Option<Interface> {
let mut device_list = nusb::list_devices().ok()?;
let porky_info = device_list
.find(|d| d.vendor_id() == 0xbabe && d.product_id() == 0xface)
.ok_or("No Porky Found")
.map_err(|_| {
io::Error::new(
io::ErrorKind::NotFound,
"Could not find at attached porky device",
)
})
.ok()?;
let device = porky_info.open().ok()?;
device.claim_interface(0).ok()
map

Check warning on line 64 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L64

Added line #L64 was not covered by tests
}
Err(_) => HashMap::default(),

Check warning on line 66 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L66

Added line #L66 was not covered by tests
}
}

/// Generic request to send data to porky over USB
Expand Down Expand Up @@ -105,13 +102,10 @@

/// Send a new Wi-Fi SsidSpec to the connected porky device
pub async fn send_ssid_spec(serial_number: String, ssid_spec: SsidSpec) -> Result<(), String> {
let porky = find_porky().ok_or("Could not find USB attached porky")?;

let hardware_description = get_hardware_description(&porky).await?;

if hardware_description.details.serial != serial_number {
return Err("USB attached porky does not have matching serial number".into());
}
let porkys = find_porkys().await;
let porky = porkys
.get(&serial_number)
.ok_or("Cannot find USB attached porky with matching serial number".to_string())?;

Check warning on line 108 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L105-L108

Added lines #L105 - L108 were not covered by tests

let mut buf = [0; 1024];
let data = postcard::to_slice(&ssid_spec, &mut buf).unwrap();
Expand All @@ -125,69 +119,71 @@
data,
};

usb_send_porky(&porky, set_wifi_details).await
usb_send_porky(porky, set_wifi_details).await

Check warning on line 122 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L122

Added line #L122 was not covered by tests
}

/// Reset the SsidSpec in a connected porky device
pub async fn reset_ssid_spec(serial_number: String) -> Result<(), String> {
let porky = find_porky().ok_or("Could not find USB attached porky")?;
// TODO have find take an optional serial number to look for
let hardware_description = get_hardware_description(&porky).await?;
if hardware_description.details.serial != serial_number {
return Err("USB attached porky does not have matching serial number".into());
}

usb_send_porky(&porky, RESET_SSID).await
let porkys = find_porkys().await;
let porky = porkys
.get(&serial_number)
.ok_or("Cannot find USB attached porky with matching serial number".to_string())?;
usb_send_porky(porky, RESET_SSID).await

Check warning on line 131 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L127-L131

Added lines #L127 - L131 were not covered by tests
}

/// A stream of [DeviceEvent] to a possibly connected porky
/// A stream of [DeviceEvent] announcing the discovery or loss of devices
pub fn subscribe() -> impl Stream<Item = DeviceEvent> {
let mut usb_state = Disconnected;

stream::channel(100, move |gui_sender| async move {
let mut previous_serials: Vec<String> = vec![];

Check warning on line 137 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L137

Added line #L137 was not covered by tests

loop {
let mut gui_sender_clone = gui_sender.clone();
tokio::time::sleep(Duration::from_secs(1)).await;

let porky_found = find_porky();

usb_state = match (porky_found, &usb_state) {
(Some(porky), Disconnected) => match get_hardware_description(&porky).await {
Ok(hardware_description) => {
let wifi_details = if hardware_description.details.wifi {
match get_wifi_details(&porky).await {
Ok(details) => Some(details),
Err(_) => {
// TODO report error to UI
None
let current_porkys = find_porkys().await;

Check warning on line 141 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L141

Added line #L141 was not covered by tests

// New devices
for (serial, porky) in &current_porkys {
if !previous_serials.contains(serial) {
match get_hardware_description(porky).await {
Ok(hardware_description) => {
let wifi_details = if hardware_description.details.wifi {
match get_wifi_details(porky).await {
Ok(details) => Some(details),

Check warning on line 150 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L144-L150

Added lines #L144 - L150 were not covered by tests
Err(_) => {
// TODO report error to UI
None

Check warning on line 153 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L153

Added line #L153 was not covered by tests
}
}
}
} else {
None
};
let _ = gui_sender_clone
.send(DeviceEvent::DeviceFound(
USBRaw,
hardware_description.clone(),
wifi_details,
))
.await;
Connected(hardware_description)
}
Err(e) => {
let _ = gui_sender_clone.send(DeviceEvent::Error(e)).await;
Disconnected
} else {
None

Check warning on line 157 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L157

Added line #L157 was not covered by tests
};

println!("Found new device");
let _ = gui_sender_clone
.send(DeviceEvent::DeviceFound(
USBRaw,
hardware_description.clone(),
wifi_details,
))
.await;

Check warning on line 167 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L160-L167

Added lines #L160 - L167 were not covered by tests
}
Err(e) => {
let _ = gui_sender_clone.send(DeviceEvent::Error(e)).await;

Check warning on line 170 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L169-L170

Added lines #L169 - L170 were not covered by tests
}
}
},
(Some(_), Connected(hw)) => Connected(hw.clone()),
(None, Disconnected) => Disconnected,
(None, Connected(hardware_description)) => {
}

Check warning on line 173 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L173

Added line #L173 was not covered by tests
}

// Lost devices
for serial in previous_serials {
if !current_porkys.contains_key(&serial) {

Check warning on line 178 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L177-L178

Added lines #L177 - L178 were not covered by tests
let _ = gui_sender_clone
.send(DeviceEvent::DeviceLost(hardware_description.clone()))
.send(DeviceEvent::DeviceLost(serial.clone()))

Check warning on line 180 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L180

Added line #L180 was not covered by tests
.await;
Disconnected
}
};
}

previous_serials = current_porkys.into_keys().collect();
tokio::time::sleep(Duration::from_secs(2)).await;

Check warning on line 186 in src/usb_raw.rs

View check run for this annotation

Codecov / codecov/patch

src/usb_raw.rs#L185-L186

Added lines #L185 - L186 were not covered by tests
}
})
}
Expand Down
9 changes: 2 additions & 7 deletions src/views/hardware_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
#[derive(Debug, Clone)]
pub enum DeviceEvent {
DeviceFound(DiscoveryMethod, HardwareDescription, Option<WiFiDetails>),
DeviceLost(HardwareDescription),
DeviceLost(String),
Error(String),
}

Expand Down Expand Up @@ -352,10 +352,5 @@
#[cfg(feature = "usb-raw")]
/// Create subscriptions for ticks for updating charts of waveforms and events coming from hardware
pub fn subscription() -> Subscription<DeviceEvent> {
let subscriptions = vec![
#[cfg(feature = "usb-raw")]
Subscription::run_with_id("device", usb_raw::subscribe()),
];

Subscription::batch(subscriptions)
Subscription::run(usb_raw::subscribe)

Check warning on line 355 in src/views/hardware_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/views/hardware_menu.rs#L355

Added line #L355 was not covered by tests
}