From c7cf168cfbb7d83c1080edfda3891ee542fc2a60 Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Sat, 9 Jan 2021 15:44:56 +0800 Subject: [PATCH] feat: wasm is working --- Cargo.lock | 26 +-- blflash/Cargo.toml | 2 +- blflash/src/async_serial/wasm.rs | 263 ++++++++++++++++++++++--------- blflash/src/connection.rs | 18 ++- blflash/src/flasher.rs | 23 ++- blflash/src/fs/native.rs | 6 +- blflash/src/fs/wasm.rs | 7 +- libblflash/Cargo.toml | 4 +- libblflash/index.html | 2 + libblflash/index.js | 56 ++++--- libblflash/src/lib.rs | 30 ++-- 11 files changed, 298 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd42472..a8dcb3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/blflash/Cargo.toml b/blflash/Cargo.toml index 1c87e1c..f16183a 100644 --- a/blflash/Cargo.toml +++ b/blflash/Cargo.toml @@ -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" diff --git a/blflash/src/async_serial/wasm.rs b/blflash/src/async_serial/wasm.rs index fd54bf3..10ddab9 100644 --- a/blflash/src/async_serial/wasm.rs +++ b/blflash/src/async_serial/wasm.rs @@ -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; - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} +use web_sys::window; type Item = io::Result>; +struct Settings<'a>(&'a mut binding::SerialOptions); +impl<'a> SerialPortSettings for Settings<'a> { + fn baud_rate(&self) -> Option { + todo!() + } + + fn char_size(&self) -> Option { + todo!() + } + + fn parity(&self) -> Option { + todo!() + } + + fn stop_bits(&self) -> Option { + todo!() + } + + fn flow_control(&self) -> Option { + 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>, - readable: IntoAsyncRead>, - writable: IntoSink<'static>, + readable: Option>>, + writable: Option>, port: binding::SerialPort, signals: binding::SerialOutputSignals, timeout: Duration, - writing: bool, + option: binding::SerialOptions, + // opened: Rc>, + // _on_connect: EventListener, + // _on_disconnect: EventListener, +} - open: Mutex, +fn get_pipe( + port: &JsValue, +) -> crate::Result<( + Option>>, + Option>, +)> { + 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::().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 { let window = window().ok_or(Error::WebError("Failed to get window"))?; - let navigator = window - .navigator() - .dyn_into::() - .expect("navigator"); + let navigator: JsValue = window.navigator().into(); + let navigator: binding::Navigator = navigator.into(); + let serial = navigator.serial(); - let port = Into::::into(serial.request_port()) + let port = JsFuture::from(serial.request_port()) .await - .expect("Failed to await request_port") - .dyn_into::() - .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::::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::::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> { - 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> { - if !self.writing { - self.writing = true; - self.writable - .start_send(Ok(Vec::from(buf))) - .map_err(|_| Into::::into(io::ErrorKind::BrokenPipe))? - } - let r = ready!(self.writable.poll_ready(cx)); - r.map_err(|_| Into::::into(io::ErrorKind::BrokenPipe))?; - self.writing = false; + let writable = self.writable.as_mut().unwrap(); + ready!(writable.poll_ready_unpin(cx)) + .map_err(|_| Into::::into(io::ErrorKind::BrokenPipe))?; + + let jsbuf: JsValue = Uint8Array::from(buf).into(); + writable + .start_send_unpin(jsbuf) + .map_err(|_| Into::::into(io::ErrorKind::BrokenPipe))?; Poll::Ready(Ok(buf.len())) } - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + ready!(self.writable.as_mut().unwrap().poll_flush_unpin(cx)) + .map_err(|_| Into::::into(io::ErrorKind::BrokenPipe)) + .into() } - fn poll_close(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + ready!(self.writable.as_mut().unwrap().poll_close_unpin(cx)) + .map_err(|_| Into::::into(io::ErrorKind::BrokenPipe)) + .into() } } diff --git a/blflash/src/connection.rs b/blflash/src/connection.rs index 0513772..2a5a548 100644 --- a/blflash/src/connection.rs +++ b/blflash/src/connection.rs @@ -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 } diff --git a/blflash/src/flasher.rs b/blflash/src/flasher.rs index c5d8ba6..28cac2b 100644 --- a/blflash/src/flasher.rs +++ b/blflash/src/flasher.rs @@ -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 = 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() { diff --git a/blflash/src/fs/native.rs b/blflash/src/fs/native.rs index ef294c1..90d7d5b 100644 --- a/blflash/src/fs/native.rs +++ b/blflash/src/fs/native.rs @@ -11,12 +11,12 @@ pub fn read>(path: P) -> io::Result> { pub use fs::File; -pub fn fs_read_file(path: PathBuf) -> Option> { +pub fn fs_read_file(_path: PathBuf) -> Option> { unimplemented!("only avaliable on wasm") } -pub fn fs_write_file(path: PathBuf, content: Vec) { +pub fn fs_write_file(_path: PathBuf, _content: Vec) { unimplemented!("only avaliable on wasm") } -pub fn fs_remove_file(path: PathBuf) { +pub fn fs_remove_file(_path: PathBuf) { unimplemented!("only avaliable on wasm") } diff --git a/blflash/src/fs/wasm.rs b/blflash/src/fs/wasm.rs index fda4ec7..b811cdd 100644 --- a/blflash/src/fs/wasm.rs +++ b/blflash/src/fs/wasm.rs @@ -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>(path: P) -> io::Result> { - 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> { diff --git a/libblflash/Cargo.toml b/libblflash/Cargo.toml index 3f4a247..629df9a 100644 --- a/libblflash/Cargo.toml +++ b/libblflash/Cargo.toml @@ -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" diff --git a/libblflash/index.html b/libblflash/index.html index bad2e4a..fffcc2f 100644 --- a/libblflash/index.html +++ b/libblflash/index.html @@ -6,5 +6,7 @@ + + diff --git a/libblflash/index.js b/libblflash/index.js index 59a64f3..2fa5eed 100644 --- a/libblflash/index.js +++ b/libblflash/index.js @@ -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) \ No newline at end of file diff --git a/libblflash/src/lib.rs b/libblflash/src/lib.rs index 30f5d46..0e94a1c 100644 --- a/libblflash/src/lib.rs +++ b/libblflash/src/lib.rs @@ -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;