feat: add fs, console_error_panic_hook

This commit is contained in:
spacelin 2021-01-08 16:58:20 +08:00
parent e587a44f08
commit d0fc64fe9f
17 changed files with 212 additions and 17 deletions

21
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"command": "cargo watch -x check",
"problemMatcher": "$rustc-watch",
"group": "build",
"label": "watch native",
"isBackground": true
},
{
"type": "shell",
"command": "cargo watch -x 'check --target wasm32-unknown-unknown'",
"problemMatcher": "$rustc-watch",
"group": "build",
"label": "watch wasm",
"isBackground": true
}
]
}

1
Cargo.lock generated
View File

@ -97,6 +97,7 @@ dependencies = [
"js-sys",
"log",
"main_error",
"once_cell",
"parse_int",
"paw",
"serde",

View File

@ -4,3 +4,6 @@ members = [
"blflash",
]
default-members = ["blflash"]
exclude = [
"libblflash",
]

View File

@ -38,6 +38,7 @@ futures = "0.3"
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
once_cell = "1.5"
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3"

View File

@ -16,7 +16,7 @@ pub struct AsyncSerial(Box<dyn SerialPort>);
impl AsyncSerial {
pub async fn open(port: &str) -> crate::Result<Self> {
Ok(AsyncSerial(Box::new(serial::open(port))))
Ok(AsyncSerial(Box::new(serial::open(port)?)))
}
// pub fn new(serial: impl SerialPort + 'static) -> Self {
// Self(Box::new(serial))

View File

@ -2,8 +2,8 @@
use crate::Error;
use futures::io::{AsyncRead, AsyncWrite};
use js_sys::Reflect;
use serial::{Result, SerialPortSettings};
use js_sys::{Promise, Reflect};
use serial::SerialPortSettings;
use std::{
io,
pin::Pin,
@ -14,29 +14,40 @@ use std::{
use wasm_bindgen::prelude::*;
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>;
}
pub struct AsyncSerial(JsValue);
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 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"));
return Err(Error::WebError("serial is not supported on your browser. make sure you have enabled chrome://flags/#enable-experimental-web-platform-features"));
}
let serial: Serial = serial.into();
// Reflect::get(serial.as_ref(), "requestPort".into()).expect("Failed to get requestPort");
todo!()
}
pub async fn set_rts(&mut self, level: bool) -> Result<()> {
pub async fn set_rts(&mut self, level: bool) -> serial::Result<()> {
todo!()
}
pub async fn set_dtr(&mut self, level: bool) -> Result<()> {
pub async fn set_dtr(&mut self, level: bool) -> serial::Result<()> {
todo!()
}
pub async fn sleep(&self, duration: Duration) {
sleep(duration)
}
pub async fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
pub async fn set_timeout(&mut self, timeout: Duration) -> serial::Result<()> {
todo!()
}
pub async fn timeout(&self) -> Duration {
@ -44,8 +55,8 @@ impl AsyncSerial {
}
pub async fn reconfigure(
&mut self,
setup: &dyn Fn(&mut dyn SerialPortSettings) -> Result<()>,
) -> Result<()> {
setup: &dyn Fn(&mut dyn SerialPortSettings) -> serial::Result<()>,
) -> serial::Result<()> {
todo!()
}
}

8
blflash/src/fs/mod.rs Normal file
View File

@ -0,0 +1,8 @@
mod native;
mod wasm;
#[cfg(target_arch = "wasm32")]
pub use wasm::*;
#[cfg(not(target_arch = "wasm32"))]
pub use native::*;

22
blflash/src/fs/native.rs Normal file
View File

@ -0,0 +1,22 @@
#![cfg(not(target_arch = "wasm32"))]
use std::{
fs, io,
path::{Path, PathBuf},
};
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
fs::read(path)
}
pub use fs::File;
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>) {
unimplemented!("only avaliable on wasm")
}
pub fn fs_remove_file(path: PathBuf) {
unimplemented!("only avaliable on wasm")
}

58
blflash/src/fs/wasm.rs Normal file
View File

@ -0,0 +1,58 @@
#![cfg(target_arch = "wasm32")]
use once_cell::sync::Lazy;
use std::{
collections::HashMap,
fs,
io::{self, Cursor, Write},
path::{Path, PathBuf},
sync::Mutex,
};
static FS: Lazy<Mutex<HashMap<PathBuf, Vec<u8>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub struct File {
path: PathBuf,
buf: Option<Cursor<Vec<u8>>>,
}
impl File {
pub fn create(path: PathBuf) -> io::Result<Self> {
Ok(Self {
path,
buf: Some(Cursor::new(Vec::new())),
})
}
}
impl Write for File {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.as_mut().unwrap().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.buf.as_mut().unwrap().flush()
}
}
impl Drop for File {
fn drop(&mut self) {
FS.lock()
.unwrap()
.insert(self.path.clone(), self.buf.take().unwrap().into_inner());
}
}
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
fs::read(path)
}
pub fn fs_read_file(path: PathBuf) -> Option<Vec<u8>> {
FS.lock().unwrap().get(&path).map(Clone::clone)
}
pub fn fs_write_file(path: PathBuf, content: Vec<u8>) {
FS.lock().unwrap().insert(path, content);
}
pub fn fs_remove_file(path: PathBuf) {
FS.lock().unwrap().remove(&path);
}

