mirror of
https://github.com/spacemeowx2/blflash.git
synced 2024-10-04 13:49:51 +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"
|
||||
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]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@ -103,7 +92,6 @@ dependencies = [
|
||||
name = "blflash"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"async-timer",
|
||||
"byteorder",
|
||||
"crc",
|
||||
"deku",
|
||||
@ -111,6 +99,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"futures",
|
||||
"gloo-events",
|
||||
"gloo-timers",
|
||||
"hex",
|
||||
"indicatif",
|
||||
"js-sys",
|
||||
@ -582,6 +571,19 @@ dependencies = [
|
||||
"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]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
|
@ -40,7 +40,7 @@ wasm-bindgen = "0.2"
|
||||
js-sys = "0.3"
|
||||
once_cell = "1.5"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
async-timer = "0.7"
|
||||
gloo-timers = { version = "0.2", features = ["futures"] }
|
||||
gloo-events = "0.1"
|
||||
wasm-streams = "0.1"
|
||||
|
||||
|
@ -5,116 +5,209 @@ pub mod binding {
|
||||
}
|
||||
|
||||
use crate::Error;
|
||||
use async_timer::oneshot::{Oneshot, Timer};
|
||||
use futures::{
|
||||
channel::mpsc,
|
||||
io::{AsyncRead, AsyncWrite},
|
||||
io::{AsyncRead, AsyncReadExt, AsyncWrite},
|
||||
ready,
|
||||
sink::Sink,
|
||||
stream::{BoxStream, IntoAsyncRead, Stream, StreamExt, TryStreamExt},
|
||||
sink::SinkExt,
|
||||
stream::{IntoAsyncRead, LocalBoxStream, StreamExt, TryStreamExt},
|
||||
};
|
||||
use gloo_events::EventListener;
|
||||
use js_sys::Reflect;
|
||||
use gloo_timers::future::TimeoutFuture;
|
||||
use js_sys::{Reflect, Uint8Array};
|
||||
use serial::SerialPortSettings;
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
io,
|
||||
pin::Pin,
|
||||
sync::Mutex,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use wasm_bindgen_futures::{spawn_local, JsFuture};
|
||||
use wasm_streams::{
|
||||
readable::{IntoStream, ReadableStream},
|
||||
readable::ReadableStream,
|
||||
writable::{IntoSink, WritableStream},
|
||||
};
|
||||
use web_sys::{window, EventTarget};
|
||||
|
||||
#[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);
|
||||
}
|
||||
use web_sys::window;
|
||||
|
||||
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 {
|
||||
// receiver: IntoAsyncRead<mpsc::Receiver<Item>>,
|
||||
readable: IntoAsyncRead<BoxStream<'static, Item>>,
|
||||
writable: IntoSink<'static>,
|
||||
readable: Option<IntoAsyncRead<LocalBoxStream<'static, Item>>>,
|
||||
writable: Option<IntoSink<'static>>,
|
||||
port: binding::SerialPort,
|
||||
signals: binding::SerialOutputSignals,
|
||||
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,
|
||||
_on_disconnect: EventListener,
|
||||
let readable = ReadableStream::from_raw(readable.unchecked_into());
|
||||
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 {
|
||||
pub async fn open(_port: &str) -> crate::Result<Self> {
|
||||
let window = window().ok_or(Error::WebError("Failed to get window"))?;
|
||||
let navigator = window
|
||||
.navigator()
|
||||
.dyn_into::<binding::Navigator>()
|
||||
.expect("navigator");
|
||||
let navigator: JsValue = window.navigator().into();
|
||||
let navigator: binding::Navigator = navigator.into();
|
||||
|
||||
let serial = navigator.serial();
|
||||
let port = Into::<JsFuture>::into(serial.request_port())
|
||||
let port = JsFuture::from(serial.request_port())
|
||||
.await
|
||||
.expect("Failed to await request_port")
|
||||
.dyn_into::<binding::SerialPort>()
|
||||
.expect("SerialPort");
|
||||
let target: JsValue = port.clone().into();
|
||||
let target: EventTarget = target.into();
|
||||
.map_err(|_| Error::WebError("Failed to await request_port"))?;
|
||||
|
||||
// let (sender, b) = mpsc::channel(128);
|
||||
// let (c, receiver) = mpsc::channel(128);
|
||||
// let target: EventTarget = port.clone().into();
|
||||
let port: binding::SerialPort = port.into();
|
||||
|
||||
let _on_connect = EventListener::new(&target, "connect", move |_event| log("on connect!"));
|
||||
let _on_disconnect =
|
||||
EventListener::new(&target, "disconnect", move |_event| log("on disconnect!"));
|
||||
// make sure the port is closed
|
||||
if let Err(e) = JsFuture::from(port.close()).await {
|
||||
log::warn!("Failed to close port {:?}", e);
|
||||
}
|
||||
|
||||
let readable = Reflect::get(&port, &"readable".into()).expect("readable");
|
||||
let writable = Reflect::get(&port, &"writable".into()).expect("writable");
|
||||
let option = binding::SerialOptions::new(115200);
|
||||
JsFuture::from(port.open(&option))
|
||||
.await
|
||||
.map_err(|_| Error::WebError("Failed to open serial"))?;
|
||||
|
||||
let readable = ReadableStream::from_raw(readable.unchecked_into());
|
||||
let writable = WritableStream::from_raw(writable.unchecked_into());
|
||||
// let opened = Rc::new(RefCell::new(true));
|
||||
// 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 {
|
||||
writable: writable.into_sink(),
|
||||
readable: readable.into_stream().boxed().into_async_read(),
|
||||
readable,
|
||||
writable,
|
||||
port,
|
||||
signals: binding::SerialOutputSignals::new(),
|
||||
timeout: Duration::from_secs(1),
|
||||
open: Mutex::new(false),
|
||||
writing: false,
|
||||
_on_connect,
|
||||
_on_disconnect,
|
||||
// opened,
|
||||
option,
|
||||
// _on_connect,
|
||||
// _on_disconnect,
|
||||
})
|
||||
}
|
||||
pub async fn set_rts(&mut self, level: bool) -> serial::Result<()> {
|
||||
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
|
||||
.expect("Failed to set signals");
|
||||
.map_err(|_| serial::Error::new(serial::ErrorKind::NoDevice, "Failed to set_rts"))?;
|
||||
Ok(())
|
||||
}
|
||||
pub async fn set_dtr(&mut self, level: bool) -> serial::Result<()> {
|
||||
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
|
||||
.expect("Failed to set signals");
|
||||
.map_err(|_| serial::Error::new(serial::ErrorKind::NoDevice, "Failed to set_dtr"))?;
|
||||
Ok(())
|
||||
}
|
||||
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<()> {
|
||||
self.timeout = timeout;
|
||||
@ -127,7 +220,27 @@ impl AsyncSerial {
|
||||
&mut self,
|
||||
setup: &dyn Fn(&mut dyn SerialPortSettings) -> 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(())
|
||||
}
|
||||
}
|
||||
@ -138,7 +251,8 @@ impl AsyncRead for AsyncSerial {
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> 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<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
if !self.writing {
|
||||
self.writing = true;
|
||||
self.writable
|
||||
.start_send(Ok(Vec::from(buf)))
|
||||
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?
|
||||
}
|
||||
let r = ready!(self.writable.poll_ready(cx));
|
||||
r.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
||||
self.writing = false;
|
||||
let writable = self.writable.as_mut().unwrap();
|
||||
ready!(writable.poll_ready_unpin(cx))
|
||||
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
||||
|
||||
let jsbuf: JsValue = Uint8Array::from(buf).into();
|
||||
writable
|
||||
.start_send_unpin(jsbuf)
|
||||
.map_err(|_| Into::<io::Error>::into(io::ErrorKind::BrokenPipe))?;
|
||||
Poll::Ready(Ok(buf.len()))
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
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<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
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> {
|
||||
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.sleep(Duration::from_millis(50)).await;
|
||||
self.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_dtr(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.sleep(Duration::from_millis(50)).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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.sleep(Duration::from_millis(50)).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.sleep(Duration::from_millis(50)).await;
|
||||
self.sleep(Duration::from_millis(50)).await;
|
||||
self.serial.set_rts(false).await?;
|
||||
self.serial.sleep(Duration::from_millis(50)).await;
|
||||
self.sleep(Duration::from_millis(50)).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn sleep(&self, duration: Duration) {
|
||||
self.serial.sleep(duration).await
|
||||
}
|
||||
|
||||
pub async fn timeout(&self) -> Duration {
|
||||
self.serial.timeout().await
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ use crate::{connection::Connection, elf::RomSegment};
|
||||
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
|
||||
use serial::BaudRate;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::ops::Range;
|
||||
use std::{
|
||||
io::{Cursor, Read, Write},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use std::{ops::Range, thread::sleep};
|
||||
|
||||
fn get_bar(len: u64) -> ProgressBar {
|
||||
let bar = ProgressBar::new(len);
|
||||
@ -97,20 +97,26 @@ impl Flasher {
|
||||
let mut reader = Cursor::new(&segment.data);
|
||||
let mut cur = segment.addr;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let start = Instant::now();
|
||||
log::info!("Program flash... {:x}", local_hash);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let pb = get_bar(segment.size() as u64);
|
||||
loop {
|
||||
let size = self.eflash_loader().flash_program(cur, &mut reader).await?;
|
||||
// log::trace!("program {:x} {:x}", cur, size);
|
||||
cur += size;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.inc(size as u64);
|
||||
if size == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.finish_and_clear();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let elapsed = start.elapsed();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
log::info!(
|
||||
"Program done {:?} {}/s",
|
||||
elapsed,
|
||||
@ -168,6 +174,7 @@ impl Flasher {
|
||||
|
||||
const BLOCK_SIZE: usize = 4096;
|
||||
let mut cur = range.start;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let pb = get_bar(range.len() as u64);
|
||||
while cur < range.end {
|
||||
let data = self
|
||||
@ -176,8 +183,10 @@ impl Flasher {
|
||||
.await?;
|
||||
writer.write_all(&data)?;
|
||||
cur += data.len() as u32;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.inc(data.len() as u64);
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.finish_and_clear();
|
||||
|
||||
Ok(())
|
||||
@ -190,18 +199,24 @@ impl Flasher {
|
||||
self.boot_rom().load_boot_header(&mut reader).await?;
|
||||
self.boot_rom().load_segment_header(&mut reader).await?;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let start = Instant::now();
|
||||
log::info!("Sending eflash_loader...");
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let pb = get_bar(len as u64);
|
||||
loop {
|
||||
let size = self.boot_rom().load_segment_data(&mut reader).await?;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.inc(size as u64);
|
||||
if size == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pb.finish_and_clear();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let elapsed = start.elapsed();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
log::info!(
|
||||
"Finished {:?} {}/s",
|
||||
elapsed,
|
||||
@ -210,7 +225,7 @@ impl Flasher {
|
||||
|
||||
self.boot_rom().check_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.handshake().await?;
|
||||
|
||||
@ -239,11 +254,13 @@ impl Flasher {
|
||||
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();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let start = Instant::now();
|
||||
connection.write_all(&data).await?;
|
||||
connection.flush().await?;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
log::trace!("handshake sent elapsed {:?}", start.elapsed());
|
||||
sleep(Duration::from_millis(200));
|
||||
connection.sleep(Duration::from_millis(200)).await;
|
||||
|
||||
for _ in 0..5 {
|
||||
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 fn fs_read_file(path: PathBuf) -> Option<Vec<u8>> {
|
||||
pub fn fs_read_file(_path: PathBuf) -> Option<Vec<u8>> {
|
||||
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")
|
||||
}
|
||||
pub fn fs_remove_file(path: PathBuf) {
|
||||
pub fn fs_remove_file(_path: PathBuf) {
|
||||
unimplemented!("only avaliable on wasm")
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
io::{self, Cursor, Write},
|
||||
path::{Path, PathBuf},
|
||||
sync::Mutex,
|
||||
@ -44,7 +43,11 @@ impl Drop for File {
|
||||
}
|
||||
|
||||
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>> {
|
||||
|
@ -9,8 +9,8 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
blflash = { version = "0.3", path = "../blflash" }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
log = "0.4"
|
||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||
wasm-bindgen-futures = "0.4"
|
||||
console_error_panic_hook = "0.1"
|
||||
wasm-logger = "0.2"
|
||||
|
@ -6,5 +6,7 @@
|
||||
<body>
|
||||
<script type="module" src="index.js"></script>
|
||||
<button id="dump">dump</button>
|
||||
<button id="flash">flash</button>
|
||||
<input id="file" type="file"></input>
|
||||
</body>
|
||||
</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() {
|
||||
await dump({
|
||||
port: 'port',
|
||||
baud_rate: 115200,
|
||||
initial_baud_rate: 115200,
|
||||
output: "output.bin",
|
||||
start: 0,
|
||||
end: 0x100000,
|
||||
})
|
||||
try {
|
||||
await dump({
|
||||
port: 'port',
|
||||
baud_rate: 1000000,
|
||||
initial_baud_rate: 115200,
|
||||
output: "output.bin",
|
||||
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() {
|
||||
console.log('load wasm')
|
||||
await init()
|
||||
console.log('wasm loaded')
|
||||
|
||||
// const r = await dump({
|
||||
// port: 'port',
|
||||
// baud_rate: 115200,
|
||||
// initial_baud_rate: 115200,
|
||||
// output: "output.bin",
|
||||
// start: 0,
|
||||
// end: 0x100000,
|
||||
// })
|
||||
// console.log(r)
|
||||
document.getElementById('dump').addEventListener('click', onDump)
|
||||
document.getElementById('flash').addEventListener('click', onFlash)
|
||||
}
|
||||
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 std::path::PathBuf;
|
||||
mod utils;
|
||||
|
||||
fn map_result(r: Result<(), Error>) -> JsValue {
|
||||
match r {
|
||||
Ok(_) => JsValue::UNDEFINED,
|
||||
Err(e) => JsValue::from_str(&e.to_string()),
|
||||
}
|
||||
fn init() {
|
||||
utils::set_panic_hook();
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn flash(opt: JsValue) -> JsValue {
|
||||
utils::set_panic_hook();
|
||||
pub async fn flash(opt: JsValue) -> Result<(), JsValue> {
|
||||
init();
|
||||
|
||||
let opt: FlashOpt = opt.into_serde().unwrap();
|
||||
let result = blflash::flash(opt).await;
|
||||
map_result(result)
|
||||
let opt: FlashOpt = opt.into_serde().map_err(|e| e.to_string())?;
|
||||
blflash::flash(opt).await.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn dump(opt: JsValue) -> JsValue {
|
||||
utils::set_panic_hook();
|
||||
pub async fn dump(opt: JsValue) -> Result<(), JsValue> {
|
||||
init();
|
||||
|
||||
let opt: DumpOpt = opt.into_serde().unwrap();
|
||||
let result = blflash::dump(opt).await;
|
||||
map_result(result)
|
||||
let opt: DumpOpt = opt.into_serde().map_err(|e| e.to_string())?;
|
||||
blflash::dump(opt).await.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct FS;
|
||||
|
Loading…
Reference in New Issue
Block a user