From 0566093ee8c6681fa1cecc8cf55e3cf75bd6248e Mon Sep 17 00:00:00 2001 From: Koichi Akabe Date: Tue, 29 Mar 2022 13:24:10 +0900 Subject: [PATCH] Add examples directory (#27) * Add examples directory * fix --- .gitignore | 3 +- Cargo.toml | 2 +- examples/embedded_device/.cargo/config.toml | 40 ++++++++++++ examples/embedded_device/Cargo.toml | 24 +++++++ examples/embedded_device/README.md | 27 ++++++++ examples/embedded_device/build.rs | 26 ++++++++ examples/embedded_device/memory.x | 4 ++ examples/embedded_device/openocd.cfg | 5 ++ examples/embedded_device/openocd.gdb | 16 +++++ examples/embedded_device/src/main.rs | 65 +++++++++++++++++++ {vaporetto_wasm => examples/wasm}/Cargo.toml | 6 +- {vaporetto_wasm => examples/wasm}/README.md | 0 .../wasm}/build_portable_js.py | 0 {vaporetto_wasm => examples/wasm}/src/lib.rs | 0 .../wasm}/www/index.css | 0 .../wasm}/www/index.html | 0 .../wasm}/www/index.js | 0 17 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 examples/embedded_device/.cargo/config.toml create mode 100644 examples/embedded_device/Cargo.toml create mode 100644 examples/embedded_device/README.md create mode 100644 examples/embedded_device/build.rs create mode 100644 examples/embedded_device/memory.x create mode 100644 examples/embedded_device/openocd.cfg create mode 100644 examples/embedded_device/openocd.gdb create mode 100644 examples/embedded_device/src/main.rs rename {vaporetto_wasm => examples/wasm}/Cargo.toml (66%) rename {vaporetto_wasm => examples/wasm}/README.md (100%) rename {vaporetto_wasm => examples/wasm}/build_portable_js.py (100%) rename {vaporetto_wasm => examples/wasm}/src/lib.rs (100%) rename {vaporetto_wasm => examples/wasm}/www/index.css (100%) rename {vaporetto_wasm => examples/wasm}/www/index.html (100%) rename {vaporetto_wasm => examples/wasm}/www/index.js (100%) diff --git a/.gitignore b/.gitignore index ea8c4bf7..fa8d85ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target +Cargo.lock +target diff --git a/Cargo.toml b/Cargo.toml index 0a60007c..98843a08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,5 +12,5 @@ members = [ ] exclude = [ - "vaporetto_wasm", + "examples", ] diff --git a/examples/embedded_device/.cargo/config.toml b/examples/embedded_device/.cargo/config.toml new file mode 100644 index 00000000..b1b4f13d --- /dev/null +++ b/examples/embedded_device/.cargo/config.toml @@ -0,0 +1,40 @@ +[target.thumbv7m-none-eabi] +# uncomment this to make `cargo run` execute programs on QEMU +# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# uncomment ONE of these three option to make `cargo run` start a GDB session +# which option to pick depends on your system +runner = "arm-none-eabi-gdb -q -x openocd.gdb" +# runner = "gdb-multiarch -q -x openocd.gdb" +# runner = "gdb -q -x openocd.gdb" + +rustflags = [ + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", + + # LLD (shipped with the Rust toolchain) is used as the default linker + "-C", "link-arg=-Tlink.x", + + # if you run into problems with LLD switch to the GNU linker by commenting out + # this line + # "-C", "linker=arm-none-eabi-ld", + + # if you need to link to pre-compiled C libraries provided by a C toolchain + # use GCC as the linker by commenting out both lines above and then + # uncommenting the three lines below + # "-C", "linker=arm-none-eabi-gcc", + # "-C", "link-arg=-Wl,-Tlink.x", + # "-C", "link-arg=-nostartfiles", +] + +[build] +# Pick ONE of these compilation targets +# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ +# target = "thumbv7m-none-eabi" # Cortex-M3 +# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) +# target = "thumbv8m.base-none-eabi" # Cortex-M23 +# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU) +# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU) diff --git a/examples/embedded_device/Cargo.toml b/examples/embedded_device/Cargo.toml new file mode 100644 index 00000000..d23415dd --- /dev/null +++ b/examples/embedded_device/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "vaporetto_embedded_device" +edition = "2021" +version = "0.1.0" + +[dependencies] +cortex-m = "0.6.0" +cortex-m-rt = "0.6.10" +cortex-m-semihosting = "0.3.3" +panic-halt = "0.2.0" + +vaporetto = { path = "../../vaporetto", default-features = false } +vaporetto_rules = { path = "../../vaporetto_rules" } + +alloc-cortex-m = "0.4.0" + +[build-dependencies] +vaporetto = { path = "../../vaporetto", default-features = false } +ruzstd = "0.2.4" # MIT + +[profile.release] +codegen-units = 1 +debug = true +lto = true diff --git a/examples/embedded_device/README.md b/examples/embedded_device/README.md new file mode 100644 index 00000000..ff965c57 --- /dev/null +++ b/examples/embedded_device/README.md @@ -0,0 +1,27 @@ +# Embedded device example of Vaporetto + +## How to build? + +This example is written for embedded devices. +Install an appropriate compiler following [the documentation](https://docs.rust-embedded.org/book/) beforehand. + +We comfirmed the behaviour on [STM32F3DISCOVERY](http://www.st.com/en/evaluation-tools/stm32f3discovery.html). +This device has just 256K Flash and 40K RAM, so we recommend using a very tiny model trained with a low +`--cost` option and without a dictionary. + +The model file is read and embedded on the building phase, so you need to specify the model file using `VAPORETTO_MODEL_PATH` as follows: +```sh +VAPORETTO_MODEL_PATH=$PWD/model.zst cargo +nightly build --release +``` + +This example automatically launches GDB on the `run` command, so you can quickly run this example using two terminals. +First, run the following command to connect to the device: +```sh +openocd +``` +Then, run the following command in another terminal: +```sh +VAPORETTO_MODEL_PATH=$PWD/model.zst cargo +nightly run --release +``` + +If it works correctly, tokenized results will be shown on the first terminal. diff --git a/examples/embedded_device/build.rs b/examples/embedded_device/build.rs new file mode 100644 index 00000000..43e276d8 --- /dev/null +++ b/examples/embedded_device/build.rs @@ -0,0 +1,26 @@ +use std::env; +use std::fs::File; +use std::io::{BufWriter, Cursor, Read, Write}; +use std::path::PathBuf; + +use vaporetto::{Model, Predictor}; + +fn main() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); + + let mut f = Cursor::new(include_bytes!(env!("VAPORETTO_MODEL_PATH"))); + let mut decoder = ruzstd::StreamingDecoder::new(&mut f).unwrap(); + let mut buff = vec![]; + decoder.read_to_end(&mut buff).unwrap(); + let (model, _) = Model::read_slice(&buff).unwrap(); + let predictor = Predictor::new(model, false).unwrap(); + let mut buf = BufWriter::new(File::create(out.join("predictor.bin")).unwrap()); + let model_data = predictor.serialize_to_vec().unwrap(); + buf.write_all(&model_data).unwrap(); +} diff --git a/examples/embedded_device/memory.x b/examples/embedded_device/memory.x new file mode 100644 index 00000000..cfe1082a --- /dev/null +++ b/examples/embedded_device/memory.x @@ -0,0 +1,4 @@ +MEMORY { + FLASH : ORIGIN = 0x08000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 40K +} diff --git a/examples/embedded_device/openocd.cfg b/examples/embedded_device/openocd.cfg new file mode 100644 index 00000000..5aec560b --- /dev/null +++ b/examples/embedded_device/openocd.cfg @@ -0,0 +1,5 @@ +# Sample OpenOCD configuration for the STM32F3DISCOVERY development board + +source [find interface/stlink.cfg] + +source [find target/stm32f3x.cfg] diff --git a/examples/embedded_device/openocd.gdb b/examples/embedded_device/openocd.gdb new file mode 100644 index 00000000..3dd3c812 --- /dev/null +++ b/examples/embedded_device/openocd.gdb @@ -0,0 +1,16 @@ +target extended-remote :3333 + +# print demangled symbols +set print asm-demangle on + +# detect unhandled exceptions, hard faults and panics +break DefaultHandler +break HardFault +break rust_begin_unwind + +monitor arm semihosting enable + +load + +# start the process but immediately halt the processor +stepi diff --git a/examples/embedded_device/src/main.rs b/examples/embedded_device/src/main.rs new file mode 100644 index 00000000..8bf76c02 --- /dev/null +++ b/examples/embedded_device/src/main.rs @@ -0,0 +1,65 @@ +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +extern crate alloc; + +// core crate +use core::alloc::Layout; + +// alloc crate +use alloc::vec::Vec; + +// devices +use alloc_cortex_m::CortexMHeap; +use cortex_m::asm; +use cortex_m_rt::entry; +use cortex_m_semihosting::hprintln; + +// other crates +use vaporetto::{Predictor, Sentence, CharacterType}; +use vaporetto_rules::{ + sentence_filters::KyteaWsConstFilter, + SentenceFilter, +}; + +// panic behaviour +use panic_halt as _; + +#[global_allocator] +static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); + +const HEAP_SIZE: usize = 40 * 1024; // in bytes + +#[entry] +fn main() -> ! { + unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) } + + let predictor_data = include_bytes!(concat!(env!("OUT_DIR"), "/predictor.bin")); + let (predictor, _) = unsafe { Predictor::deserialize_from_slice_unchecked(predictor_data) }.unwrap(); + + let docs = &[ + "🚤VaporettoはSTM32F303VCT6(FLASH:256KiB,RAM:40KiB)などの小さなデバイスでも動作します", + ]; + + let wsconst_d_filter = KyteaWsConstFilter::new(CharacterType::Digit); + + loop { + for &text in docs { + hprintln!("\x1b[32mINPUT:\x1b[m {:?}", text).unwrap(); + let s = Sentence::from_raw(text).unwrap(); + let s = predictor.predict(s); + let s = wsconst_d_filter.filter(s); + let v = s.to_tokenized_vec().unwrap().iter().map(|t| t.surface).collect::>(); + hprintln!("\x1b[31mOUTPUT:\x1b[m {:?}", v).unwrap(); + } + } +} + +#[alloc_error_handler] +fn alloc_error(_layout: Layout) -> ! { + hprintln!("alloc error").unwrap(); + asm::bkpt(); + + loop {} +} diff --git a/vaporetto_wasm/Cargo.toml b/examples/wasm/Cargo.toml similarity index 66% rename from vaporetto_wasm/Cargo.toml rename to examples/wasm/Cargo.toml index 99a7afad..e3115010 100644 --- a/vaporetto_wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "vaporetto_wasm" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib", "rlib"] [dependencies] js-sys = "0.3.52" # MIT or Apache-2.0 -vaporetto = { path = "../vaporetto" } # MIT or Apache-2.0 -vaporetto_rules = { path = "../vaporetto_rules" } # MIT or Apache-2.0 +vaporetto = { path = "../../vaporetto" } # MIT or Apache-2.0 +vaporetto_rules = { path = "../../vaporetto_rules" } # MIT or Apache-2.0 wasm-bindgen = "0.2.75" # MIT or Apache-2.0 ruzstd = "0.2.4" # MIT wee_alloc = "0.4.5" # MPL-2.0 diff --git a/vaporetto_wasm/README.md b/examples/wasm/README.md similarity index 100% rename from vaporetto_wasm/README.md rename to examples/wasm/README.md diff --git a/vaporetto_wasm/build_portable_js.py b/examples/wasm/build_portable_js.py similarity index 100% rename from vaporetto_wasm/build_portable_js.py rename to examples/wasm/build_portable_js.py diff --git a/vaporetto_wasm/src/lib.rs b/examples/wasm/src/lib.rs similarity index 100% rename from vaporetto_wasm/src/lib.rs rename to examples/wasm/src/lib.rs diff --git a/vaporetto_wasm/www/index.css b/examples/wasm/www/index.css similarity index 100% rename from vaporetto_wasm/www/index.css rename to examples/wasm/www/index.css diff --git a/vaporetto_wasm/www/index.html b/examples/wasm/www/index.html similarity index 100% rename from vaporetto_wasm/www/index.html rename to examples/wasm/www/index.html diff --git a/vaporetto_wasm/www/index.js b/examples/wasm/www/index.js similarity index 100% rename from vaporetto_wasm/www/index.js rename to examples/wasm/www/index.js