diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..2deb356 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,18 @@ +[build] +target = "riscv32imc-esp-espidf" + +[target.riscv32imc-esp-espidf] +linker = "ldproxy" +runner = "espflash flash --monitor" # Select this runner for espflash v3.x.x +rustflags = [ "--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 + +[unstable] +build-std = ["std", "panic_abort"] + +[env] +MCU="esp32c3" +# Note: this variable is not used by the pio builder (`cargo build --features pio`) +ESP_IDF_VERSION = "v5.2.2" + +# Workaround for https://github.com/esp-rs/esp-idf-template/issues/174 +CRATE_CC_NO_DEFAULTS = "1" diff --git a/.github/workflows/rust_ci.yml b/.github/workflows/rust_ci.yml new file mode 100644 index 0000000..c161418 --- /dev/null +++ b/.github/workflows/rust_ci.yml @@ -0,0 +1,39 @@ +name: Continuous Integration + +on: + push: + paths-ignore: + - "**/README.md" + pull_request: + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + rust-checks: + name: Rust Checks + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + action: + - command: build + args: --release + - command: fmt + args: --all -- --check --color always + - command: clippy + args: --all-targets --all-features --workspace -- -D warnings + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Rust + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: nightly + components: rust-src + - name: Enable caching + uses: Swatinem/rust-cache@v2 + - name: Run command + run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73a638b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/.vscode +/.embuild +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9f3eea7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "esp" +version = "0.1.0" +authors = ["65787978"] +edition = "2021" +resolver = "2" +rust-version = "1.77" + +[[bin]] +name = "esp" +harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors + +[profile.release] +opt-level = "s" + +[profile.dev] +debug = true # Symbols are nice and they don't increase the size on Flash +opt-level = "z" + +[features] +default = ["std", "embassy", "esp-idf-svc/native"] + +pio = ["esp-idf-svc/pio"] +std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"] +alloc = ["esp-idf-svc/alloc"] +nightly = ["esp-idf-svc/nightly"] +experimental = ["esp-idf-svc/experimental", "esp-idf-svc/bt"] +embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf-svc/embassy-time-driver"] + +[dependencies] +log = { version = "0.4", default-features = false } +esp-idf-svc = { version = "0.49", default-features = false } + +[build-dependencies] +embuild = "0.32.0" \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..112ec3f --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + embuild::espidf::sysenv::output(); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..f70d225 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly" +components = ["rust-src"] diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..c25b89d --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,10 @@ +# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K) +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000 + +# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default). +# This allows to use 1 ms granularity for thread sleeps (10 ms by default). +#CONFIG_FREERTOS_HZ=1000 + +# Workaround for https://github.com/espressif/esp-idf/issues/7631 +#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n +#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ccb4986 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,61 @@ +/* + +___| 0 | 1 | 2 | 3 | 4 | 5 | ___| 0 | 1 | 2 | 3 | 4 | 5 | + 0 |_ESC_|__1__|__2__|__3__|__4__|__5__| 0 |__6__|__7__|__8__|__9__|__0__|__-__| + 1 |_TAB_|__Q__|__W__|__E__|__R__|__T__| 1 |__Y__|__U__|__I__|__O__|__P__|__{__| + 2 |_CAP_|__A__|__S__|__D__|__F__|__G__| 2 |__H__|__J__|__K__|__L__|__;__|__}__| + 3 |_SFT_|__Z__|__X__|__C__|__V__|__B__| 3 |__N__|__M__|__,__|__.__|__/__|__\__| + 4 |_____|_____|_____|_CTL_|_BSP_|_DEL_| 4 |_CTL_|_ENT_|_SPC_|_FUN_|_____|_____| + +*/ +use std::collections::HashMap; + +#[derive(Clone, Default, Debug)] +pub struct KeyboardLeftSide { + pub key: HashMap<(u8, u8), bool>, +} + +impl KeyboardLeftSide { + pub fn new() -> KeyboardLeftSide { + KeyboardLeftSide { + key: HashMap::new(), + } + } + + pub fn initialize_keys(&mut self) { + self.key.insert((0, 0), false); /* ESC */ + self.key.insert((0, 1), false); /* 1 */ + self.key.insert((0, 2), false); /* 2 */ + self.key.insert((0, 3), false); /* 3 */ + self.key.insert((0, 4), false); /* 4 */ + self.key.insert((0, 5), false); /* 5 */ + + self.key.insert((1, 0), false); /* TAB */ + self.key.insert((1, 1), false); /* Q */ + self.key.insert((1, 2), false); /* W */ + self.key.insert((1, 3), false); /* E */ + self.key.insert((1, 4), false); /* R */ + self.key.insert((1, 5), false); /* T */ + + self.key.insert((2, 0), false); /* CAP */ + self.key.insert((2, 1), false); /* A */ + self.key.insert((2, 2), false); /* S */ + self.key.insert((2, 3), false); /* D */ + self.key.insert((2, 4), false); /* F */ + self.key.insert((2, 5), false); /* G */ + + self.key.insert((3, 0), false); /* SFT */ + self.key.insert((3, 1), false); /* Z */ + self.key.insert((3, 2), false); /* X */ + self.key.insert((3, 3), false); /* C */ + self.key.insert((3, 4), false); /* V */ + self.key.insert((3, 5), false); /* B */ + + self.key.insert((4, 0), false); /* placeHolder */ + self.key.insert((4, 1), false); /* placeHolder */ + self.key.insert((4, 2), false); /* placeHolder */ + self.key.insert((4, 3), false); /* CTL */ + self.key.insert((4, 4), false); /* BSP */ + self.key.insert((4, 5), false); /* DEL */ + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c51f5b8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,48 @@ +use esp::KeyboardLeftSide; +use esp_idf_svc::{bt::*, log::EspLogger, sys}; +use std::{thread::sleep, time::Duration}; + +fn main() { + // It is necessary to call this function once. Otherwise some patches to the runtime + // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 + esp_idf_svc::sys::link_patches(); + + // Bind the log crate to the ESP Logging facilities + esp_idf_svc::log::EspLogger::initialize_default(); + + log::info!("Hello, world!"); + + /* Declare keys */ + let mut keyboard_left_side = KeyboardLeftSide::new(); + keyboard_left_side.initialize_keys(); + + let mut has_key_been_pressed_this_cycle = false; + let mut previous_key_pressed: (u8, u8) = (0, 0); + + loop { + /* Implement hardware matrix scan */ + let key_pressed_matrix: Option<(u8, u8)> = Some((0, 0)); + + match key_pressed_matrix { + Some(key_pressed) => { + if let Some(key) = keyboard_left_side.key.get_mut(&key_pressed) { + *key = true; + previous_key_pressed = key_pressed; + has_key_been_pressed_this_cycle = true; + log::info!("Key pressed: {:?}", key_pressed); + } + } + + /* If a key is not pressed, set the previous key to false */ + None => { + if has_key_been_pressed_this_cycle { + keyboard_left_side.key.insert(previous_key_pressed, false); + has_key_been_pressed_this_cycle = false; + } + } + } + + /* Sleep for 20 milliseconds before fetching the matrix */ + sleep(Duration::from_millis(20)); + } +}