Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device: various fixes & improvements #277

Merged
merged 5 commits into from
Apr 9, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ jobs:
run: cargo fmt --all

- name: Suggest Changes
continue-on-error: true
if: success() && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target')
# https://docs.github.com/en/rest/pulls/reviews?apiVersion=2022-11-28#create-a-review-for-a-pull-request
uses: parkerbxyz/suggest-changes@v1
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion cargo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cargo-playdate"
version = "0.4.0-beta.2"
version = "0.4.0-beta.3"
readme = "README.md"
description = "Build tool for neat yellow console."
keywords = ["playdate", "build", "cargo", "plugin", "cargo-subcommand"]
Expand Down Expand Up @@ -93,3 +93,7 @@ rand = "0.8"

[target.'cfg(unix)'.dev-dependencies]
nix = { version = "0.28", features = ["signal"] }


[features]
eject = ["device/eject"] # windows only, enable one more unmount method
2 changes: 1 addition & 1 deletion cargo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fn execute(config: &Config) -> CargoResult<()> {
.map(|m| m.device.value.as_ref())
.flatten()
{
format!("on the '{}'", query.to_printable_string()).into()
format!("on the '{}'", query.to_value_string()).into()
} else {
"on a device".into()
}
Expand Down
2 changes: 1 addition & 1 deletion support/device/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-device"
version = "0.2.2"
version = "0.2.3"
readme = "README.md"
description = "Cross-platform interface Playdate device, async & blocking."
keywords = ["playdate", "usb", "serial"]
Expand Down
2 changes: 1 addition & 1 deletion support/device/src/device/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub async fn wait_mode_change(mut dev: Device, to: Mode, retry: Retries<impl Ite
);

if mode == to {
dev.info().serial_number().map(|s| trace!("{s} is in {to} mode."));
trace!("{dev} is in {to} mode.");
return Ok(dev);
}

Expand Down
53 changes: 42 additions & 11 deletions support/device/src/device/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;
use std::str::FromStr;

use super::serial::SerialNumber;
use self::error::DeviceQueryError as Error;


pub const DEVICE_SERIAL_ENV: &str = "PLAYDATE_SERIAL_DEVICE";
Expand Down Expand Up @@ -76,26 +77,20 @@ pub enum Value {
Com(u16),
}

type ParseError = <SerialNumber as FromStr>::Err;
impl FromStr for Value {
type Err = crate::error::Error;
type Err = Error;

fn from_str(dev: &str) -> Result<Self, Self::Err> {
let name = dev.trim();
if name.is_empty() {
return Err(ParseError::from(name).into());
return Err(error::ParseError::from(name).into());
}

#[cfg(windows)]
match name.strip_prefix("COM").map(|s| s.parse::<u16>()) {
Some(Ok(com)) => return Ok(Value::Com(com)),
Some(Err(err)) => {
use std::io::{Error, ErrorKind};

return Err(Error::new(
ErrorKind::InvalidInput,
format!("Invalid format, seems to COM port, but {err}."),
).into());
return Err(Error::invalid(format!("Invalid format, seems to COM port, but {err}.")));
},
None => { /* nothing there */ },
}
Expand Down Expand Up @@ -124,16 +119,52 @@ impl FromStr for Value {
}

impl<'s> TryFrom<&'s str> for Value {
type Error = crate::error::Error;
type Error = Error;
fn try_from(dev: &'s str) -> Result<Self, Self::Error> { Self::from_str(dev) }
}

impl Value {
pub fn to_printable_string(&self) -> String {
pub fn to_value_string(&self) -> String {
match self {
Self::Serial(sn) => sn.to_string(),
Self::Path(p) => p.display().to_string(),
Self::Com(n) => format!("COM{n}"),
}
}
}


pub mod error {
use std::backtrace::Backtrace;
use std::str::FromStr;
use thiserror::Error;
use miette::Diagnostic;

pub type ParseError = <super::SerialNumber as FromStr>::Err;


#[derive(Error, Debug, Diagnostic)]
pub enum DeviceQueryError {
#[error(transparent)]
#[diagnostic(transparent)]
DeviceSerial {
#[backtrace]
#[from]
source: ParseError,
},

#[error("Invalid query format: {message}")]
Invalid {
message: String,
#[backtrace]
backtrace: Backtrace,
},
}

impl DeviceQueryError {
pub fn invalid(message: String) -> Self {
Self::Invalid { message,
backtrace: Backtrace::capture() }
}
}
}
47 changes: 25 additions & 22 deletions support/device/src/device/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ impl SerialNumber {
}

impl FromStr for SerialNumber {
type Err = DeviceSerialFormatError;
type Err = error::SerialNumberFormatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::contained_in(s).ok_or_else(|| DeviceSerialFormatError::from(s))
Self::contained_in(s).ok_or_else(|| error::SerialNumberFormatError::from(s))
}
}

Expand Down Expand Up @@ -82,30 +82,33 @@ impl std::fmt::Display for SerialNumber {
}


use std::backtrace::Backtrace;
use thiserror::Error;
use miette::Diagnostic;
pub mod error {

use std::backtrace::Backtrace;
use thiserror::Error;
use miette::Diagnostic;

#[derive(Error, Debug, Diagnostic)]
#[error("Invalid serial number: {value}, expected format: PDUN-XNNNNNN.")]
pub struct DeviceSerialFormatError {
pub value: String,
#[backtrace]
backtrace: Backtrace,
}

impl DeviceSerialFormatError {
fn new(value: String) -> Self {
Self { value,
backtrace: Backtrace::capture() }
#[derive(Error, Debug, Diagnostic)]
#[error("invalid serial number `{value}`, expected format `PDUN-XNNNNNN`.")]
pub struct SerialNumberFormatError {
pub value: String,
#[backtrace]
backtrace: Backtrace,
}
}

impl From<String> for DeviceSerialFormatError {
fn from(value: String) -> Self { Self::new(value) }
}
impl SerialNumberFormatError {
fn new(value: String) -> Self {
Self { value,
backtrace: Backtrace::capture() }
}
}

impl From<String> for SerialNumberFormatError {
fn from(value: String) -> Self { Self::new(value) }
}

impl From<&str> for DeviceSerialFormatError {
fn from(value: &str) -> Self { Self::new(value.to_owned()) }
impl From<&str> for SerialNumberFormatError {
fn from(value: &str) -> Self { Self::new(value.to_owned()) }
}
}
2 changes: 1 addition & 1 deletion support/device/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub enum Error {
DeviceSerial {
#[backtrace]
#[from]
source: crate::device::serial::DeviceSerialFormatError,
source: crate::device::serial::error::SerialNumberFormatError,
},

#[error(transparent)]
Expand Down
33 changes: 1 addition & 32 deletions support/device/src/interface/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use crate::error::Error;


pub trait Out: In {
// type Error: std::error::Error;

fn send(&self, data: &[u8]) -> impl Future<Output = Result<usize, Error>>;

fn send_cmd(&self, cmd: Command) -> impl Future<Output = Result<usize, Error>> {
Expand All @@ -27,36 +25,7 @@ pub trait Out: In {
}
}

pub trait In {
// type Error: std::error::Error = crate::error::Error;
}
pub trait In {}

pub trait Interface: Out {}
impl<T: In + Out> Interface for T {}


// pub trait AsyncSend {
// fn send_cmd(&mut self,
// cmd: crate::device::command::Command)
// -> impl std::future::Future<Output = Result<usize, Error>>;
// }


// mod ext {
// use super::*;


// impl<T> AsyncSend for T
// where T: tokio::io::AsyncWriteExt,
// Self: Unpin
// {
// #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
// async fn send_cmd(&mut self, cmd: crate::device::command::Command) -> Result<usize, Error> {
// let cmd = cmd.with_break();
// let bytes = cmd.as_bytes();
// self.write_all(bytes).await?;
// self.flush().await?;
// Ok(bytes.len())
// }
// }
// }
7 changes: 1 addition & 6 deletions support/device/src/interface/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@ use crate::device::command::Command;
use crate::error::Error;

pub trait Out: In {
// type Error: std::error::Error = crate::error::Error;

// fn send(&self, data: &[u8]) -> Result<usize, Self::Error>;
fn send_cmd(&self, cmd: Command) -> Result<usize, Error>;
}

pub trait In {
// type Error: std::error::Error = crate::error::Error;
}
pub trait In {}

pub trait Interface: In + Out {}
// impl<T: In<Error = Err> + Out<Error = Err>, Err> Interface for T {}
Expand Down
5 changes: 1 addition & 4 deletions support/device/src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ impl r#async::In for Interface
where crate::usb::Interface: r#async::In,
crate::serial::Interface: r#async::In
{
// type Error = Error;
}


Expand All @@ -79,6 +78,4 @@ impl blocking::Out for Interface {
}
}

impl blocking::In for Interface {
// type Error = crate::error::Error;
}
impl blocking::In for Interface {}
12 changes: 10 additions & 2 deletions support/device/src/mount/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ async fn wait_mount_point<T>(dev: Device, retry: Retries<T>) -> Result<MountedDe


#[cfg_attr(feature = "tracing", tracing::instrument())]
pub async fn unmount(query: Query) -> Result<Unordered<impl Future<Output = (Device, Result)>>> {
pub async fn unmount(query: Query) -> Result<impl Stream<Item = (Device, Result)>> {
match query.value {
Some(QueryValue::Path(path)) => {
// TODO: Check query is path and this is mounted volume.
Expand All @@ -324,7 +324,15 @@ pub async fn unmount(query: Query) -> Result<Unordered<impl Future<Output = (Dev
Some(QueryValue::Com(_)) => todo!("ERROR: not supported (impossible)"),
Some(QueryValue::Serial(sn)) => unmount_mb_sn(Some(sn)),
_ => unmount_mb_sn(None),
}.await
}.map_ok(|stream| {
stream.inspect(|(dev, res)| {
if let Some(err) = res.as_ref().err() {
error!("{dev}: {err}");
warn!("Please press 'A' on the Playdate to exit Data Disk mode.");
}
})
})
.await
}

/// Unmount device(s), then wait for state change to [`Data`][usb::mode::Mode::Data].
Expand Down
3 changes: 0 additions & 3 deletions support/device/src/mount/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ mod methods;
pub use methods::*;


// TODO: If unmount fails, do warn!("Please press 'A' on the Playdate to exit Data Disk mode.")


// TODO: MountError for this module


Expand Down
2 changes: 1 addition & 1 deletion support/device/src/mount/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ pub async fn volume_for(dev: &Device) -> Result<Volume, Error> {
}

let sn = dev.info().serial_number().ok_or_else(|| {
Error::DeviceSerial { source: crate::device::serial::DeviceSerialFormatError::from("missed") }
Error::DeviceSerial { source: crate::device::serial::error::SerialNumberFormatError::from("missed sn") }
})?;
let sn = SerialNumber::try_from(sn)?;
let dev_addr = dev.info().device_address() as u32;
Expand Down
25 changes: 25 additions & 0 deletions support/device/src/retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,28 @@ impl IterTime for Duration {
calc_interval(total_wait, self)
}
}


pub fn retry_blocking<F, R, E>(retry: Retries<impl IterTime>, f: F) -> Result<R, crate::error::Error>
where F: Fn() -> Result<R, E>,
E: Into<crate::error::Error> {
let total = &retry.total;
let iteration = retry.iters.interval(total);
let retries_num = total.as_millis() / iteration.as_millis();
trace!("start retries: {retries_num} * {iteration:?} ≈ {total:?}.");

let mut counter = retries_num;
loop {
trace!("try: {}/{retries_num}", retries_num - counter);
match f() {
Ok(r) => return Ok(r),
Err(e) => {
counter -= 1;
if counter == 0 {
return Err(e.into());
}
std::thread::sleep(iteration);
},
}
}
}