View File

@ -7,6 +7,7 @@ pub mod image;
use async_serial::AsyncSerial;
use serde::Deserialize;
mod async_serial;
pub mod fs;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub use error::{Error, RomError};
@ -20,12 +21,9 @@ use crate::{
elf::{FirmwareImage, RomSegment},
image::BootHeaderCfgFile,
};
use fs::{read, File};
use serial::{BaudRate, CharSize, FlowControl, Parity, SerialPortSettings, StopBits};
use std::{
borrow::Cow,
fs::{read, File},
path::PathBuf,
};
use std::{borrow::Cow, path::PathBuf};
use structopt::StructOpt;
#[derive(StructOpt, Deserialize)]
@ -41,7 +39,7 @@ pub struct Connection {
pub initial_baud_rate: usize,
}
#[derive(StructOpt, Deserialize)]
#[derive(StructOpt, Deserialize, Default)]
pub struct Boot2Opt {
/// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml
#[structopt(long, parse(from_os_str))]
@ -54,26 +52,31 @@ pub struct Boot2Opt {
pub dtb: Option<PathBuf>,
/// Without boot2
#[structopt(short, long)]
#[serde(default)]
pub without_boot2: bool,
}
#[derive(StructOpt, Deserialize)]
pub struct FlashOpt {
#[structopt(flatten)]
#[serde(flatten)]
pub conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
pub image: PathBuf,
/// Don't skip if hash matches
#[structopt(short, long)]
#[serde(default)]
pub force: bool,
#[structopt(flatten)]
#[serde(default, flatten)]
pub boot: Boot2Opt,
}
#[derive(StructOpt, Deserialize)]
pub struct CheckOpt {
#[structopt(flatten)]
#[serde(flatten)]
pub conn: Connection,
/// Bin file
#[structopt(parse(from_os_str))]
@ -85,6 +88,7 @@ pub struct CheckOpt {
#[derive(StructOpt, Deserialize)]
pub struct DumpOpt {
#[structopt(flatten)]
#[serde(flatten)]
pub conn: Connection,
/// Output file
#[structopt(parse(from_os_str))]

2
libblflash/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

View File

@ -13,3 +13,4 @@ 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"
console_error_panic_hook = "0.1"

9
libblflash/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>blflash web</title>
</head>
<body>
<script type="module" src="index.js"></script>
</body>
</html>

18
libblflash/index.js Normal file
View File

@ -0,0 +1,18 @@
import init, { dump, FS } from './pkg/libblflash.js'
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)
}
main()

View File

@ -1,5 +1,7 @@
use blflash::{Boot2Opt, Connection, Error, FlashOpt};
use blflash::{Boot2Opt, Connection, Error, FlashOpt, DumpOpt, fs};
use wasm_bindgen::prelude::*;
use std::path::PathBuf;
mod utils;
fn map_result(r: Result<(), Error>) -> JsValue {
match r {
@ -10,7 +12,38 @@ fn map_result(r: Result<(), Error>) -> JsValue {
#[wasm_bindgen]
pub async fn flash(opt: JsValue) -> JsValue {
utils::set_panic_hook();
let opt: FlashOpt = opt.into_serde().unwrap();
let result = blflash::flash(opt).await;
map_result(result)
}
#[wasm_bindgen]
pub async fn dump(opt: JsValue) -> JsValue {
utils::set_panic_hook();
let opt: DumpOpt = opt.into_serde().unwrap();
let result = blflash::dump(opt).await;
map_result(result)
}
struct FS;
#[wasm_bindgen]
impl FS {
#[wasm_bindgen]
pub fn read_file(path: String) -> Option<Vec<u8>> {
fs::fs_read_file(PathBuf::from(path))
}
#[wasm_bindgen]
pub fn write_file(path: String, content: Vec<u8>) {
fs::fs_write_file(PathBuf::from(path), content)
}
#[wasm_bindgen]
pub fn remove_file(path: String) {
fs::fs_remove_file(PathBuf::from(path))
}
}

3
libblflash/src/utils.rs Normal file
View File

@ -0,0 +1,3 @@
pub fn set_panic_hook() {
console_error_panic_hook::set_once();
}