summaryrefslogtreecommitdiff
path: root/firmware/rust
diff options
context:
space:
mode:
authorMarc Poulhiès <dkm@kataplop.net>2022-07-07 21:51:38 +0200
committerMarc Poulhiès <dkm@kataplop.net>2022-07-22 21:06:23 +0200
commit3c71e3a2a3af39d579c2649fddf0c8ba835bfa01 (patch)
treef383b855123ae2fb66ebb3537d36153388418ca8 /firmware/rust
parent972760b3e68156c72129b833d5624d4e6f60619b (diff)
Move rust firmware in subdir
... for the upcoming Ada one.
Diffstat (limited to 'firmware/rust')
-rw-r--r--firmware/rust/.cargo/config12
-rw-r--r--firmware/rust/Cargo.lock573
-rw-r--r--firmware/rust/Cargo.toml29
-rw-r--r--firmware/rust/Embed.toml21
-rw-r--r--firmware/rust/memory.x6
-rw-r--r--firmware/rust/src/main.rs551
6 files changed, 1192 insertions, 0 deletions
diff --git a/firmware/rust/.cargo/config b/firmware/rust/.cargo/config
new file mode 100644
index 0000000..96e1aaa
--- /dev/null
+++ b/firmware/rust/.cargo/config
@@ -0,0 +1,12 @@
+[target.thumbv6m-none-eabi]
+
+# 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 = ["-C", "link-arg=-Tlink.x"]
+
+[build]
+target = "thumbv6m-none-eabi"
diff --git a/firmware/rust/Cargo.lock b/firmware/rust/Cargo.lock
new file mode 100644
index 0000000..0cda0e0
--- /dev/null
+++ b/firmware/rust/Cargo.lock
@@ -0,0 +1,573 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aligned"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c19796bd8d477f1a9d4ac2465b464a8b1359474f06a96bb3cda650b4fca309bf"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "arraydeque"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0ffd3d69bd89910509a5d31d1f1353f38ccffdd116dd0099bbd6627f7bd8ad8"
+
+[[package]]
+name = "as-slice"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
+dependencies = [
+ "generic-array 0.12.4",
+ "generic-array 0.13.3",
+ "generic-array 0.14.4",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bare-metal"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
+dependencies = [
+ "rustc_version 0.2.3",
+]
+
+[[package]]
+name = "bare-metal"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
+
+[[package]]
+name = "bitfield"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
+
+[[package]]
+name = "bytemuck"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cast"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374"
+dependencies = [
+ "rustc_version 0.3.3",
+]
+
+[[package]]
+name = "cortex-m"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9075300b07c6a56263b9b582c214d0ff037b00d45ec9fde1cc711490c56f1bb9"
+dependencies = [
+ "aligned",
+ "bare-metal 0.2.5",
+ "bitfield",
+ "cortex-m 0.7.2",
+ "volatile-register",
+]
+
+[[package]]
+name = "cortex-m"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b"
+dependencies = [
+ "bare-metal 0.2.5",
+ "bitfield",
+ "embedded-hal",
+ "volatile-register",
+]
+
+[[package]]
+name = "cortex-m-rt"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "980c9d0233a909f355ed297ef122f257942de5e0a2cb1c39f60684b65bcb90fb"
+dependencies = [
+ "cortex-m-rt-macros",
+ "r0",
+]
+
+[[package]]
+name = "cortex-m-rt-macros"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4717562afbba06e760d34451919f5c3bf3ac15c7bb897e8b04862a7428378647"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cortex-m-rtic"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa43f63284b363ac64f9ce5221a0f593b54f73258aba8e1a88c1feed8efdb664"
+dependencies = [
+ "cortex-m 0.6.7",
+ "cortex-m-rt",
+ "cortex-m-rtic-macros",
+ "heapless 0.6.1",
+ "rtic-core",
+ "version_check",
+]
+
+[[package]]
+name = "cortex-m-rtic-macros"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a1a6a4c9550373038c0e21a78d44d529bd697c25bbf6b8004bddc6e63b119c7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rtic-syntax",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "embedded-hal"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db184d3fa27bc7a2344250394c0264144dfe0bc81a4401801dcb964b8dd172ad"
+dependencies = [
+ "nb 0.1.3",
+ "void",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "hash32"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+
+[[package]]
+name = "heapless"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1"
+dependencies = [
+ "as-slice",
+ "generic-array 0.13.3",
+ "hash32",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "heapless"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
+dependencies = [
+ "as-slice",
+ "generic-array 0.14.4",
+ "hash32",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "keyberon"
+version = "0.2.0"
+source = "git+https://github.com/TeXiToi/keyberon#cbd75317a5521b94995128ccec83e658045fa05d"
+dependencies = [
+ "arraydeque",
+ "either",
+ "embedded-hal",
+ "generic-array 0.14.4",
+ "heapless 0.5.6",
+ "keyberon-macros",
+ "usb-device",
+]
+
+[[package]]
+name = "keyberon-macros"
+version = "0.1.0"
+source = "git+https://github.com/TeXiToi/keyberon#cbd75317a5521b94995128ccec83e658045fa05d"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "nb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
+dependencies = [
+ "nb 1.0.0",
+]
+
+[[package]]
+name = "nb"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
+
+[[package]]
+name = "panic-halt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
+
+[[package]]
+name = "pest"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
+dependencies = [
+ "ucd-trie",
+]
+
+[[package]]
+name = "pouetpouet"
+version = "0.1.0"
+dependencies = [
+ "cortex-m 0.6.7",
+ "cortex-m-rt",
+ "cortex-m-rtic",
+ "embedded-hal",
+ "generic-array 0.13.3",
+ "keyberon",
+ "nb 1.0.0",
+ "panic-halt",
+ "smart-leds",
+ "stm32f0xx-hal",
+ "usb-device",
+ "ws2812-spi",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r0"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
+
+[[package]]
+name = "rgb"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fddb3b23626145d1776addfc307e1a1851f60ef6ca64f376bcb889697144cf0"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "rtic-core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef"
+
+[[package]]
+name = "rtic-syntax"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8152fcaa845720d61e6cc570548b89144c2c307f18a480bbd97e55e9f6eeff04"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver 0.9.0",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
+dependencies = [
+ "semver 0.11.0",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser 0.7.0",
+]
+
+[[package]]
+name = "semver"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
+dependencies = [
+ "semver-parser 0.10.2",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "semver-parser"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
+dependencies = [
+ "pest",
+]
+
+[[package]]
+name = "smart-leds"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38dd45fa275f70b4110eac5f5182611ad384f88bb22b68b9a9c3cafd7015290b"
+dependencies = [
+ "smart-leds-trait",
+]
+
+[[package]]
+name = "smart-leds-trait"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebf6d833fa93f16a1c1874e62c2aebe8567e5bdd436d59bf543ed258b6f7a8e3"
+dependencies = [
+ "rgb",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "stm32-usbd"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70d13eca735cae37df697f599777b000cc0ee924df8452f2b4bfaa6798ab0338"
+dependencies = [
+ "cortex-m 0.6.7",
+ "usb-device",
+ "vcell",
+]
+
+[[package]]
+name = "stm32f0"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "401a6a390b26fff7c8166049cac102511d557fd5204f5d4795bfb00301b00730"
+dependencies = [
+ "bare-metal 0.2.5",
+ "cortex-m 0.6.7",
+ "cortex-m-rt",
+ "vcell",
+]
+
+[[package]]
+name = "stm32f0xx-hal"
+version = "0.17.1"
+source = "git+https://github.com/dkm/stm32f0xx-hal/#34d2ee36e2112aa162665c1fdc3ab5bba99df2b4"
+dependencies = [
+ "bare-metal 1.0.0",
+ "cast",
+ "cortex-m 0.6.7",
+ "embedded-hal",
+ "nb 1.0.0",
+ "stm32-usbd",
+ "stm32f0",
+ "void",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "typenum"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "usb-device"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6be90410d4772074ea49525e2e753b65920b94b57eee21a6ef7b6a6fe6296245"
+
+[[package]]
+name = "vcell"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
+
+[[package]]
+name = "version_check"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "volatile-register"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
+dependencies = [
+ "vcell",
+]
+
+[[package]]
+name = "ws2812-spi"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6c2ba0d6c0ea9c117487411e93dc5dacaafc2c17698677a03d1c67901d4c70a"
+dependencies = [
+ "embedded-hal",
+ "nb 0.1.3",
+ "smart-leds-trait",
+]
diff --git a/firmware/rust/Cargo.toml b/firmware/rust/Cargo.toml
new file mode 100644
index 0000000..54f44cc
--- /dev/null
+++ b/firmware/rust/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "pouetpouet"
+version = "0.1.0"
+authors = ["Marc Poulhiès <dkm@kataplop.net>", "Guillaume Pinot <texitoi@texitoi.eu>"]
+edition = "2018"
+
+[dependencies]
+stm32f0xx-hal = { git = "https://github.com/dkm/stm32f0xx-hal/", features = ["rt", "stm32f072", "stm32-usbd"] }
+##stm32f0xx-hal = { version = "0.17.0", features = ["rt", "stm32f072", "stm32-usbd"] }
+cortex-m = "0.7"
+cortex-m-rt = { version = "0.7", features = ["device"] }
+panic-halt = "0.2"
+keyberon = { git = "https://github.com/TeXiToi/keyberon" }
+cortex-m-rtic = { version = "0.5", default-features = false, features = ["cortex-m-7"] }
+embedded-hal = "0.2"
+usb-device = "0.2"
+nb = "1.0"
+ws2812-spi = "0.4"
+smart-leds = "0.3"
+
+[profile.release]
+lto = true
+incremental = false
+opt-level = "z"
+debug = true
+
+[features]
+default = [ ]
+testmode = [ ]
diff --git a/firmware/rust/Embed.toml b/firmware/rust/Embed.toml
new file mode 100644
index 0000000..80179ac
--- /dev/null
+++ b/firmware/rust/Embed.toml
@@ -0,0 +1,21 @@
+[default.probe]
+protocol = "Swd"
+
+[default.flashing]
+enabled = true
+
+[default.reset]
+enabled = true
+# Whether or not the target should be halted after reset.
+halt_afterwards = false
+
+[default.general]
+chip = "STM32L072CBTX"
+log_level = "WARN"
+
+[default.rtt]
+enabled = false
+
+[default.gdb]
+enabled = true
+gdb_connection_string = "127.0.0.1:1337"
diff --git a/firmware/rust/memory.x b/firmware/rust/memory.x
new file mode 100644
index 0000000..5153cb7
--- /dev/null
+++ b/firmware/rust/memory.x
@@ -0,0 +1,6 @@
+/* Linker script for the STM32F103C8T6 */
+MEMORY
+{
+ FLASH : ORIGIN = 0x08000000, LENGTH = 128K
+ RAM : ORIGIN = 0x20000000, LENGTH = 16K
+}
diff --git a/firmware/rust/src/main.rs b/firmware/rust/src/main.rs
new file mode 100644
index 0000000..e9b544c
--- /dev/null
+++ b/firmware/rust/src/main.rs
@@ -0,0 +1,551 @@
+#![no_main]
+#![no_std]
+
+// set the panic handler
+use panic_halt as _;
+
+use core::convert::Infallible;
+
+use keyberon::layout::Layout;
+use keyberon::matrix::{Matrix, PressedKeys};
+use rtic::app;
+use stm32f0xx_hal as hal;
+use usb_device::bus::UsbBusAllocator;
+use usb_device::class::UsbClass as _;
+
+extern crate smart_leds;
+extern crate ws2812_spi;
+use smart_leds::{brightness, colors, SmartLedsWrite, RGB8};
+
+use ws2812_spi as ws2812;
+
+use hal::delay::Delay;
+use hal::gpio::{gpioa, Alternate, Input, Output, Pin, PullUp, PushPull, AF0};
+use hal::prelude::*;
+
+use embedded_hal::spi::FullDuplex;
+
+use hal::usb;
+use hal::{
+ spi::{EightBit, Mode, Phase, Polarity},
+ stm32, timers,
+};
+
+use keyberon::action::Action;
+use keyberon::debounce::Debouncer;
+use keyberon::key_code::KbHidReport;
+use keyberon::key_code::KeyCode;
+
+type Spi = hal::spi::Spi<
+ stm32::SPI1,
+ gpioa::PA5<Alternate<AF0>>,
+ gpioa::PA6<Alternate<AF0>>,
+ gpioa::PA7<Alternate<AF0>>,
+ EightBit,
+>;
+
+type UsbClass = keyberon::Class<'static, usb::UsbBusType, Leds<Spi>>;
+
+type UsbDevice = usb_device::device::UsbDevice<'static, usb::UsbBusType>;
+
+trait ResultExt<T> {
+ fn get(self) -> T;
+}
+impl<T> ResultExt<T> for Result<T, Infallible> {
+ fn get(self) -> T {
+ match self {
+ Ok(v) => v,
+ Err(e) => match e {},
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum CustomActions {
+ LightUp,
+ LightDown,
+
+ ModeCycle,
+ ColorCycle,
+ FreqUp,
+ FreqDown,
+}
+
+#[cfg(not(feature = "testmode"))]
+#[rustfmt::skip]
+
+pub static LAYERS: keyberon::layout::Layers<CustomActions> = keyberon::layout::layout! {
+ {
+ [Kb1 Kb2 Kb3 Kb4 Kb5 Grave Kb6 Kb7 Kb8 Kb9 Kb0 Minus]
+ [Q W E R T Tab Y U I O P LBracket]
+ [A S D F G BSpace H J K L SColon Quote]
+ [Z X C V B Enter N M Comma Dot Slash Bslash ]
+ [LCtrl (1) LGui LShift LAlt Space RAlt RBracket Equal Delete RShift RCtrl]
+ }
+ {
+ [F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12]
+ [SysReq NumLock t t t Escape Insert PgUp PgDown VolUp VolDown Mute ]
+ [t t t t t t Home Up End t t t ]
+ [NonUsBslash {Action::Custom(CustomActions::ColorCycle)} {Action::Custom(CustomActions::FreqUp)} {Action::Custom(CustomActions::FreqDown)} t t Left Down Right t t PgUp ]
+ [{Action::Custom(CustomActions::LightUp)} t {Action::Custom(CustomActions::LightDown)} {Action::Custom(CustomActions::ModeCycle)} t t t t t t t PgDown]
+ }
+};
+
+#[cfg(feature = "testmode")]
+#[rustfmt::skip]
+pub static LAYERS: keyberon::layout::Layers<CustomActions> = keyberon::layout::layout! {
+ {
+ [A, A, A, A, A, A, A, A, A, A, A, A],
+ [A, A, A, A, A, A, A, A, A, A, A, A],
+ [A, A, A, A, A, A, A, A, A, A, A, A],
+ [A, A, A, A, A, A, A, A, A, A, A, A],
+ [A, A, A, A, A, A, A, A, A, A, A, A],
+ }
+};
+
+pub struct Leds<SPI> {
+ ws: ws2812::Ws2812<SPI>,
+ leds: [RGB8; 10],
+}
+
+impl<SPI, E> keyberon::keyboard::Leds for Leds<SPI>
+where
+ SPI: FullDuplex<u8, Error = E>,
+{
+ fn caps_lock(&mut self, status: bool) {
+ if status {
+ self.leds[0] = colors::BLUE;
+ } else {
+ self.leds[0] = colors::BLACK;
+ }
+ if self.ws.write(brightness(self.leds.iter().cloned(), 10)).is_err() {
+ panic!();
+ }
+ }
+
+ fn num_lock(&mut self, status: bool) {
+ if status {
+ self.leds[1] = colors::GREEN;
+ } else {
+ self.leds[1] = colors::BLACK;
+ }
+ if self.ws.write(brightness(self.leds.iter().cloned(), 10)).is_err() {
+ panic!();
+ }
+ }
+
+ fn compose(&mut self, status: bool) {
+ if status {
+ self.leds[3] = colors::VIOLET;
+ } else {
+ self.leds[3] = colors::BLACK;
+ }
+ if self.ws.write(brightness(self.leds.iter().cloned(), 10)).is_err() {
+ panic!();
+ }
+
+ }
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum BacklightMode {
+ Off,
+ Solid(RGB8),
+ Circling(RGB8, usize, usize, usize, bool),
+ Breath(RGB8, usize, usize, bool),
+}
+
+pub struct Backlight {
+ mode: BacklightMode,
+ brightness: u8,
+}
+
+trait ColorSeq {
+ fn next_color(&self) -> RGB8;
+}
+
+const COLORS_SEQ: [RGB8; 5] = [
+ colors::RED,
+ colors::GREEN,
+ colors::BLUE,
+ colors::VIOLET,
+ colors::YELLOW,
+];
+
+impl ColorSeq for RGB8 {
+ fn next_color(&self) -> RGB8 {
+ let mut next = false;
+
+ for c in &COLORS_SEQ {
+ if next {
+ return *c;
+ }
+
+ if *self == *c {
+ next = true;
+ }
+ }
+
+ COLORS_SEQ[0]
+ }
+}
+
+impl Backlight {
+ pub fn next_mode(&mut self) {
+ self.mode = match self.mode {
+ BacklightMode::Off => BacklightMode::Solid(colors::RED),
+ BacklightMode::Solid(_) => BacklightMode::Circling(colors::RED, 100, 0, 0, true),
+ BacklightMode::Circling(_, _, _, _, _) => {
+ BacklightMode::Breath(colors::RED, 10, 0, true)
+ }
+ BacklightMode::Breath(_, _, _, _) => BacklightMode::Off,
+ }
+ }
+
+ pub fn change_freq(&mut self, up: bool) {
+ self.mode = match self.mode {
+ BacklightMode::Breath(c, tstep, step, dir) => {
+ let tstep = if up {
+ if tstep - 10 > 10 {
+ tstep - 10
+ } else {
+ 10
+ }
+ } else if tstep + 10 < 1000 {
+ tstep + 10
+ } else {
+ 1000
+ };
+ BacklightMode::Breath(c, tstep, step, dir)
+ }
+ BacklightMode::Circling(c, tstep, step, i, dir) => {
+ let tstep = if up {
+ if tstep - 10 > 10 {
+ tstep - 10
+ } else {
+ 10
+ }
+ } else if tstep + 10 < 1000 {
+ tstep + 10
+ } else {
+ 1000
+ };
+ BacklightMode::Circling(c, tstep, step, i, dir)
+ }
+ any => any,
+ }
+ }
+
+ pub fn next_color(&mut self) {
+ self.mode = match self.mode {
+ BacklightMode::Solid(c) => BacklightMode::Solid(c.next_color()),
+ BacklightMode::Breath(c, tstep, step, dir) => {
+ BacklightMode::Breath(c.next_color(), tstep, step, dir)
+ }
+ BacklightMode::Circling(c, ts, s, i, dir) => {
+ BacklightMode::Circling(c.next_color(), ts, s, i, dir)
+ }
+ any => any,
+ }
+ }
+
+ pub fn refresh_leds(&mut self, leds: &mut Leds<Spi>) {
+ self.mode = match self.mode {
+ BacklightMode::Off => {
+ for l in leds.leds[4..].iter_mut() {
+ *l = colors::BLACK;
+ }
+ BacklightMode::Off
+ }
+
+ BacklightMode::Solid(c) => {
+ for l in leds.leds[4..].iter_mut() {
+ *l = c;
+ }
+ BacklightMode::Solid(c)
+ }
+
+ BacklightMode::Breath(c, tstep, step, dir) => {
+ let mut step = step + 1;
+ let mut new_dir = dir;
+
+ if step >= tstep {
+ step = 0;
+
+ for l in leds.leds[4..].iter_mut() {
+ *l = c;
+ }
+
+ if dir {
+ if self.brightness == 100 {
+ self.brightness -= 1;
+ new_dir = false;
+ }
+ self.brightness += 1;
+ } else {
+ if self.brightness == 5 {
+ self.brightness += 1;
+ new_dir = true;
+ }
+ self.brightness -= 1;
+ }
+ }
+
+ BacklightMode::Breath(c, tstep, step, new_dir)
+ }
+
+ BacklightMode::Circling(c, tstep, step, index, dir) => {
+ let mut new_dir = dir;
+ let mut new_index = index;
+
+ let mut step = step + 1;
+
+ if step >= tstep {
+ step = 0;
+
+ if new_index == 0 && !dir {
+ new_index = 0;
+ new_dir = true;
+ } else if new_index == 6 && dir {
+ new_index = 6;
+ new_dir = false;
+ } else {
+ new_index = if dir { index + 1 } else { index - 1 };
+ }
+ }
+
+ for (i, l) in leds.leds[4..].iter_mut().enumerate() {
+ let ni = if new_index == 0 { 5 } else { new_index - 1 };
+ if i == ni {
+ *l = c;
+ } else {
+ *l = colors::BLACK;
+ }
+ }
+ BacklightMode::Circling(c, tstep, step, new_index as usize, new_dir)
+ }
+ };
+
+ if leds.ws
+ .write(brightness(leds.leds.iter().cloned(), self.brightness)).is_err() {
+ panic!();
+ }
+ }
+}
+
+#[app(device = crate::hal::pac, peripherals = true)]
+const APP: () = {
+ struct Resources {
+ usb_dev: UsbDevice,
+ usb_class: UsbClass,
+ matrix: Matrix<Pin<Input<PullUp>>, Pin<Output<PushPull>>, 12, 5>,
+ debouncer: Debouncer<PressedKeys<12, 5>>,
+ layout: Layout<CustomActions>,
+ timer: timers::Timer<stm32::TIM3>,
+
+ backlight: Backlight,
+ }
+
+ #[init]
+ fn init(mut c: init::Context) -> init::LateResources {
+ static mut USB_BUS: Option<UsbBusAllocator<usb::UsbBusType>> = None;
+ let mut rcc = c
+ .device
+ .RCC
+ .configure()
+ .hsi48()
+ .enable_crs(c.device.CRS)
+ .sysclk(48.mhz())
+ .pclk(24.mhz())
+ .freeze(&mut c.device.FLASH);
+
+ let gpioa = c.device.GPIOA.split(&mut rcc);
+ let gpiob = c.device.GPIOB.split(&mut rcc);
+
+ let usb = usb::Peripheral {
+ usb: c.device.USB,
+ pin_dm: gpioa.pa11,
+ pin_dp: gpioa.pa12,
+ };
+ *USB_BUS = Some(usb::UsbBusType::new(usb));
+ let usb_bus = USB_BUS.as_ref().unwrap();
+
+ // Handling of ws2812 leds
+
+ let pa5 = gpioa.pa5; // sck
+ let pa6 = gpioa.pa6; // miso
+ let pa7 = gpioa.pa7; // mosi
+
+ // Configure pins for SPI
+ let (sck, miso, mosi) = cortex_m::interrupt::free(move |cs| {
+ (
+ pa5.into_alternate_af0(cs),
+ pa6.into_alternate_af0(cs),
+ pa7.into_alternate_af0(cs),
+ )
+ });
+
+ const MODE: Mode = Mode {
+ polarity: Polarity::IdleHigh,
+ phase: Phase::CaptureOnSecondTransition,
+ };
+ let spi = Spi::spi1(
+ c.device.SPI1,
+ (sck, miso, mosi),
+ MODE,
+ 3_000_000.hz(),
+ &mut rcc,
+ );
+
+ // ws2812
+ let mut ws = ws2812::Ws2812::new(spi);
+
+ // Do a simple smooth blink at start
+ let mut delay = Delay::new(c.core.SYST, &rcc);
+ let tmpleds = [colors::GREEN; 10];
+ for i in (0..100).chain((0..100).rev()) {
+ ws.write(brightness(tmpleds.iter().cloned(), i)).unwrap();
+ delay.delay_ms(5u8);
+ }
+
+ let mut leds = Leds {
+ ws,
+ leds: [colors::BLACK; 10],
+ };
+
+ leds.ws.write(leds.leds.iter().cloned()).unwrap();
+
+ let usb_class = keyberon::new_class(usb_bus, leds);
+ let usb_dev = keyberon::new_device(usb_bus);
+
+ let mut timer = timers::Timer::tim3(c.device.TIM3, 1.khz(), &mut rcc);
+ timer.listen(timers::Event::TimeOut);
+
+ let pa15 = gpioa.pa15;
+ let pa1 = gpioa.pa1;
+ let pa0 = gpioa.pa0;
+
+ let matrix = cortex_m::interrupt::free(move |cs| {
+ Matrix::new(
+ [
+ pa0.into_pull_up_input(cs).downgrade(),
+ pa1.into_pull_up_input(cs).downgrade(),
+ gpiob.pb13.into_pull_up_input(cs).downgrade(),
+ gpiob.pb12.into_pull_up_input(cs).downgrade(),
+ gpiob.pb14.into_pull_up_input(cs).downgrade(),
+ gpiob.pb15.into_pull_up_input(cs).downgrade(),
+ pa15.into_pull_up_input(cs).downgrade(),
+ gpiob.pb3.into_pull_up_input(cs).downgrade(),
+ gpiob.pb4.into_pull_up_input(cs).downgrade(),
+ gpiob.pb5.into_pull_up_input(cs).downgrade(),
+ gpiob.pb8.into_pull_up_input(cs).downgrade(),
+ gpiob.pb9.into_pull_up_input(cs).downgrade(),
+ ],
+ [
+ gpiob.pb0.into_push_pull_output(cs).downgrade(),
+ gpiob.pb1.into_push_pull_output(cs).downgrade(),
+ gpiob.pb2.into_push_pull_output(cs).downgrade(),
+ gpiob.pb10.into_push_pull_output(cs).downgrade(),
+ gpiob.pb11.into_push_pull_output(cs).downgrade(),
+
+ ],
+ )});
+
+ init::LateResources {
+ usb_dev,
+ usb_class,
+ timer,
+ debouncer: Debouncer::new(PressedKeys::default(), PressedKeys::default(), 5),
+ matrix: matrix.get(),
+ layout: Layout::new(LAYERS),
+
+ backlight: Backlight {
+ mode: BacklightMode::Off,
+ brightness: 8,
+ },
+ }
+ }
+
+ #[task(binds = USB, priority = 4, resources = [usb_dev, usb_class])]
+ fn usb_rx(c: usb_rx::Context) {
+ if c.resources.usb_dev.poll(&mut [c.resources.usb_class]) {
+ c.resources.usb_class.poll();
+ }
+ }
+
+ #[task(
+ binds = TIM3,
+ priority = 2,
+ resources = [matrix, debouncer, timer, layout, usb_class, backlight],
+ )]
+ fn tick(c: tick::Context) {
+ c.resources.timer.wait().ok();
+
+ for event in c
+ .resources
+ .debouncer
+ .events(c.resources.matrix.get().unwrap())
+ {
+ c.resources.layout.event(event);
+ }
+ let mut usb_class = c.resources.usb_class;
+ let backlight = c.resources.backlight;
+
+ match c.resources.layout.tick() {
+ keyberon::layout::CustomEvent::Release(CustomActions::LightUp) => {
+ let bl_val = &mut backlight.brightness;
+ *bl_val = if *bl_val == 100 { 100 } else { *bl_val + 1 };
+ usb_class.lock(|k| {
+ let leds = k.device_mut().leds_mut();
+ if leds.ws
+ .write(brightness(leds.leds.iter().cloned(), *bl_val)).is_err() {
+ panic!();
+ }
+ });
+ }
+ keyberon::layout::CustomEvent::Release(CustomActions::LightDown) => {
+ let bl_val = &mut backlight.brightness;
+ *bl_val = if *bl_val == 0 { 0 } else { *bl_val - 1 };
+ usb_class.lock(|k| {
+ let leds = k.device_mut().leds_mut();
+ if leds.ws
+ .write(brightness(leds.leds.iter().cloned(), *bl_val)).is_err() {
+ panic!();
+ }
+ });
+ }
+ keyberon::layout::CustomEvent::Release(CustomActions::ColorCycle) => {
+ backlight.next_color();
+ }
+ keyberon::layout::CustomEvent::Release(CustomActions::ModeCycle) => {
+ backlight.next_mode();
+ }
+ keyberon::layout::CustomEvent::Release(CustomActions::FreqUp) => {
+ backlight.change_freq(true);
+ }
+ keyberon::layout::CustomEvent::Release(CustomActions::FreqDown) => {
+ backlight.change_freq(false);
+ }
+ _ => (),
+ }
+
+ usb_class.lock(|k| {
+ backlight.refresh_leds(k.device_mut().leds_mut());
+ });
+
+ c.resources.layout.tick();
+ send_report(c.resources.layout.keycodes(), &mut usb_class);
+ }
+
+ extern "C" {
+ fn CEC_CAN();
+ }
+};
+
+fn send_report(iter: impl Iterator<Item = KeyCode>, usb_class: &mut resources::usb_class<'_>) {
+ use rtic::Mutex;
+ let report: KbHidReport = iter.collect();
+ if usb_class.lock(|k| k.device_mut().set_keyboard_report(report.clone())) {
+ while let Ok(0) = usb_class.lock(|k| k.write(report.as_bytes())) {}
+ }
+}