mirror of
https://github.com/spacemeowx2/blflash.git
synced 2024-09-04 05:29:02 +00:00
feat: wasm is working
This commit is contained in:
parent
7f8f042814
commit
c7cf168cfb
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -39,17 +39,6 @@ version = "1.0.37"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86"
|
checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-timer"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba5fa6ed76cb2aa820707b4eb9ec46f42da9ce70b0eafab5e5e34942b38a44d5"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -103,7 +92,6 @@ dependencies = [
|
|||||||
name = "blflash"
|
name = "blflash"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-timer",
|
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"crc",
|
"crc",
|
||||||
"deku",
|
"deku",
|
||||||
@ -111,6 +99,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"gloo-events",
|
"gloo-events",
|
||||||
|
"gloo-timers",
|
||||||
"hex",
|
"hex",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -582,6 +571,19 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-timers"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -40,7 +40,7 @@ wasm-bindgen = "0.2"
|
|||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
once_cell = "1.5"
|
once_cell = "1.5"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
async-timer = "0.7"
|
gloo-timers = { version = "0.2", features = ["futures"] }
|
||||||
gloo-events = "0.1"
|
gloo-events = "0.1"
|
||||||
wasm-streams = "0.1"
|
wasm-streams = "0.1"
|
||||||
|
|
||||||
|
@ -5,116 +5,209 @@ pub mod binding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use async_timer::oneshot::{Oneshot, Timer};
|
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc,
|
io::{AsyncRead, AsyncReadExt, AsyncWrite},
|
||||||
io::{AsyncRead, AsyncWrite},
|
|
||||||
ready,
|
ready,
|
||||||
sink::Sink,
|
sink::SinkExt,
|
||||||
stream::{BoxStream, IntoAsyncRead, Stream, StreamExt, TryStreamExt},
|
stream::{IntoAsyncRead, LocalBoxStream, StreamExt, TryStreamExt},
|
||||||
};
|
};
|
||||||
use gloo_events::EventListener;
|
use gloo_timers::future::TimeoutFuture;
|
||||||
use js_sys::Reflect;
|
use js_sys::{Reflect, Uint8Array};
|
||||||
use serial::SerialPortSettings;
|
use serial::SerialPortSettings;
|
||||||
use std::{
|
use std::{
|
||||||
|
convert::TryInto,
|
||||||
io,
|
io,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::Mutex,
|
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use wasm_bindgen::{prelude::*, JsCast};
|
use wasm_bindgen::{prelude::*, JsCast};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::{spawn_local, JsFuture};
|
||||||
use wasm_streams::{
|
use wasm_streams::{
|
||||||
readable::{IntoStream, ReadableStream},
|
readable::ReadableStream,
|
||||||
writable::{IntoSink, WritableStream},
|
writable::{IntoSink, WritableStream},
|
||||||
};
|
};
|
||||||
use web_sys::{window, EventTarget};
|
use web_sys::window;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
extern "C" {
|
|
||||||
// #[wasm_bindgen(extends=js_sys::Object, js_name=Serial , typescript_type="Serial")]
|
|
||||||
// pub type Serial;
|
|
||||||
// #[wasm_bindgen(catch, method, structural, js_class="Serial" , js_name=requestPort)]
|
|
||||||
// pub fn requestPort(this: &Serial) -> Result<Promise, JsValue>;
|
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
|
||||||
fn log(s: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
type Item = io::Result<Vec<u8>>;
|
type Item = io::Result<Vec<u8>>;
|
||||||
|
|
||||||
|
struct Settings<'a>(&'a mut binding::SerialOptions);
|
||||||
|
impl<'a> SerialPortSettings for Settings<'a> {
|
||||||
|
fn baud_rate(&self) -> Option<serial::BaudRate> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn char_size(&self) -> Option<serial::CharSize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parity(&self) -> Option<serial::Parity> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_bits(&self) -> Option<serial::StopBits> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flow_control(&self) -> Option<serial::FlowControl> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_baud_rate(&mut self, baud_rate: serial::BaudRate) -> serial::Result<()> {
|
||||||
|
log::trace!("set_baud_rate {:?}", baud_rate);
|
||||||
|
self.0.baud_rate(baud_rate.speed() as u32);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_char_size(&mut self, char_size: serial::CharSize) {
|
||||||
|
log::trace!("set_char_size {:?}", char_size);
|
||||||
|
self.0.data_bits(match char_size {
|
||||||
|
serial::CharSize::Bits5 => 5,
|
||||||
|
serial::CharSize::Bits6 => 6,
|
||||||
|
serial::CharSize::Bits7 => 7,
|
||||||
|
serial::CharSize::Bits8 => 8,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_parity(&mut self, parity: serial::Parity) {
|
||||||
|
log::trace!("set_parity {:?}", parity);
|
||||||
|
use binding::ParityType;
|
||||||
|
use serial::Parity;
|
||||||
|
self.0.parity(match parity {
|
||||||
|
Parity::ParityNone => ParityType::None,
|
||||||
|
Parity::ParityEven => ParityType::Even,
|
||||||
|
Parity::ParityOdd => ParityType::Odd,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stop_bits(&mut self, stop_bits: serial::StopBits) {
|
||||||
|
log::trace!("set_stop_bits {:?}", stop_bits);
|
||||||
|
self.0.stop_bits(match stop_bits {
|
||||||
|
serial::StopBits::Stop1 => 1,
|
||||||
|
serial::StopBits::Stop2 => 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_flow_control(&mut self, flow_control: serial::FlowControl) {
|
||||||
|
log::trace!("set_flow_control {:?}", flow_control);
|
||||||
|
use binding::FlowControlType;
|
||||||
|
use serial::FlowControl;
|
||||||
|
self.0.flow_control(match flow_control {
|
||||||
|
FlowControl::FlowNone => FlowControlType::None,
|
||||||
|
FlowControl::FlowHardware => FlowControlType::Hardware,
|
||||||
|
_ => unreachable!(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AsyncSerial {
|
pub struct AsyncSerial {
|
||||||
// receiver: IntoAsyncRead<mpsc::Receiver<Item>>,
|
readable: Option<IntoAsyncRead<LocalBoxStream<'static, Item>>>,
|
||||||
readable: IntoAsyncRead<BoxStream<'static, Item>>,
|
writable: Option<IntoSink<'static>>,
|
||||||
writable: IntoSink<'static>,
|
|
||||||
port: binding::SerialPort,
|
port: binding::SerialPort,
|
||||||
signals: binding::SerialOutputSignals,
|
signals: binding::SerialOutputSignals,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
writing: bool,
|
option: binding::SerialOptions,
|
||||||
|
// opened: Rc<RefCell<bool>>,
|
||||||
|
// _on_connect: EventListener,
|
||||||
|
// _on_disconnect: EventListener,
|
||||||
|
}
|
||||||
|
|
||||||
open: Mutex<bool>,
|
fn get_pipe(
|
||||||
|
port: &JsValue,
|
||||||
|
) -> crate::Result<(
|
||||||
|
Option<IntoAsyncRead<LocalBoxStream<'static, Item>>>,
|
||||||
|
Option<IntoSink<'static>>,
|
||||||
|
)> {
|
||||||
|
let readable = Reflect::get(&port, &"readable".into())
|
||||||
|
.map_err(|_| Error::WebError("Failed to get readable"))?;
|
||||||
|
let writable = Reflect::get(&port, &"writable".into())
|
||||||
|
.map_err(|_| Error::WebError("Failed to get writable"))?;
|
||||||
|
|
||||||
_on_connect: EventListener,
|
let readable = ReadableStream::from_raw(readable.unchecked_into());
|
||||||
_on_disconnect: EventListener,
|
let writable = WritableStream::from_raw(writable.unchecked_into());
|
||||||
|
|
||||||
|
let readable = readable
|
||||||
|
.into_stream()
|
||||||
|
.map(|item| {
|
||||||
|
item.map(|v| v.unchecked_into::<Uint8Array>().to_vec())
|
||||||
|
.map_err(|_| io::Error::from(io::ErrorKind::BrokenPipe))
|
||||||
|
})
|
||||||
|
.boxed_local()
|
||||||
|
.into_async_read();
|
||||||
|
|
||||||
|
Ok((Some(readable), Some(writable.into_sink())))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncSerial {
|
impl AsyncSerial {
|
||||||
pub async fn open(_port: &str) -> crate::Result<Self> {
|
pub async fn open(_port: &str) -> crate::Result<Self> {
|
||||||
let window = window().ok_or(Error::WebError("Failed to get window"))?;
|
let window = window().ok_or(Error::WebError("Failed to get window"))?;
|
||||||
let navigator = window
|
let navigator: JsValue = window.navigator().into();
|
||||||
.navigator()
|
let navigator: binding::Navigator = navigator.into();
|
||||||
.dyn_into::<binding::Navigator>()
|
|
||||||
.expect("navigator");
|
|
||||||
let serial = navigator.serial();
|
let serial = navigator.serial();
|
||||||
let port = Into::<JsFuture>::into(serial.request_port())
|
let port = JsFuture::from(serial.request_port())
|
||||||
.await
|
.await
|
||||||
.expect("Failed to await request_port")
|
.map_err(|_| Error::WebError("Failed to await request_port"))?;
|
||||||
.dyn_into::<binding::SerialPort>()
|
|
||||||
.expect("SerialPort");
|
|
||||||
let target: JsValue = port.clone().into();
|
|
||||||
let target: EventTarget = target.into();
|
|
||||||
|
|
||||||
// let (sender, b) = mpsc::channel(128);
|
// let target: EventTarget = port.clone().into();
|
||||||
// let (c, receiver) = mpsc::channel(128);
|
let port: binding::SerialPort = port.into();
|
||||||
|
|
||||||
let _on_connect = EventListener::new(&target, "connect", move |_event| log("on connect!"));
|
// make sure the port is closed
|
||||||
let _on_disconnect =
|
if let Err(e) = JsFuture::from(port.close()).await {
|
||||||
EventListener::new(&target, "disconnect", move |_event| log("on disconnect!"));
|
log::warn!("Failed to close port {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
let readable = Reflect::get(&port, &"readable".into()).expect("readable");
|
let option = binding::SerialOptions::new(115200);
|
||||||
let writable = Reflect::get(&port, &"writable".into()).expect("writable");
|
JsFuture::from(port.open(&option))
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::WebError("Failed to open serial"))?;
|
||||||
|
|
||||||
let readable = ReadableStream::from_raw(readable.unchecked_into());
|
// let opened = Rc::new(RefCell::new(true));
|
||||||
let writable = WritableStream::from_raw(writable.unchecked_into());
|
// let _on_connect = {
|
||||||
|
// let open = open.clone();
|
||||||
|
// EventListener::new(&target, "connect", move |_event| {
|
||||||
|
// log("on connect!");
|
||||||
|
// open.replace(true);
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
// let _on_disconnect = {
|
||||||
|
// let open = open.clone();
|
||||||
|
// EventListener::new(&target, "disconnect", move |_event| {
|
||||||
|
// log("on disconnect!");
|
||||||
|
// open.replace(false);
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
|
||||||
|
let (readable, writable) = get_pipe(&port)?;
|
||||||
|
|
||||||
Ok(AsyncSerial {
|
Ok(AsyncSerial {
|
||||||
writable: writable.into_sink(),
|
readable,
|
||||||
readable: readable.into_stream().boxed().into_async_read(),
|
writable,
|
||||||
port,
|
port,
|
||||||
signals: binding::SerialOutputSignals::new(),
|
signals: binding::SerialOutputSignals::new(),
|
||||||
timeout: Duration::from_secs(1),
|
timeout: Duration::from_secs(1),
|
||||||
open: Mutex::new(false),
|
// opened,
|
||||||
writing: false,
|
option,
|
||||||
_on_connect,
|
// _on_connect,
|
||||||
_on_disconnect,
|
// _on_disconnect,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub async fn set_rts(&mut self, level: bool) -> serial::Result<()> {
|
pub async fn set_rts(&mut self, level: bool) -> serial::Result<()> {
|
||||||
self.signals.request_to_send(level);
|
self.signals.request_to_send(level);
|
||||||
Into::<JsFuture>::into(self.port.set_signals_with_signals(&self.signals))
|
JsFuture::from(self.port.set_signals_with_signals(&self.signals))
|
||||||
.await
|
.await
|
||||||
.expect("Failed to set signals");
|
.map_err(|_| serial::Error::new(serial::ErrorKind::NoDevice, "Failed to set_rts"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn set_dtr(&mut self, level: bool) -> serial::Result<()> {
|
pub async fn set_dtr(&mut self, level: bool) -> serial::Result<()> {
|
||||||
self.signals.data_terminal_ready(level);
|
self.signals.data_terminal_ready(level);
|
||||||
Into::<JsFuture>::into(self.port.set_signals_with_signals(&self.signals))
|
JsFuture::from(self.port.set_signals_with_signals(&self.signals))
|
||||||
.await
|
.await
|
||||||
.expect("Failed to set signals");
|
.map_err(|_| serial::Error::new(serial::ErrorKind::NoDevice, "Failed to set_dtr"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn sleep(&self, duration: Duration) {
|
pub async fn sleep(&self, duration: Duration) {
|
||||||
Timer::new(duration).await;
|
TimeoutFuture::new(duration.as_millis().try_into().unwrap()).await;
|
||||||
}
|
}
|
||||||
pub async fn set_timeout(&mut self, timeout: Duration) -> serial::Result<()> {
|
pub async fn set_timeout(&mut self, timeout: Duration) -> serial::Result<()> {
|
||||||
self.timeout = timeout;
|
self.timeout = timeout;
|
||||||
@ -127,7 +220,27 @@ impl AsyncSerial {
|
|||||||
&mut self,
|
&mut self,
|
||||||
setup: &dyn Fn(&mut dyn SerialPortSettings) -> serial::Result<()>,
|
setup: &dyn Fn(&mut dyn SerialPortSettings) -> serial::Result<()>,
|
||||||
) -> serial::Result<()> {
|
) -> serial::Result<()> {
|
||||||
// TODO
|
let mut settings = Settings(&mut self.option);
|
||||||
|
setup(&mut settings)?;
|
||||||
|
|
||||||
|
self.readable.take();
|
||||||
|
self.writable.take();
|
||||||
|
// make sure the port is closed
|
||||||
|
if let Err(e) = JsFuture::from(self.port.close()).await {
|
||||||
|
log::warn!("Failed to close port {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsFuture::from(self.port.open(&self.option))
|
||||||
|
.await
|
||||||
|
.map_err(|_| {
|
||||||
|
serial::Error::new(serial::ErrorKind::NoDevice, "Failed to open serial")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let (readable, writable) = get_pipe(&self.port)
|
||||||
|
.map_err(|_| serial::Error::new(serial::ErrorKind::NoDevice, "Failed to get pipe"))?;
|
||||||
|
self.readable = readable;
|
||||||
|
self.writable = writable;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,7 +251,8 @@ impl AsyncRead for AsyncSerial {
|
|||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
AsyncRead::poll_read(Pin::new(&mut self.readable), cx, buf)
|
// self.readable.poll_read_unpin(cx, buf)
|
||||||
|
AsyncRead::poll_read(Pin::new(&mut self.readable.as_mut().unwrap()), cx, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,23 +262,26 @@ impl AsyncWrite for AsyncSerial {
|
|||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<usize>> {
|
||||||
if !self.writing {
|
let writable = self.writable.as_mut().unwrap();
|
||||||
self.writing = true;
|
ready!(writable.poll_ready_unpin(cx))
|
||||||
self.writable
|
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
||||||
.start_send(Ok(Vec::from(buf)))
|
|
||||||
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?
|
let jsbuf: JsValue = Uint8Array::from(buf).into();
|
||||||
}
|
writable
|
||||||
let r = ready!(self.writable.poll_ready(cx));
|
.start_send_unpin(jsbuf)
|
||||||
r.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
||||||
self.writing = false;
|
|
||||||
Poll::Ready(Ok(buf.len()))
|
Poll::Ready(Ok(buf.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
Poll::Ready(Ok(()))
|
ready!(self.writable.as_mut().unwrap().poll_flush_unpin(cx))
|
||||||
|
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_close(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
Poll::Ready(Ok(()))
|
ready!(self.writable.as_mut().unwrap().poll_close_unpin(cx))
|
||||||
|
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,28 +78,32 @@ impl Connection {
|
|||||||
|
|
||||||
pub async fn reset(&mut self) -> Result<(), Error> {
|
pub async fn reset(&mut self) -> Result<(), Error> {
|
||||||
self.serial.set_rts(false).await?;
|
self.serial.set_rts(false).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
self.serial.set_dtr(true).await?;
|
self.serial.set_dtr(true).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
self.serial.set_dtr(false).await?;
|
self.serial.set_dtr(false).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn reset_to_flash(&mut self) -> Result<(), Error> {
|
pub async fn reset_to_flash(&mut self) -> Result<(), Error> {
|
||||||
self.serial.set_rts(true).await?;
|
self.serial.set_rts(true).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
self.serial.set_dtr(true).await?;
|
self.serial.set_dtr(true).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
self.serial.set_dtr(false).await?;
|
self.serial.set_dtr(false).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
self.serial.set_rts(false).await?;
|
self.serial.set_rts(false).await?;
|
||||||
self.serial.sleep(Duration::from_millis(50)).await;
|
self.sleep(Duration::from_millis(50)).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sleep(&self, duration: Duration) {
|
||||||
|
self.serial.sleep(duration).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn timeout(&self) -> Duration {
|
pub async fn timeout(&self) -> Duration {
|
||||||
self.serial.timeout().await
|
self.serial.timeout().await
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ use crate::{connection::Connection, elf::RomSegment};
|
|||||||
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
|
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
|
||||||
use serial::BaudRate;
|
use serial::BaudRate;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::ops::Range;
|
||||||
use std::{
|
use std::{
|
||||||
io::{Cursor, Read, Write},
|
io::{Cursor, Read, Write},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use std::{ops::Range, thread::sleep};
|
|
||||||
|
|
||||||
fn get_bar(len: u64) -> ProgressBar {
|
fn get_bar(len: u64) -> ProgressBar {
|
||||||
let bar = ProgressBar::new(len);
|
let bar = ProgressBar::new(len);
|
||||||
@ -97,20 +97,26 @@ impl Flasher {
|
|||||||
let mut reader = Cursor::new(&segment.data);
|
let mut reader = Cursor::new(&segment.data);
|
||||||
let mut cur = segment.addr;
|
let mut cur = segment.addr;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
log::info!("Program flash... {:x}", local_hash);
|
log::info!("Program flash... {:x}", local_hash);
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let pb = get_bar(segment.size() as u64);
|
let pb = get_bar(segment.size() as u64);
|
||||||
loop {
|
loop {
|
||||||
let size = self.eflash_loader().flash_program(cur, &mut reader).await?;
|
let size = self.eflash_loader().flash_program(cur, &mut reader).await?;
|
||||||
// log::trace!("program {:x} {:x}", cur, size);
|
// log::trace!("program {:x} {:x}", cur, size);
|
||||||
cur += size;
|
cur += size;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.inc(size as u64);
|
pb.inc(size as u64);
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.finish_and_clear();
|
pb.finish_and_clear();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
log::info!(
|
log::info!(
|
||||||
"Program done {:?} {}/s",
|
"Program done {:?} {}/s",
|
||||||
elapsed,
|
elapsed,
|
||||||
@ -168,6 +174,7 @@ impl Flasher {
|
|||||||
|
|
||||||
const BLOCK_SIZE: usize = 4096;
|
const BLOCK_SIZE: usize = 4096;
|
||||||
let mut cur = range.start;
|
let mut cur = range.start;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let pb = get_bar(range.len() as u64);
|
let pb = get_bar(range.len() as u64);
|
||||||
while cur < range.end {
|
while cur < range.end {
|
||||||
let data = self
|
let data = self
|
||||||
@ -176,8 +183,10 @@ impl Flasher {
|
|||||||
.await?;
|
.await?;
|
||||||
writer.write_all(&data)?;
|
writer.write_all(&data)?;
|
||||||
cur += data.len() as u32;
|
cur += data.len() as u32;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.inc(data.len() as u64);
|
pb.inc(data.len() as u64);
|
||||||
}
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.finish_and_clear();
|
pb.finish_and_clear();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -190,18 +199,24 @@ impl Flasher {
|
|||||||
self.boot_rom().load_boot_header(&mut reader).await?;
|
self.boot_rom().load_boot_header(&mut reader).await?;
|
||||||
self.boot_rom().load_segment_header(&mut reader).await?;
|
self.boot_rom().load_segment_header(&mut reader).await?;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
log::info!("Sending eflash_loader...");
|
log::info!("Sending eflash_loader...");
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let pb = get_bar(len as u64);
|
let pb = get_bar(len as u64);
|
||||||
loop {
|
loop {
|
||||||
let size = self.boot_rom().load_segment_data(&mut reader).await?;
|
let size = self.boot_rom().load_segment_data(&mut reader).await?;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.inc(size as u64);
|
pb.inc(size as u64);
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pb.finish_and_clear();
|
pb.finish_and_clear();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
log::info!(
|
log::info!(
|
||||||
"Finished {:?} {}/s",
|
"Finished {:?} {}/s",
|
||||||
elapsed,
|
elapsed,
|
||||||
@ -210,7 +225,7 @@ impl Flasher {
|
|||||||
|
|
||||||
self.boot_rom().check_image().await?;
|
self.boot_rom().check_image().await?;
|
||||||
self.boot_rom().run_image().await?;
|
self.boot_rom().run_image().await?;
|
||||||
sleep(Duration::from_millis(500));
|
self.connection.sleep(Duration::from_millis(500)).await;
|
||||||
self.connection.set_baud(self.flash_speed).await?;
|
self.connection.set_baud(self.flash_speed).await?;
|
||||||
self.handshake().await?;
|
self.handshake().await?;
|
||||||
|
|
||||||
@ -239,11 +254,13 @@ impl Flasher {
|
|||||||
let len = connection.calc_duration_length(Duration::from_millis(5));
|
let len = connection.calc_duration_length(Duration::from_millis(5));
|
||||||
log::trace!("5ms send count {}", len);
|
log::trace!("5ms send count {}", len);
|
||||||
let data: Vec<u8> = std::iter::repeat(0x55u8).take(len).collect();
|
let data: Vec<u8> = std::iter::repeat(0x55u8).take(len).collect();
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
connection.write_all(&data).await?;
|
connection.write_all(&data).await?;
|
||||||
connection.flush().await?;
|
connection.flush().await?;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
log::trace!("handshake sent elapsed {:?}", start.elapsed());
|
log::trace!("handshake sent elapsed {:?}", start.elapsed());
|
||||||
sleep(Duration::from_millis(200));
|
connection.sleep(Duration::from_millis(200)).await;
|
||||||
|
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
if connection.read_response(0).await.is_ok() {
|
if connection.read_response(0).await.is_ok() {
|
||||||
|
@ -11,12 +11,12 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
|||||||
|
|
||||||
pub use fs::File;
|
pub use fs::File;
|
||||||
|
|
||||||
pub fn fs_read_file(path: PathBuf) -> Option<Vec<u8>> {
|
pub fn fs_read_file(_path: PathBuf) -> Option<Vec<u8>> {
|
||||||
unimplemented!("only avaliable on wasm")
|
unimplemented!("only avaliable on wasm")
|
||||||
}
|
}
|
||||||
pub fn fs_write_file(path: PathBuf, content: Vec<u8>) {
|
pub fn fs_write_file(_path: PathBuf, _content: Vec<u8>) {
|
||||||
unimplemented!("only avaliable on wasm")
|
unimplemented!("only avaliable on wasm")
|
||||||
}
|
}
|
||||||
pub fn fs_remove_file(path: PathBuf) {
|
pub fn fs_remove_file(_path: PathBuf) {
|
||||||
unimplemented!("only avaliable on wasm")
|
unimplemented!("only avaliable on wasm")
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs,
|
|
||||||
io::{self, Cursor, Write},
|
io::{self, Cursor, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
@ -44,7 +43,11 @@ impl Drop for File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
||||||
fs::read(path)
|
FS.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&path.as_ref().to_path_buf())
|
||||||
|
.map(Clone::clone)
|
||||||
|
.ok_or(io::ErrorKind::NotFound.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fs_read_file(path: PathBuf) -> Option<Vec<u8>> {
|
pub fn fs_read_file(path: PathBuf) -> Option<Vec<u8>> {
|
||||||
|
@ -9,8 +9,8 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
blflash = { version = "0.3", path = "../blflash" }
|
blflash = { version = "0.3", path = "../blflash" }
|
||||||
|
log = "0.4"
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
|
||||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
|
wasm-logger = "0.2"
|
||||||
|
@ -6,5 +6,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<script type="module" src="index.js"></script>
|
<script type="module" src="index.js"></script>
|
||||||
<button id="dump">dump</button>
|
<button id="dump">dump</button>
|
||||||
|
<button id="flash">flash</button>
|
||||||
|
<input id="file" type="file"></input>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,29 +1,45 @@
|
|||||||
import init, { dump, FS } from './pkg/libblflash.js'
|
import init, { dump, flash, FS } from './pkg/libblflash.js'
|
||||||
|
|
||||||
async function onDump() {
|
async function onDump() {
|
||||||
await dump({
|
try {
|
||||||
port: 'port',
|
await dump({
|
||||||
baud_rate: 115200,
|
port: 'port',
|
||||||
initial_baud_rate: 115200,
|
baud_rate: 1000000,
|
||||||
output: "output.bin",
|
initial_baud_rate: 115200,
|
||||||
start: 0,
|
output: "output.bin",
|
||||||
end: 0x100000,
|
start: 0,
|
||||||
})
|
end: 0x100000,
|
||||||
|
})
|
||||||
|
console.log('done')
|
||||||
|
debugger
|
||||||
|
const result = FS.read_file('output.bin')
|
||||||
|
console.log(result)
|
||||||
|
} catch(e) {
|
||||||
|
console.error('error during Dump', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function onFlash(event) {
|
||||||
|
try {
|
||||||
|
const file = document.getElementById('file').files[0]
|
||||||
|
const content = await new Response(file).arrayBuffer()
|
||||||
|
|
||||||
|
FS.write_file('input.bin', new Uint8Array(content))
|
||||||
|
await flash({
|
||||||
|
port: 'port',
|
||||||
|
baud_rate: 1000000,
|
||||||
|
initial_baud_rate: 115200,
|
||||||
|
image: 'input.bin',
|
||||||
|
})
|
||||||
|
console.log('done')
|
||||||
|
} catch(e) {
|
||||||
|
console.error('error during Flash', e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('load wasm')
|
console.log('load wasm')
|
||||||
await init()
|
await init()
|
||||||
console.log('wasm loaded')
|
console.log('wasm loaded')
|
||||||
|
document.getElementById('dump').addEventListener('click', onDump)
|
||||||
// const r = await dump({
|
document.getElementById('flash').addEventListener('click', onFlash)
|
||||||
// port: 'port',
|
|
||||||
// baud_rate: 115200,
|
|
||||||
// initial_baud_rate: 115200,
|
|
||||||
// output: "output.bin",
|
|
||||||
// start: 0,
|
|
||||||
// end: 0x100000,
|
|
||||||
// })
|
|
||||||
// console.log(r)
|
|
||||||
}
|
}
|
||||||
main()
|
main()
|
||||||
document.getElementById('dump').addEventListener('click', onDump)
|
|
@ -1,31 +1,29 @@
|
|||||||
use blflash::{Boot2Opt, Connection, Error, FlashOpt, DumpOpt, fs};
|
use blflash::{Error, FlashOpt, DumpOpt, fs};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn map_result(r: Result<(), Error>) -> JsValue {
|
fn init() {
|
||||||
match r {
|
utils::set_panic_hook();
|
||||||
Ok(_) => JsValue::UNDEFINED,
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||||
Err(e) => JsValue::from_str(&e.to_string()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn flash(opt: JsValue) -> JsValue {
|
pub async fn flash(opt: JsValue) -> Result<(), JsValue> {
|
||||||
utils::set_panic_hook();
|
init();
|
||||||
|
|
||||||
let opt: FlashOpt = opt.into_serde().unwrap();
|
let opt: FlashOpt = opt.into_serde().map_err(|e| e.to_string())?;
|
||||||
let result = blflash::flash(opt).await;
|
blflash::flash(opt).await.map_err(|e| e.to_string())?;
|
||||||
map_result(result)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn dump(opt: JsValue) -> JsValue {
|
pub async fn dump(opt: JsValue) -> Result<(), JsValue> {
|
||||||
utils::set_panic_hook();
|
init();
|
||||||
|
|
||||||
let opt: DumpOpt = opt.into_serde().unwrap();
|
let opt: DumpOpt = opt.into_serde().map_err(|e| e.to_string())?;
|
||||||
let result = blflash::dump(opt).await;
|
blflash::dump(opt).await.map_err(|e| e.to_string())?;
|
||||||
map_result(result)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FS;
|
struct FS;
|
||||||
|
Loading…
Reference in New Issue
Block a user