pub use crate::wire::{DfuDevice, DfuOutput};
#[derive(Debug, Clone, Default)]
pub struct DfuOptions {
pub vid_pid: Option<String>,
pub serial: Option<String>,
pub alt: Option<u32>,
pub dfuse_address: Option<String>,
pub reset: bool,
}
pub(crate) mod ops {
use std::time::Duration;
use serde_json::{json, Value};
use super::DfuOptions;
use crate::error::Result;
use crate::nets::debug::base64_encode;
use crate::wire::{
box_command, dfu_unsupported, map_route_missing, value_as, value_list_field, DfuDevice,
DfuOutput, Op, Timeout,
};
const PATH: &str = "/usb/dfu";
const LIST_TIMEOUT: Timeout = Timeout::After(Duration::from_secs(30));
const RUN_TIMEOUT: Timeout = Timeout::After(Duration::from_secs(180));
fn params(opts: &DfuOptions) -> Value {
let mut params = json!({});
if let Some(vid_pid) = &opts.vid_pid {
params["vid_pid"] = json!(vid_pid);
}
if let Some(serial) = &opts.serial {
params["serial"] = json!(serial);
}
if let Some(alt) = opts.alt {
params["alt"] = json!(alt);
}
if let Some(addr) = &opts.dfuse_address {
params["dfuse_address"] = json!(addr);
}
if opts.reset {
params["reset"] = json!(true);
}
params
}
pub(crate) fn list() -> Op<Vec<DfuDevice>> {
Op {
req: box_command(PATH, "list", json!({}), LIST_TIMEOUT),
parse: |resp| value_list_field(resp, "devices"),
}
}
pub(crate) fn download(firmware: &[u8], opts: &DfuOptions) -> Op<DfuOutput> {
let mut p = params(opts);
p["firmware"] = json!(base64_encode(firmware));
Op {
req: box_command(PATH, "download", p, RUN_TIMEOUT),
parse: value_as::<DfuOutput>,
}
}
pub(crate) fn detach(opts: &DfuOptions) -> Op<DfuOutput> {
Op {
req: box_command(PATH, "detach", params(opts), RUN_TIMEOUT),
parse: value_as::<DfuOutput>,
}
}
pub(crate) fn compat<T>(result: Result<T>) -> Result<T> {
result.map_err(|e| map_route_missing(e, dfu_unsupported))
}
}
#[cfg(feature = "blocking")]
#[derive(Clone)]
pub struct Dfu<'a> {
pub(crate) client: &'a crate::client::LagerBox,
}
#[cfg(feature = "blocking")]
impl Dfu<'_> {
pub fn list(&self) -> crate::Result<Vec<DfuDevice>> {
ops::compat(self.client.run(ops::list()))
}
pub fn download(&self, firmware: &[u8], opts: &DfuOptions) -> crate::Result<DfuOutput> {
ops::compat(self.client.run(ops::download(firmware, opts)))
}
pub fn detach(&self, opts: &DfuOptions) -> crate::Result<DfuOutput> {
ops::compat(self.client.run(ops::detach(opts)))
}
}
#[cfg(feature = "async")]
#[derive(Clone)]
pub struct AsyncDfu<'a> {
pub(crate) client: &'a crate::async_client::AsyncLagerBox,
}
#[cfg(feature = "async")]
impl AsyncDfu<'_> {
pub async fn list(&self) -> crate::Result<Vec<DfuDevice>> {
ops::compat(self.client.run(ops::list()).await)
}
pub async fn download(&self, firmware: &[u8], opts: &DfuOptions) -> crate::Result<DfuOutput> {
ops::compat(self.client.run(ops::download(firmware, opts)).await)
}
pub async fn detach(&self, opts: &DfuOptions) -> crate::Result<DfuOutput> {
ops::compat(self.client.run(ops::detach(opts)).await)
}
}