mirror of
https://github.com/spacemeowx2/blflash.git
synced 2024-10-02 21:02:11 +00:00
feat: make functions async
This commit is contained in:
parent
b0967e75f7
commit
e587a44f08
223
Cargo.lock
generated
223
Cargo.lock
generated
@ -91,8 +91,10 @@ dependencies = [
|
||||
"deku",
|
||||
"directories-next",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"hex",
|
||||
"indicatif",
|
||||
"js-sys",
|
||||
"log",
|
||||
"main_error",
|
||||
"parse_int",
|
||||
@ -103,6 +105,8 @@ dependencies = [
|
||||
"structopt",
|
||||
"thiserror",
|
||||
"toml 0.5.7",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"xmas-elf",
|
||||
]
|
||||
|
||||
@ -121,6 +125,12 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
@ -135,6 +145,7 @@ dependencies = [
|
||||
"cargo-project",
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"main_error",
|
||||
"paw",
|
||||
"serial",
|
||||
@ -397,6 +408,101 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generator"
|
||||
version = "0.6.23"
|
||||
@ -512,6 +618,15 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@ -643,12 +758,38 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a83804639aad6ba65345661744708855f9fbcb71176ea8d28d05aeb11d975e7"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7bcc46b8f73443d15bc1c5fecbb315718491fa9187fa483f0e359323cde8b3a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
@ -673,6 +814,18 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
@ -878,6 +1031,12 @@ dependencies = [
|
||||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
@ -1123,6 +1282,70 @@ version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -33,3 +33,15 @@ paw = "1.0.0"
|
||||
crc = "1.8.1"
|
||||
hex = "0.4.2"
|
||||
parse_int = "0.4.0"
|
||||
futures = "0.3"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
js-sys = "0.3"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"Window",
|
||||
"Navigator"
|
||||
]
|
8
blflash/src/async_serial.rs
Normal file
8
blflash/src/async_serial.rs
Normal file
@ -0,0 +1,8 @@
|
||||
mod native;
|
||||
mod wasm;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub use wasm::AsyncSerial;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use native::AsyncSerial;
|
73
blflash/src/async_serial/native.rs
Normal file
73
blflash/src/async_serial/native.rs
Normal file
@ -0,0 +1,73 @@
|
||||
#![cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use serial::{Result, SerialPort, SerialPortSettings};
|
||||
use std::{
|
||||
io,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
// Async wrapper for SerialPort
|
||||
// Note: it's not really async. For native usage, async is not necessary.
|
||||
pub struct AsyncSerial(Box<dyn SerialPort>);
|
||||
|
||||
impl AsyncSerial {
|
||||
pub async fn open(port: &str) -> crate::Result<Self> {
|
||||
Ok(AsyncSerial(Box::new(serial::open(port))))
|
||||
}
|
||||
// pub fn new(serial: impl SerialPort + 'static) -> Self {
|
||||
// Self(Box::new(serial))
|
||||
// }
|
||||
pub async fn set_rts(&mut self, level: bool) -> Result<()> {
|
||||
self.0.set_rts(level)
|
||||
}
|
||||
pub async fn set_dtr(&mut self, level: bool) -> Result<()> {
|
||||
self.0.set_dtr(level)
|
||||
}
|
||||
pub async fn sleep(&self, duration: Duration) {
|
||||
sleep(duration)
|
||||
}
|
||||
pub async fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
|
||||
self.0.set_timeout(timeout)
|
||||
}
|
||||
pub async fn timeout(&self) -> Duration {
|
||||
self.0.timeout()
|
||||
}
|
||||
pub async fn reconfigure(
|
||||
&mut self,
|
||||
setup: &dyn Fn(&mut dyn SerialPortSettings) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.0.reconfigure(setup)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncSerial {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
Poll::Ready(self.0.read(buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncSerial {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
Poll::Ready(self.0.write(buf))
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(self.0.flush())
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
79
blflash/src/async_serial/wasm.rs
Normal file
79
blflash/src/async_serial/wasm.rs
Normal file
@ -0,0 +1,79 @@
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
use crate::Error;
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use js_sys::Reflect;
|
||||
use serial::{Result, SerialPortSettings};
|
||||
use std::{
|
||||
io,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::window;
|
||||
|
||||
pub struct AsyncSerial(JsValue);
|
||||
|
||||
impl AsyncSerial {
|
||||
pub async fn open(port: &str) -> crate::Result<Self> {
|
||||
let window = window().ok_or(Error::WebError("Failed to get window"))?;
|
||||
let serial = Reflect::get(window.navigator().as_ref(), &"serial".into())
|
||||
.map_err(|_| Error::WebError("Failed to get serial from navigator"))?;
|
||||
if serial.is_undefined() {
|
||||
return Err(Error::WebError("serial is not supported on your browser"));
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
pub async fn set_rts(&mut self, level: bool) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn set_dtr(&mut self, level: bool) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn sleep(&self, duration: Duration) {
|
||||
sleep(duration)
|
||||
}
|
||||
pub async fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn timeout(&self) -> Duration {
|
||||
todo!()
|
||||
}
|
||||
pub async fn reconfigure(
|
||||
&mut self,
|
||||
setup: &dyn Fn(&mut dyn SerialPortSettings) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncSerial {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncSerial {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
#![macro_use]
|
||||
|
||||
use crate::{Error, RomError};
|
||||
use crate::{
|
||||
async_serial::AsyncSerial,
|
||||
{Error, RomError},
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use deku::prelude::*;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::thread::sleep;
|
||||
use futures::{AsyncReadExt, AsyncWriteExt};
|
||||
use std::io::{Cursor, Write};
|
||||
use std::time::Duration;
|
||||
|
||||
use serial::{BaudRate, SerialPort, SerialPortSettings};
|
||||
use serial::{BaudRate, SerialPortSettings};
|
||||
|
||||
pub const DEFAULT_BAUDRATE: BaudRate = BaudRate::Baud115200;
|
||||
|
||||
@ -57,90 +60,83 @@ pub trait Command: DekuContainerWrite {
|
||||
}
|
||||
|
||||
pub struct Connection {
|
||||
serial: Box<dyn SerialPort>,
|
||||
serial: AsyncSerial,
|
||||
baud_rate: Option<BaudRate>,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn new(serial: impl SerialPort + 'static) -> Self {
|
||||
pub fn new(serial: AsyncSerial) -> Self {
|
||||
Connection {
|
||||
serial: Box::new(serial),
|
||||
serial,
|
||||
baud_rate: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Box<dyn SerialPort> {
|
||||
pub fn into_inner(self) -> AsyncSerial {
|
||||
self.serial
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<(), Error> {
|
||||
self.serial.set_rts(false)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
self.serial.set_dtr(true)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
self.serial.set_dtr(false)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
pub async fn reset(&mut self) -> Result<(), Error> {
|
||||
self.serial.set_rts(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_dtr(true).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_dtr(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset_to_flash(&mut self) -> Result<(), Error> {
|
||||
self.serial.set_rts(true)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
self.serial.set_dtr(true)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
self.serial.set_dtr(false)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
self.serial.set_rts(false)?;
|
||||
sleep(Duration::from_millis(50));
|
||||
pub async fn reset_to_flash(&mut self) -> Result<(), Error> {
|
||||
self.serial.set_rts(true).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_dtr(true).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_dtr(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_rts(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
|
||||
self.serial.set_timeout(timeout)?;
|
||||
pub async fn timeout(&self) -> Duration {
|
||||
self.serial.timeout().await
|
||||
}
|
||||
|
||||
pub async fn set_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
|
||||
self.serial.set_timeout(timeout).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_baud(&mut self, speed: BaudRate) -> Result<(), Error> {
|
||||
pub async fn set_baud(&mut self, speed: BaudRate) -> Result<(), Error> {
|
||||
self.baud_rate = Some(speed);
|
||||
self.serial
|
||||
.reconfigure(&|setup: &mut dyn SerialPortSettings| setup.set_baud_rate(speed))?;
|
||||
.reconfigure(&|setup: &mut dyn SerialPortSettings| setup.set_baud_rate(speed))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn with_timeout<T, F: FnMut(&mut Connection) -> Result<T, Error>>(
|
||||
&mut self,
|
||||
timeout: Duration,
|
||||
mut f: F,
|
||||
) -> Result<T, Error> {
|
||||
let old_timeout = self.serial.timeout();
|
||||
self.serial.set_timeout(timeout)?;
|
||||
let result = f(self);
|
||||
self.serial.set_timeout(old_timeout)?;
|
||||
result
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, len: usize) -> Result<Vec<u8>, Error> {
|
||||
async fn read_exact(&mut self, len: usize) -> Result<Vec<u8>, Error> {
|
||||
let mut buf = vec![0u8; len];
|
||||
self.serial.read_exact(&mut buf)?;
|
||||
self.serial.read_exact(&mut buf).await?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
pub fn read_response(&mut self, len: usize) -> Result<Vec<u8>, Error> {
|
||||
let resp = self.read_exact(2)?;
|
||||
pub async fn read_response(&mut self, len: usize) -> Result<Vec<u8>, Error> {
|
||||
let resp = self.read_exact(2).await?;
|
||||
match &resp[0..2] {
|
||||
// OK
|
||||
[0x4f, 0x4b] => {
|
||||
if len > 0 {
|
||||
self.read_exact(len)
|
||||
self.read_exact(len).await
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
// FL
|
||||
[0x46, 0x4c] => {
|
||||
let code = self.read_exact(2)?;
|
||||
let code = self.read_exact(2).await?;
|
||||
let mut reader = Cursor::new(code);
|
||||
let code = reader.read_u16::<LittleEndian>()?;
|
||||
Err(Error::RomError(RomError::from(code)))
|
||||
@ -157,28 +153,28 @@ impl Connection {
|
||||
* (duration.as_millis() as usize)
|
||||
}
|
||||
|
||||
pub fn write_all(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||
Ok(self.serial.write_all(buf)?)
|
||||
pub async fn write_all(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||
Ok(self.serial.write_all(buf).await?)
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Result<(), Error> {
|
||||
Ok(self.serial.flush()?)
|
||||
pub async fn flush(&mut self) -> Result<(), Error> {
|
||||
Ok(self.serial.flush().await?)
|
||||
}
|
||||
|
||||
pub fn command<C: Command>(&mut self, command: C) -> Result<C::Response, Error> {
|
||||
pub async fn command<C: Command>(&mut self, command: C) -> Result<C::Response, Error> {
|
||||
let req = self.to_cmd(command)?;
|
||||
self.write_all(&req)?;
|
||||
self.flush()?;
|
||||
self.write_all(&req).await?;
|
||||
self.flush().await?;
|
||||
|
||||
Ok(if let Some(resp) = C::Response::no_response_payload() {
|
||||
self.read_response(0)?;
|
||||
self.read_response(0).await?;
|
||||
resp
|
||||
} else {
|
||||
let len = LittleEndian::read_u16(&self.read_response(2)?);
|
||||
let len = LittleEndian::read_u16(&self.read_response(2).await?);
|
||||
let buf = Vec::new();
|
||||
let mut writer = Cursor::new(buf);
|
||||
writer.write_u16::<LittleEndian>(len)?;
|
||||
writer.write_all(&self.read_exact(len as usize)?)?;
|
||||
writer.write_all(&self.read_exact(len as usize).await?)?;
|
||||
C::Response::from_payload(&writer.into_inner())?
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
@ -29,6 +30,8 @@ pub enum Error {
|
||||
ParseError(#[from] deku::error::DekuError),
|
||||
#[error("Parse toml error")]
|
||||
TomlError(#[from] toml::de::Error),
|
||||
#[error("WebError {0}")]
|
||||
WebError(&'static str),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::chip::Chip;
|
||||
use crate::Error;
|
||||
use crate::{async_serial::AsyncSerial, chip::Chip};
|
||||
use crate::{connection::Connection, elf::RomSegment};
|
||||
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
|
||||
use serial::{BaudRate, SerialPort};
|
||||
use serial::BaudRate;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
io::{Cursor, Read, Write},
|
||||
@ -28,9 +28,9 @@ pub struct Flasher {
|
||||
}
|
||||
|
||||
impl Flasher {
|
||||
pub fn connect(
|
||||
pub async fn connect(
|
||||
chip: impl Chip + 'static,
|
||||
serial: impl SerialPort + 'static,
|
||||
serial: AsyncSerial,
|
||||
initial_speed: BaudRate,
|
||||
flash_speed: BaudRate,
|
||||
) -> Result<Self, Error> {
|
||||
@ -40,10 +40,13 @@ impl Flasher {
|
||||
chip: Box::new(chip),
|
||||
flash_speed,
|
||||
};
|
||||
flasher.connection.set_baud(initial_speed)?;
|
||||
flasher.start_connection()?;
|
||||
flasher.connection.set_timeout(Duration::from_secs(10))?;
|
||||
flasher.boot_info = flasher.boot_rom().get_boot_info()?;
|
||||
flasher.connection.set_baud(initial_speed).await?;
|
||||
flasher.start_connection().await?;
|
||||
flasher
|
||||
.connection
|
||||
.set_timeout(Duration::from_secs(10))
|
||||
.await?;
|
||||
flasher.boot_info = flasher.boot_rom().get_boot_info().await?;
|
||||
|
||||
Ok(flasher)
|
||||
}
|
||||
@ -56,12 +59,12 @@ impl Flasher {
|
||||
&self.boot_info
|
||||
}
|
||||
|
||||
pub fn load_segments<'a>(
|
||||
pub async fn load_segments<'a>(
|
||||
&'a mut self,
|
||||
force: bool,
|
||||
segments: impl Iterator<Item = RomSegment<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
self.load_eflash_loader()?;
|
||||
self.load_eflash_loader().await?;
|
||||
|
||||
for segment in segments {
|
||||
let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
|
||||
@ -70,7 +73,8 @@ impl Flasher {
|
||||
if !force {
|
||||
let sha256 = self
|
||||
.eflash_loader()
|
||||
.sha256_read(segment.addr, segment.size())?;
|
||||
.sha256_read(segment.addr, segment.size())
|
||||
.await?;
|
||||
if sha256 == &local_hash[..] {
|
||||
log::info!(
|
||||
"Skip segment addr: {:x} size: {} sha256 matches",
|
||||
@ -87,7 +91,8 @@ impl Flasher {
|
||||
segment.size()
|
||||
);
|
||||
self.eflash_loader()
|
||||
.flash_erase(segment.addr, segment.addr + segment.size())?;
|
||||
.flash_erase(segment.addr, segment.addr + segment.size())
|
||||
.await?;
|
||||
|
||||
let mut reader = Cursor::new(&segment.data);
|
||||
let mut cur = segment.addr;
|
||||
@ -96,7 +101,7 @@ impl Flasher {
|
||||
log::info!("Program flash... {:x}", local_hash);
|
||||
let pb = get_bar(segment.size() as u64);
|
||||
loop {
|
||||
let size = self.eflash_loader().flash_program(cur, &mut reader)?;
|
||||
let size = self.eflash_loader().flash_program(cur, &mut reader).await?;
|
||||
// log::trace!("program {:x} {:x}", cur, size);
|
||||
cur += size;
|
||||
pb.inc(size as u64);
|
||||
@ -114,7 +119,8 @@ impl Flasher {
|
||||
|
||||
let sha256 = self
|
||||
.eflash_loader()
|
||||
.sha256_read(segment.addr, segment.size())?;
|
||||
.sha256_read(segment.addr, segment.size())
|
||||
.await?;
|
||||
if sha256 != &local_hash[..] {
|
||||
log::warn!(
|
||||
"sha256 not match: {} != {}",
|
||||
@ -126,18 +132,19 @@ impl Flasher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_segments<'a>(
|
||||
pub async fn check_segments<'a>(
|
||||
&'a mut self,
|
||||
segments: impl Iterator<Item = RomSegment<'a>>,
|
||||
) -> Result<(), Error> {
|
||||
self.load_eflash_loader()?;
|
||||
self.load_eflash_loader().await?;
|
||||
|
||||
for segment in segments {
|
||||
let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
|
||||
|
||||
let sha256 = self
|
||||
.eflash_loader()
|
||||
.sha256_read(segment.addr, segment.size())?;
|
||||
.sha256_read(segment.addr, segment.size())
|
||||
.await?;
|
||||
if sha256 != &local_hash[..] {
|
||||
log::warn!(
|
||||
"{:x} sha256 not match: {} != {}",
|
||||
@ -152,8 +159,12 @@ impl Flasher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dump_flash(&mut self, range: Range<u32>, mut writer: impl Write) -> Result<(), Error> {
|
||||
self.load_eflash_loader()?;
|
||||
pub async fn dump_flash(
|
||||
&mut self,
|
||||
range: Range<u32>,
|
||||
mut writer: impl Write,
|
||||
) -> Result<(), Error> {
|
||||
self.load_eflash_loader().await?;
|
||||
|
||||
const BLOCK_SIZE: usize = 4096;
|
||||
let mut cur = range.start;
|
||||
@ -161,7 +172,8 @@ impl Flasher {
|
||||
while cur < range.end {
|
||||
let data = self
|
||||
.eflash_loader()
|
||||
.flash_read(cur, (range.end - cur).min(BLOCK_SIZE as u32))?;
|
||||
.flash_read(cur, (range.end - cur).min(BLOCK_SIZE as u32))
|
||||
.await?;
|
||||
writer.write_all(&data)?;
|
||||
cur += data.len() as u32;
|
||||
pb.inc(data.len() as u64);
|
||||
@ -171,18 +183,18 @@ impl Flasher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_eflash_loader(&mut self) -> Result<(), Error> {
|
||||
pub async fn load_eflash_loader(&mut self) -> Result<(), Error> {
|
||||
let input = self.chip.get_eflash_loader().to_vec();
|
||||
let len = input.len();
|
||||
let mut reader = Cursor::new(input);
|
||||
self.boot_rom().load_boot_header(&mut reader)?;
|
||||
self.boot_rom().load_segment_header(&mut reader)?;
|
||||
self.boot_rom().load_boot_header(&mut reader).await?;
|
||||
self.boot_rom().load_segment_header(&mut reader).await?;
|
||||
|
||||
let start = Instant::now();
|
||||
log::info!("Sending eflash_loader...");
|
||||
let pb = get_bar(len as u64);
|
||||
loop {
|
||||
let size = self.boot_rom().load_segment_data(&mut reader)?;
|
||||
let size = self.boot_rom().load_segment_data(&mut reader).await?;
|
||||
pb.inc(size as u64);
|
||||
if size == 0 {
|
||||
break;
|
||||
@ -196,19 +208,19 @@ impl Flasher {
|
||||
HumanBytes((len as f64 / elapsed.as_millis() as f64 * 1000.0) as u64)
|
||||
);
|
||||
|
||||
self.boot_rom().check_image()?;
|
||||
self.boot_rom().run_image()?;
|
||||
self.boot_rom().check_image().await?;
|
||||
self.boot_rom().run_image().await?;
|
||||
sleep(Duration::from_millis(500));
|
||||
self.connection.set_baud(self.flash_speed)?;
|
||||
self.handshake()?;
|
||||
self.connection.set_baud(self.flash_speed).await?;
|
||||
self.handshake().await?;
|
||||
|
||||
log::info!("Entered eflash_loader");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<(), Error> {
|
||||
Ok(self.connection.reset()?)
|
||||
pub async fn reset(&mut self) -> Result<(), Error> {
|
||||
Ok(self.connection.reset().await?)
|
||||
}
|
||||
|
||||
fn boot_rom(&mut self) -> BootRom {
|
||||
@ -219,34 +231,39 @@ impl Flasher {
|
||||
EflashLoader(&mut self.connection)
|
||||
}
|
||||
|
||||
fn handshake(&mut self) -> Result<(), Error> {
|
||||
self.connection
|
||||
.with_timeout(Duration::from_millis(200), |connection| {
|
||||
let len = connection.calc_duration_length(Duration::from_millis(5));
|
||||
log::trace!("5ms send count {}", len);
|
||||
let data: Vec<u8> = std::iter::repeat(0x55u8).take(len).collect();
|
||||
let start = Instant::now();
|
||||
connection.write_all(&data)?;
|
||||
connection.flush()?;
|
||||
log::trace!("handshake sent elapsed {:?}", start.elapsed());
|
||||
sleep(Duration::from_millis(200));
|
||||
async fn handshake(&mut self) -> Result<(), Error> {
|
||||
let connection = &mut self.connection;
|
||||
let old_timeout = connection.timeout().await;
|
||||
connection.set_timeout(Duration::from_millis(200)).await?;
|
||||
let result = async {
|
||||
let len = connection.calc_duration_length(Duration::from_millis(5));
|
||||
log::trace!("5ms send count {}", len);
|
||||
let data: Vec<u8> = std::iter::repeat(0x55u8).take(len).collect();
|
||||
let start = Instant::now();
|
||||
connection.write_all(&data).await?;
|
||||
connection.flush().await?;
|
||||
log::trace!("handshake sent elapsed {:?}", start.elapsed());
|
||||
sleep(Duration::from_millis(200));
|
||||
|
||||
for _ in 0..5 {
|
||||
if connection.read_response(0).is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
for _ in 0..5 {
|
||||
if connection.read_response(0).await.is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Timeout)
|
||||
})
|
||||
Err(Error::Timeout)
|
||||
}
|
||||
.await;
|
||||
self.connection.set_timeout(old_timeout).await?;
|
||||
result
|
||||
}
|
||||
|
||||
fn start_connection(&mut self) -> Result<(), Error> {
|
||||
async fn start_connection(&mut self) -> Result<(), Error> {
|
||||
log::info!("Start connection...");
|
||||
self.connection.reset_to_flash()?;
|
||||
self.connection.reset_to_flash().await?;
|
||||
for i in 1..=10 {
|
||||
self.connection.flush()?;
|
||||
if self.handshake().is_ok() {
|
||||
self.connection.flush().await?;
|
||||
if self.handshake().await.is_ok() {
|
||||
log::info!("Connection Succeed");
|
||||
return Ok(());
|
||||
} else {
|
||||
@ -260,30 +277,35 @@ impl Flasher {
|
||||
pub struct BootRom<'a>(&'a mut Connection);
|
||||
|
||||
impl<'a> BootRom<'a> {
|
||||
pub fn run_image(&mut self) -> Result<(), Error> {
|
||||
self.0.command(protocol::RunImage {})?;
|
||||
pub async fn run_image(&mut self) -> Result<(), Error> {
|
||||
self.0.command(protocol::RunImage {}).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_image(&mut self) -> Result<(), Error> {
|
||||
self.0.command(protocol::CheckImage {})?;
|
||||
pub async fn check_image(&mut self) -> Result<(), Error> {
|
||||
self.0.command(protocol::CheckImage {}).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_boot_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
pub async fn load_boot_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
let mut boot_header = vec![0u8; protocol::LOAD_BOOT_HEADER_LEN];
|
||||
reader.read_exact(&mut boot_header)?;
|
||||
self.0.command(protocol::LoadBootHeader { boot_header })?;
|
||||
self.0
|
||||
.command(protocol::LoadBootHeader { boot_header })
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_segment_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
pub async fn load_segment_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
|
||||
let mut segment_header = vec![0u8; protocol::LOAD_SEGMENT_HEADER_LEN];
|
||||
reader.read_exact(&mut segment_header)?;
|
||||
|
||||
let resp = self.0.command(protocol::LoadSegmentHeaderReq {
|
||||
segment_header: segment_header.clone(),
|
||||
})?;
|
||||
let resp = self
|
||||
.0
|
||||
.command(protocol::LoadSegmentHeaderReq {
|
||||
segment_header: segment_header.clone(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
if resp.data != segment_header {
|
||||
log::warn!(
|
||||
@ -296,7 +318,7 @@ impl<'a> BootRom<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_segment_data(&mut self, reader: &mut impl Read) -> Result<u32, Error> {
|
||||
pub async fn load_segment_data(&mut self, reader: &mut impl Read) -> Result<u32, Error> {
|
||||
let mut segment_data = vec![0u8; 4000];
|
||||
let size = reader.read(&mut segment_data)?;
|
||||
if size == 0 {
|
||||
@ -304,28 +326,38 @@ impl<'a> BootRom<'a> {
|
||||
}
|
||||
segment_data.truncate(size);
|
||||
|
||||
self.0.command(protocol::LoadSegmentData { segment_data })?;
|
||||
self.0
|
||||
.command(protocol::LoadSegmentData { segment_data })
|
||||
.await?;
|
||||
|
||||
Ok(size as u32)
|
||||
}
|
||||
|
||||
pub fn get_boot_info(&mut self) -> Result<protocol::BootInfo, Error> {
|
||||
self.0.command(protocol::BootInfoReq {})
|
||||
pub async fn get_boot_info(&mut self) -> Result<protocol::BootInfo, Error> {
|
||||
self.0.command(protocol::BootInfoReq {}).await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EflashLoader<'a>(&'a mut Connection);
|
||||
|
||||
impl<'a> EflashLoader<'a> {
|
||||
pub fn sha256_read(&mut self, addr: u32, len: u32) -> Result<[u8; 32], Error> {
|
||||
Ok(self.0.command(protocol::Sha256Read { addr, len })?.digest)
|
||||
pub async fn sha256_read(&mut self, addr: u32, len: u32) -> Result<[u8; 32], Error> {
|
||||
Ok(self
|
||||
.0
|
||||
.command(protocol::Sha256Read { addr, len })
|
||||
.await?
|
||||
.digest)
|
||||
}
|
||||
|
||||
pub fn flash_read(&mut self, addr: u32, size: u32) -> Result<Vec<u8>, Error> {
|
||||
Ok(self.0.command(protocol::FlashRead { addr, size })?.data)
|
||||
pub async fn flash_read(&mut self, addr: u32, size: u32) -> Result<Vec<u8>, Error> {
|
||||
Ok(self
|
||||
.0
|
||||
.command(protocol::FlashRead { addr, size })
|
||||
.await?
|
||||
.data)
|
||||
}
|
||||
|
||||
pub fn flash_program(&mut self, addr: u32, reader: &mut impl Read) -> Result<u32, Error> {
|
||||
pub async fn flash_program(&mut self, addr: u32, reader: &mut impl Read) -> Result<u32, Error> {
|
||||
let mut data = vec![0u8; 4000];
|
||||
let size = reader.read(&mut data)?;
|
||||
if size == 0 {
|
||||
@ -333,13 +365,15 @@ impl<'a> EflashLoader<'a> {
|
||||
}
|
||||
data.truncate(size);
|
||||
|
||||
self.0.command(protocol::FlashProgram { addr, data })?;
|
||||
self.0
|
||||
.command(protocol::FlashProgram { addr, data })
|
||||
.await?;
|
||||
|
||||
Ok(size as u32)
|
||||
}
|
||||
|
||||
pub fn flash_erase(&mut self, start: u32, end: u32) -> Result<(), Error> {
|
||||
self.0.command(protocol::FlashErase { start, end })?;
|
||||
pub async fn flash_erase(&mut self, start: u32, end: u32) -> Result<(), Error> {
|
||||
self.0.command(protocol::FlashErase { start, end }).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -4,7 +4,11 @@ pub mod elf;
|
||||
mod error;
|
||||
mod flasher;
|
||||
pub mod image;
|
||||
use async_serial::AsyncSerial;
|
||||
use serde::Deserialize;
|
||||
mod async_serial;
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
pub use error::{Error, RomError};
|
||||
pub use flasher::Flasher;
|
||||
|
||||
@ -16,7 +20,7 @@ use crate::{
|
||||
elf::{FirmwareImage, RomSegment},
|
||||
image::BootHeaderCfgFile,
|
||||
};
|
||||
use serial::{BaudRate, CharSize, FlowControl, Parity, SerialPort, SerialPortSettings, StopBits};
|
||||
use serial::{BaudRate, CharSize, FlowControl, Parity, SerialPortSettings, StopBits};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs::{read, File},
|
||||
@ -24,7 +28,7 @@ use std::{
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[derive(StructOpt, Deserialize)]
|
||||
pub struct Connection {
|
||||
/// Serial port
|
||||
#[structopt(short, long)]
|
||||
@ -37,7 +41,7 @@ pub struct Connection {
|
||||
pub initial_baud_rate: usize,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[derive(StructOpt, Deserialize)]
|
||||
pub struct Boot2Opt {
|
||||
/// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml
|
||||
#[structopt(long, parse(from_os_str))]
|
||||
@ -53,7 +57,7 @@ pub struct Boot2Opt {
|
||||
pub without_boot2: bool,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[derive(StructOpt, Deserialize)]
|
||||
pub struct FlashOpt {
|
||||
#[structopt(flatten)]
|
||||
pub conn: Connection,
|
||||
@ -67,7 +71,7 @@ pub struct FlashOpt {
|
||||
pub boot: Boot2Opt,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[derive(StructOpt, Deserialize)]
|
||||
pub struct CheckOpt {
|
||||
#[structopt(flatten)]
|
||||
pub conn: Connection,
|
||||
@ -78,7 +82,7 @@ pub struct CheckOpt {
|
||||
pub boot: Boot2Opt,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[derive(StructOpt, Deserialize)]
|
||||
pub struct DumpOpt {
|
||||
#[structopt(flatten)]
|
||||
pub conn: Connection,
|
||||
@ -104,25 +108,28 @@ pub enum Opt {
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn open_serial(&self) -> Result<impl SerialPort, Error> {
|
||||
let mut serial = serial::open(&self.port)?;
|
||||
serial.reconfigure(&|setup: &mut dyn SerialPortSettings| {
|
||||
setup.set_char_size(CharSize::Bits8);
|
||||
setup.set_stop_bits(StopBits::Stop1);
|
||||
setup.set_parity(Parity::ParityNone);
|
||||
setup.set_flow_control(FlowControl::FlowNone);
|
||||
Ok(())
|
||||
})?;
|
||||
pub async fn open_serial(&self) -> Result<AsyncSerial, Error> {
|
||||
let mut serial = AsyncSerial::open(&self.port).await?;
|
||||
serial
|
||||
.reconfigure(&|setup: &mut dyn SerialPortSettings| {
|
||||
setup.set_char_size(CharSize::Bits8);
|
||||
setup.set_stop_bits(StopBits::Stop1);
|
||||
setup.set_parity(Parity::ParityNone);
|
||||
setup.set_flow_control(FlowControl::FlowNone);
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
Ok(serial)
|
||||
}
|
||||
pub fn create_flasher(&self, chip: impl Chip + 'static) -> Result<Flasher, Error> {
|
||||
let serial = self.open_serial()?;
|
||||
pub async fn create_flasher(&self, chip: impl Chip + 'static) -> Result<Flasher, Error> {
|
||||
let serial = self.open_serial().await?;
|
||||
Flasher::connect(
|
||||
chip,
|
||||
serial,
|
||||
BaudRate::from_speed(self.initial_baud_rate),
|
||||
BaudRate::from_speed(self.baud_rate),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,47 +199,49 @@ pub fn read_image<'a>(chip: &dyn Chip, image: &'a [u8]) -> Result<Cow<'a, [u8]>,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn flash(opt: FlashOpt) -> Result<(), Error> {
|
||||
pub async fn flash(opt: FlashOpt) -> Result<(), Error> {
|
||||
let chip = Bl602;
|
||||
let image = read(&opt.image)?;
|
||||
let image = read_image(&chip, &image)?;
|
||||
|
||||
let mut flasher = opt.conn.create_flasher(chip)?;
|
||||
let mut flasher = opt.conn.create_flasher(chip).await?;
|
||||
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
|
||||
log::trace!("Boot info: {:x?}", flasher.boot_info());
|
||||
|
||||
let segments = opt.boot.get_segments(&chip, Vec::from(image))?;
|
||||
flasher.load_segments(opt.force, segments.into_iter())?;
|
||||
flasher.reset()?;
|
||||
flasher
|
||||
.load_segments(opt.force, segments.into_iter())
|
||||
.await?;
|
||||
flasher.reset().await?;
|
||||
|
||||
log::info!("Success");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(opt: CheckOpt) -> Result<(), Error> {
|
||||
pub async fn check(opt: CheckOpt) -> Result<(), Error> {
|
||||
let chip = Bl602;
|
||||
let image = read(&opt.image)?;
|
||||
let image = read_image(&chip, &image)?;
|
||||
|
||||
let mut flasher = opt.conn.create_flasher(Bl602)?;
|
||||
let mut flasher = opt.conn.create_flasher(Bl602).await?;
|
||||
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
|
||||
log::trace!("Boot info: {:x?}", flasher.boot_info());
|
||||
|
||||
let segments = opt.boot.get_segments(&chip, Vec::from(image))?;
|
||||
flasher.check_segments(segments.into_iter())?;
|
||||
flasher.check_segments(segments.into_iter()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dump(opt: DumpOpt) -> Result<(), Error> {
|
||||
pub async fn dump(opt: DumpOpt) -> Result<(), Error> {
|
||||
let mut output = File::create(opt.output)?;
|
||||
let mut flasher = opt.conn.create_flasher(Bl602)?;
|
||||
let mut flasher = opt.conn.create_flasher(Bl602).await?;
|
||||
|
||||
log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version);
|
||||
log::trace!("Boot info: {:x?}", flasher.boot_info());
|
||||
|
||||
flasher.dump_flash(opt.start..opt.end, &mut output)?;
|
||||
flasher.dump_flash(opt.start..opt.end, &mut output).await?;
|
||||
|
||||
log::info!("Success");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use blflash::{check, dump, flash, Opt};
|
||||
use env_logger::Env;
|
||||
use futures::executor::block_on;
|
||||
use main_error::MainError;
|
||||
|
||||
#[paw::main]
|
||||
@ -8,11 +9,13 @@ fn main(args: Opt) -> Result<(), MainError> {
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
|
||||
match args {
|
||||
Opt::Flash(opt) => flash(opt)?,
|
||||
Opt::Check(opt) => check(opt)?,
|
||||
Opt::Dump(opt) => dump(opt)?,
|
||||
};
|
||||
block_on(async {
|
||||
match args {
|
||||
Opt::Flash(opt) => flash(opt).await,
|
||||
Opt::Check(opt) => check(opt).await,
|
||||
Opt::Dump(opt) => dump(opt).await,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -17,3 +17,4 @@ color-eyre = "0.5.10"
|
||||
structopt = "0.3.21"
|
||||
paw = "1.0.0"
|
||||
env_logger = "0.8.2"
|
||||
futures = "0.3"
|
||||
|
@ -32,7 +32,7 @@ enum Opt {
|
||||
Blflash(BlflashOpt),
|
||||
}
|
||||
|
||||
fn blflash_main(args: BlflashOpt) -> Result<()> {
|
||||
async fn blflash_main(args: BlflashOpt) -> Result<()> {
|
||||
let chip = Bl602;
|
||||
let target = chip.target();
|
||||
|
||||
@ -51,7 +51,7 @@ fn blflash_main(args: BlflashOpt) -> Result<()> {
|
||||
boot: args.boot,
|
||||
};
|
||||
|
||||
flash(flash_opt)?;
|
||||
flash(flash_opt).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -62,9 +62,11 @@ fn main(args: Opt) -> Result<()> {
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
|
||||
match args {
|
||||
Opt::Blflash(opt) => blflash_main(opt),
|
||||
}
|
||||
futures::executor::block_on(async {
|
||||
match args {
|
||||
Opt::Blflash(opt) => blflash_main(opt).await,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_artifact_path(target: &str, release: bool, example: &Option<String>) -> Result<PathBuf> {
|
||||
|
15
libblflash/Cargo.toml
Normal file
15
libblflash/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "libblflash"
|
||||
version = "0.1.0"
|
||||
authors = ["spacemeowx2 <spacemeowx2@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
blflash = { version = "0.3", path = "../blflash" }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||
wasm-bindgen-futures = "0.4"
|
16
libblflash/src/lib.rs
Normal file
16
libblflash/src/lib.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use blflash::{Boot2Opt, Connection, Error, FlashOpt};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
fn map_result(r: Result<(), Error>) -> JsValue {
|
||||
match r {
|
||||
Ok(_) => JsValue::UNDEFINED,
|
||||
Err(e) => JsValue::from_str(&e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn flash(opt: JsValue) -> JsValue {
|
||||
let opt: FlashOpt = opt.into_serde().unwrap();
|
||||
let result = blflash::flash(opt).await;
|
||||
map_result(result)
|
||||
}
|
Loading…
Reference in New Issue
Block a user