mirror of
https://github.com/spacemeowx2/blflash.git
synced 2024-10-04 13:49:51 +00:00
feat: add fs, console_error_panic_hook
This commit is contained in:
parent
e587a44f08
commit
d0fc64fe9f
21
.vscode/tasks.json
vendored
Normal file
21
.vscode/tasks.json
vendored
Normal 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
1
Cargo.lock
generated
@ -97,6 +97,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"main_error",
|
||||
"once_cell",
|
||||
"parse_int",
|
||||
"paw",
|
||||
"serde",
|
||||
|
@ -4,3 +4,6 @@ members = [
|
||||
"blflash",
|
||||
]
|
||||
default-members = ["blflash"]
|
||||
exclude = [
|
||||
"libblflash",
|
||||
]
|
||||
|
@ -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"
|
||||
|
@ -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))
|
||||
|
@ -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
8
blflash/src/fs/mod.rs
Normal 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
22
blflash/src/fs/native.rs
Normal 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
58
blflash/src/fs/wasm.rs
Normal 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);
|
||||
}
|
@ -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
2
libblflash/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
@ -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
9
libblflash/index.html
Normal 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
18
libblflash/index.js
Normal 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()
|
@ -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
3
libblflash/src/utils.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub fn set_panic_hook() {
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
Loading…
Reference in New Issue
Block a user