moving standalone mode to alsa rust direct binding crate & moving led_driver to a specific package

This commit is contained in:
2025-08-04 16:37:40 +00:00
parent 66c4aeffa6
commit 57ace1383b
52 changed files with 859 additions and 577 deletions
Generated
+234 -424
View File
@@ -141,7 +141,47 @@ dependencies = [
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
"windows-targets",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bindgen"
version = "0.72.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
dependencies = [
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
@@ -162,6 +202,12 @@ version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "bytemuck"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -184,10 +230,13 @@ dependencies = [
]
[[package]]
name = "cesu8"
version = "1.1.0"
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
@@ -215,6 +264,17 @@ dependencies = [
"windows-link",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
@@ -222,13 +282,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "combine"
version = "4.6.7"
name = "colored"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"bytes",
"memchr",
"lazy_static",
"windows-sys 0.59.0",
]
[[package]]
@@ -237,46 +297,6 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "coreaudio-rs"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17"
dependencies = [
"bitflags 1.3.2",
"libc",
"objc2-audio-toolbox",
"objc2-core-audio",
"objc2-core-audio-types",
"objc2-core-foundation",
]
[[package]]
name = "cpal"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd307f43cc2a697e2d1f8bc7a1d824b5269e052209e28883e5bc04d095aaa3f"
dependencies = [
"alsa",
"coreaudio-rs",
"dasp_sample",
"jni",
"js-sys",
"libc",
"mach2",
"ndk",
"ndk-context",
"num-derive",
"num-traits",
"objc2-audio-toolbox",
"objc2-core-audio",
"objc2-core-audio-types",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows",
]
[[package]]
name = "crossbeam"
version = "0.8.4"
@@ -344,21 +364,21 @@ dependencies = [
]
[[package]]
name = "dasp_sample"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
[[package]]
name = "dispatch2"
name = "drawille"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
checksum = "e64e461c3f1e69d99372620640b3fd5f0309eeda2e26e4af69f6760c0e1df845"
dependencies = [
"bitflags 2.9.1",
"objc2",
"colored",
"fnv",
]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "env_filter"
version = "0.1.3"
@@ -383,10 +403,19 @@ dependencies = [
]
[[package]]
name = "equivalent"
version = "1.0.2"
name = "float-cmp"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8"
dependencies = [
"num-traits",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "gimli"
@@ -395,10 +424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "hashbrown"
version = "0.15.4"
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "iana-time-zone"
@@ -412,7 +441,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.2",
"windows-core",
]
[[package]]
@@ -424,22 +453,21 @@ dependencies = [
"cc",
]
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "jiff"
version = "0.2.14"
@@ -464,28 +492,6 @@ dependencies = [
"syn",
]
[[package]]
name = "jni"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
dependencies = [
"cesu8",
"cfg-if",
"combine",
"jni-sys",
"log",
"thiserror",
"walkdir",
"windows-sys 0.45.0",
]
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.77"
@@ -496,25 +502,58 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "led_driver"
version = "0.1.0"
dependencies = [
"bindgen 0.72.0",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libloading"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "libm"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "lightsabre_backend"
version = "0.1.0"
dependencies = [
"alsa",
"artnet_protocol",
"cpal",
"bindgen 0.71.1",
"crossbeam",
"ctrlc",
"env_logger",
"led_driver",
"log",
"nix 0.30.1",
"rpi-mailbox",
"rppal",
"spectrum-analyzer",
"textplots",
]
[[package]]
@@ -533,15 +572,6 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "mach2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.7.4"
@@ -557,6 +587,23 @@ dependencies = [
"autocfg",
]
[[package]]
name = "microfft"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b6673eb0cc536241d6734c2ca45abfdbf90e9e7791c66a36a7ba3c315b76cf"
dependencies = [
"cfg-if",
"num-complex",
"static_assertions",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.8"
@@ -577,35 +624,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "ndk"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
dependencies = [
"bitflags 2.9.1",
"jni-sys",
"log",
"ndk-sys",
"num_enum",
"thiserror",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]]
name = "ndk-sys"
version = "0.6.0+11769913"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
dependencies = [
"jni-sys",
]
[[package]]
name = "nix"
version = "0.26.4"
@@ -632,14 +650,22 @@ dependencies = [
]
[[package]]
name = "num-derive"
version = "0.4.2"
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"proc-macro2",
"quote",
"syn",
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
@@ -651,100 +677,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_enum"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
dependencies = [
"num_enum_derive",
"rustversion",
]
[[package]]
name = "num_enum_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "objc2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
dependencies = [
"objc2-encode",
]
[[package]]
name = "objc2-audio-toolbox"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
dependencies = [
"bitflags 2.9.1",
"libc",
"objc2",
"objc2-core-audio",
"objc2-core-audio-types",
"objc2-core-foundation",
"objc2-foundation",
]
[[package]]
name = "objc2-core-audio"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82"
dependencies = [
"dispatch2",
"objc2",
"objc2-core-audio-types",
"objc2-core-foundation",
]
[[package]]
name = "objc2-core-audio-types"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
dependencies = [
"bitflags 2.9.1",
"objc2",
]
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags 2.9.1",
"dispatch2",
"objc2",
]
[[package]]
name = "objc2-encode"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
[[package]]
name = "objc2-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
"objc2",
]
[[package]]
name = "object"
version = "0.36.7"
@@ -786,9 +718,15 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.6",
"windows-targets",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pin-project-lite"
version = "0.2.16"
@@ -823,12 +761,13 @@ dependencies = [
]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
name = "prettyplease"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55"
dependencies = [
"toml_edit",
"proc-macro2",
"syn",
]
[[package]]
@@ -887,6 +826,15 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rgb"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
dependencies = [
"bytemuck",
]
[[package]]
name = "rpi-mailbox"
version = "0.3.0"
@@ -922,21 +870,18 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -994,6 +939,24 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "spectrum-analyzer"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f5353405212be77e7f9e95aa77934f0aafb0f80c586571680b9c20ce5bae758"
dependencies = [
"float-cmp",
"libm",
"microfft",
"paste",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.101"
@@ -1005,6 +968,16 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "textplots"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f7657a0066c9f9663659db0665319adff8b0943305fc73eddf1010e5a2072b1"
dependencies = [
"drawille",
"rgb",
]
[[package]]
name = "thiserror"
version = "1.0.69"
@@ -1054,23 +1027,6 @@ dependencies = [
"syn",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
@@ -1083,16 +1039,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@@ -1125,19 +1071,6 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
@@ -1170,45 +1103,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
"windows-core 0.54.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.61.2"
@@ -1218,7 +1112,7 @@ dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result 0.3.4",
"windows-result",
"windows-strings",
]
@@ -1250,15 +1144,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.4"
@@ -1277,22 +1162,13 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.6",
"windows-targets",
]
[[package]]
@@ -1301,22 +1177,7 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows-targets",
]
[[package]]
@@ -1325,46 +1186,28 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -1377,59 +1220,26 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
dependencies = [
"memchr",
]
+5 -1
View File
@@ -1,3 +1,7 @@
[workspace]
resolver = "3"
members = ["lightsabre_backend", "rust_sandbox"]
members = [
"lightsabre_backend/led_driver",
"lightsabre_backend/system",
"rust_sandbox",
]
+2 -2
View File
@@ -1,6 +1,6 @@
# LightSabre
LightSabre is a project designed to control WS281x RGB LEDs using the Secondary Memory Interface (SMI) of a Raspberry Pi, tailored for scenographic and lighting applications.
LightSabre is a project designed to control WS281x RGB LEDs using the Secondary Memory Interface (SMI) of a Raspberry Pi, tailored for scenography and lighting applications.
## Features
@@ -42,8 +42,8 @@ What about Realtime ?
`sudo raspi-config`
See. `nmcli`
`nmcli c up preconfigured`
`nmcli c up preconfigured`
#### Rust
-4
View File
@@ -1,4 +0,0 @@
fn main() {
println!("cargo::rustc-link-search=/workspaces/LightSabre/lightsabre_backend/drivers/lib/");
// println!("cargo:rustc-link-search=/workspaces/LightSabre/lightsabre_backend/drivers/lib");
}
+9
View File
@@ -0,0 +1,9 @@
[package]
name = "led_driver"
version = "0.1.0"
edition = "2024"
[dependencies]
[build-dependencies]
bindgen = "0.72.0"
+26
View File
@@ -0,0 +1,26 @@
use std::{env, path::PathBuf};
fn main() {
println!("cargo::rustc-link-search=/workspaces/LightSabre/lightsabre_backend/led_driver/lib");
// Tell cargo to tell rustc to link the RPiLedBars_drivers and logc libraries.
println!("cargo:rustc-link-lib=RpiLedBars_drivers_8ch");
println!("cargo:rustc-link-lib=logc");
// The bindgen::Builder is the main entry point to bindgen, and lets you build up options for the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate bindings for.
.header("lib/wrapper.h")
// Tell cargo to invalidate the built crate whenever any of the included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
+13
View File
@@ -0,0 +1,13 @@
#! /usr/bin/env bash
dest_path=${0%/*}/lib
source_host=${1:-raspberrypi.local}
scp \
raspberrypi.local:RpiLedBars/backend/.build/src/drivers/libRpiLedBars_drivers.a \
${dest_path}/bin/libRpiLedBars_drivers_8ch.a
scp \
raspberrypi.local:RpiLedBars/backend/.build/_deps/logc-build/liblogc.a \
${dest_path}/bin/liblogc.a
@@ -0,0 +1,34 @@
#include "include/log.h"
#include "src/leddriver/rpi_leddriver.h"
#include "src/common.h"
#define CHAN_MAXLEDS 60 // Maximum number of LEDs per channel
#define LED_NCHANS 8 // Number of LED channels (8 or 16)
#define TX_TEST 0 // If non-zero, use dummy Tx data
#define LED_NBITS 24 // Number of data bits per LED
#define LED_PREBITS 4 // Number of zero bits before LED data
#define LED_POSTBITS 4 // Number of zero bits after LED data
#define BIT_NPULSES 3 // Number of O/P pulses per LED bit
// Length of data for 1 row (1 LED on each channel)
#define LED_DLEN (LED_NBITS * BIT_NPULSES)
// Transmit data type, 8 or 16 bits
#if LED_NCHANS > 8
typedef uint16_t TXDATA_T;
#else
typedef uint8_t TXDATA_T;
#endif
// Ofset into Tx data buffer, given LED number in chan
#define LED_TX_OSET(n) (LED_PREBITS + (LED_DLEN * (n)))
// Size of data buffers & NV memory, given number of LEDs per chan
#define TX_BUFF_LEN(n) (LED_TX_OSET(n) + LED_POSTBITS)
#define TX_BUFF_SIZE(n) (TX_BUFF_LEN(n) * sizeof(TXDATA_T))
#define VC_MEM_SIZE (PAGE_SIZE + TX_BUFF_SIZE(CHAN_MAXLEDS))
extern TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)];
extern TXDATA_T *txdata;
extern MEM_MAP vc_mem;
+159
View File
@@ -0,0 +1,159 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
pub struct LedDriver {
led_per_strip_count: usize,
strip_count: usize,
}
// Offset into Tx data buffer, given LED number in chan
macro_rules! LED_TX_OSET {
($n:expr) => {
LED_PREBITS + (LED_DLEN * $n)
};
}
impl LedDriver {
const LED_NCHANS: usize = LED_NCHANS as usize; // Number of channels (strips)
const TX_TEST: usize = TX_TEST as usize; // If non-zero, use dummy Tx data
const LED_NBITS: usize = LED_NBITS as usize; // Number of data bits per LED
pub const LED_PREBITS: usize = LED_PREBITS as usize; // Number of zero bits before LED data
const LED_POSTBITS: usize = LED_POSTBITS as usize; // Number of zero bits after LED data
const BIT_NPULSES: usize = BIT_NPULSES as usize; // Number of O/P pulses per LED bit
// Length of data for 1 row (1 LED on each channel)
pub const LED_DLEN: usize = Self::LED_NBITS * Self::BIT_NPULSES;
pub fn new(led_per_strip_count: usize, strip_count: usize) -> LedDriver {
unsafe { leddriver_setup() };
LedDriver {
led_per_strip_count,
strip_count,
}
}
pub fn get_led_per_strip_count(&self) -> usize {
self.led_per_strip_count
}
pub fn get_strip_count(&self) -> usize {
self.strip_count
}
pub fn set_color(&self, rgb: u32, index: usize) {
unsafe { set_color(rgb, index as i32) };
}
pub fn set_color_till_led(&self, color: u32, led_num: usize) {
let led_num = led_num.min(self.get_led_per_strip_count());
// Set color for all strips
for led_index in 0..=led_num {
self.direct_set_color(color, led_index);
}
for led in led_num + 1..self.get_led_per_strip_count() {
self.direct_set_color(0x000000, led);
}
}
pub fn direct_set_color(&self, rgb: u32, index: usize) {
let mut mask = 0_u32;
let mut offset = LED_TX_OSET!(index as u32) as usize;
// For each bit of the 24-bit RGB values..
for n in 0..Self::LED_NBITS {
let tx_data = unsafe { &mut tx_buffer[offset..offset + Self::BIT_NPULSES] };
// Mask to convert RGB to GRB, M.S bit first
Self::compute_mask(&mut mask, n);
// 1st byte or word is a high pulse on all lines
tx_data[0] = 0xff;
// 2nd has high or low bits from data
tx_data[1] = if rgb & mask != 0_u32 { 0xff } else { 0x00 };
// 3rd is a low pulse
tx_data[2] = 0x00;
offset += Self::BIT_NPULSES;
}
}
pub fn set_led_color(&self, rgb: u32, led_index: usize, strip_index: usize) {
let mut mask = 0_u32;
let mut offset = LED_TX_OSET!(led_index as u32) as usize;
let strip_mask = !(0b1_u8 << strip_index); // Mask to clear the led bit of desired strip
// For each bit of the 24-bit RGB values..
for n in 0..Self::LED_NBITS {
let tx_data = unsafe { &mut tx_buffer[offset..offset + Self::BIT_NPULSES] };
// Mask to convert RGB to GRB, M.S bit first
Self::compute_mask(&mut mask, n);
// 1st byte or word is a high pulse on all lines
tx_data[0] = 0xff;
// 2nd has high or low bits from data
tx_data[1] = tx_data[1] & strip_mask
| if rgb & mask != 0_u32 {
0b1 << strip_index
} else {
0x00
};
// 3rd is a low pulse
tx_data[2] = 0x00;
offset += Self::BIT_NPULSES;
}
}
pub fn set_strip_index_colors(&self, rgb: [u32; Self::LED_NCHANS], led_index: usize) {
let mut mask = 0_u32;
let mut offset = LED_TX_OSET!(led_index as u32) as usize;
// For each bit of the 24-bit RGB values..
for n in 0..Self::LED_NBITS {
let tx_data = unsafe { &mut tx_buffer[offset..offset + Self::BIT_NPULSES] };
// Mask to convert RGB to GRB, M.S bit first
Self::compute_mask(&mut mask, n);
// 1st byte or word is a high pulse on all lines
tx_data[offset] = 0xff;
tx_data[offset + 1] = 0x00; // Clear the strip bits first
// 2nd has high or low bits from data
for (strip_index, rgb) in rgb.iter().enumerate() {
if rgb & mask != 0_u32 {
// Set the bit for this strip
tx_data[offset + 1] |= 0b1 << strip_index;
}
}
// 3rd is a low pulse
tx_data[offset + 2] = 0x00;
offset += Self::BIT_NPULSES;
}
}
pub fn refresh(&self) {
unsafe { leddriver_refresh() };
}
// pub fn color_hsv(&self, hue: u16, sat: u8, val: u8) -> u32 {
// unsafe { ColorHSV(hue, sat, val) }
// }
fn compute_mask(mask: &mut u32, n: usize) {
*mask = if n == 0 {
0x800000
} else if n == 8 {
0x8000
} else if n == 16 {
0x80
} else {
*mask >> 1
}
}
}
impl Drop for LedDriver {
fn drop(&mut self) {
unsafe { leddriver_close() };
}
}
@@ -1,59 +0,0 @@
use cpal::traits::{DeviceTrait, HostTrait};
use rppal::gpio::Gpio;
use crate::cputasks::modes::AppModeHandler;
use crate::devices::led_driver::LedDriver;
pub struct StandaloneMode {
_i2s_mic_pin: Vec<rppal::gpio::IoPin>,
}
impl StandaloneMode {
const I2S_PINS: [u8; 3] = [20, 19, 18];
pub fn new() -> Self {
let gpio = Gpio::new().expect("Failed to initialize GPIO");
let i2s_mic_pin: Vec<rppal::gpio::IoPin> = Self::I2S_PINS
.iter()
.map(|&pin| {
gpio.get(pin)
.expect(&format!("Failed to get GPIO pin {}", pin))
.into_io(rppal::gpio::Mode::Alt0)
})
.collect();
StandaloneMode {
_i2s_mic_pin: i2s_mic_pin,
}
}
}
impl AppModeHandler for StandaloneMode {
fn enter(&mut self) {
log::debug!("[Standalone] Entering Standalone Mode");
let host = cpal::default_host();
// default_input_device()
host.devices()
.unwrap()
.for_each(|device| log::info!("{:?}", device.name()));
if let Some(device) = host
.input_devices()
.unwrap()
.find(|device| device.name() == Ok(String::from("snd_rpi_googlevoicehat_soundcar")))
{
log::info!("Found record device {:?}", device.name());
log::info!("Default config : {:?}", device.default_input_config())
} else {
log::error!("Record device not found");
}
}
fn run(&mut self, _: &mut LedDriver) {
log::trace!("[Standalone] Running...");
}
fn exit(&mut self) {
log::debug!("[Standalone] Exiting Standalone Mode");
}
}
@@ -1,61 +0,0 @@
#[link(name = "logc", kind = "static")]
unsafe extern "C" {
unsafe fn log_log(level: u32, file: *const u8, line: i32, fmt: *const u8, ...);
}
#[link(name = "RpiLedBars_drivers", kind = "static")]
unsafe extern "C" {
unsafe fn leddriver_setup();
unsafe fn leddriver_close();
unsafe fn set_color(rgb: u32, index: usize);
// unsafe fn rgb_txdata(rgbs: *mut u32, index: usize);
unsafe fn leddriver_refresh();
// unsafe fn ColorHSV(hue: u16, sat: u8, val: u8) -> u32;
}
pub struct LedDriver {
led_per_strips: usize,
}
impl LedDriver {
pub fn new(led_per_strips: usize) -> LedDriver {
unsafe {
log_log(
0,
"coucou".as_bytes().as_ptr(),
13,
"hello".as_bytes().as_ptr(),
)
};
unsafe { leddriver_setup() };
LedDriver { led_per_strips }
}
pub fn get_led_per_strips(&self) -> usize {
self.led_per_strips
}
pub fn set_color(&self, rgb: u32, index: usize) {
unsafe { set_color(rgb, index) };
}
pub fn refresh(&self) {
unsafe { leddriver_refresh() };
}
// pub fn color_hsv(&self, hue: u16, sat: u8, val: u8) -> u32 {
// unsafe { ColorHSV(hue, sat, val) }
// }
}
impl Drop for LedDriver {
fn drop(&mut self) {
unsafe { leddriver_close() };
}
}
@@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2024"
[dependencies]
alsa = "0.9.1"
artnet_protocol = "0.4.3"
cpal = "0.16.0"
crossbeam = "0.8.4"
ctrlc = { version = "3.4.7", features = ["termination"] }
env_logger = "0.11.8"
@@ -13,6 +13,12 @@ log = "0.4.27"
nix = "0.30.1"
rpi-mailbox = "0.3.0"
rppal = "0.22.1"
spectrum-analyzer = "1.7.0"
textplots = "0.8.7"
led_driver = { path = "../led_driver" }
[build-dependencies]
bindgen = "0.71.0"
[features]
default = ["rpizero2", "16channel"]
@@ -14,9 +14,9 @@ use crate::channels::Message;
use crate::devices::led_driver::LedDriver;
pub trait AppModeHandler {
fn enter(&mut self);
fn run(&mut self, led_driver: &mut LedDriver);
fn exit(&mut self);
fn enter(&mut self) -> Result<(), Box<dyn std::error::Error>>;
fn run(&mut self, led_driver: &mut LedDriver) -> Result<(), Box<dyn std::error::Error>>;
fn exit(&mut self) -> Result<(), Box<dyn std::error::Error>>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -20,7 +20,7 @@ impl ArtNetMode {
}
impl AppModeHandler for ArtNetMode {
fn enter(&mut self) {
fn enter(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[ArtNet] Entering ArtNet Mode");
let mut attempts = 0_usize;
@@ -41,9 +41,10 @@ impl AppModeHandler for ArtNetMode {
socket.set_nonblocking(true).unwrap();
self.socket = Some(socket);
log::debug!("[ArtNet] ArtNet Mode initialized and listening on port 6454");
Ok(())
}
fn run(&mut self, led_driver: &mut LedDriver) {
fn run(&mut self, led_driver: &mut LedDriver) -> Result<(), Box<dyn std::error::Error>> {
log::trace!("[ArtNet] Running...");
let buf = &mut [0; 530];
let mut is_first_data_frame = true;
@@ -109,8 +110,9 @@ impl AppModeHandler for ArtNetMode {
is_first_data_frame = false;
}
let led_strip = (u16::from(output.port_address) & 0b0111_u16) as usize;
//output.port_address
for i in 0..led_driver.get_led_per_strips() {
for i in 0..led_driver.get_led_per_strip_count() {
let data_index = i * 3;
let g = *output.data.as_ref().get(data_index).unwrap_or(&0);
let r = *output.data.as_ref().get(data_index + 1).unwrap_or(&0);
@@ -118,11 +120,9 @@ impl AppModeHandler for ArtNetMode {
// let color = (r as u32) << 16 + (g as u32) << 8 + b;
let color: u32 =
((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
led_driver.set_color(color, i);
led_driver.direct_set_color(color, i);
}
led_driver.refresh();
// Here you would typically handle the output data, e.g., send it to the LED driver
// For now, we just log it
}
ArtCommand::PollReply(_) => {
log::trace!("[ArtNet] Received PollReply command, ignoring");
@@ -139,14 +139,16 @@ impl AppModeHandler for ArtNetMode {
Err(e) => panic!("encountered IO error: {e}"),
}
}
Ok(())
}
fn exit(&mut self) {
fn exit(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[ArtNet] Exiting ArtNet Mode");
log::info!("[ArtNet] Statistics: {}", self.statistics);
self.socket = None;
self.last_frame_time = None;
self.statistics = ArtNetModeStatistics::default();
Ok(())
}
}
@@ -30,22 +30,24 @@ impl DiagnosticsMode {
fn init_led_iterator(led_driver: &LedDriver) -> Range<usize> {
// Initialize the LED iterator to cover all LEDs
0..led_driver.get_led_per_strips()
0..led_driver.get_led_per_strip_count()
}
}
impl AppModeHandler for DiagnosticsMode {
fn enter(&mut self) {
fn enter(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[Diagnostics] Entering Diagnostics Mode");
self.cycle_count = 0;
Ok(())
}
fn run(&mut self, led_driver: &mut LedDriver) {
fn run(&mut self, led_driver: &mut LedDriver) -> Result<(), Box<dyn std::error::Error>> {
if self.cycle_count % 50 == 0 {
log::trace!("[Diagnostics] Running...");
let (led, color) = match self.led_iterator.next() {
Some(led) => {
led_driver.set_color(**self.color_iterator.peek().unwrap(), led);
// led_driver.direct_set_color(**self.color_iterator.peek().unwrap(), led);
led_driver.set_led_color(**self.color_iterator.peek().unwrap(), led, 0);
(led, *self.color_iterator.peek().unwrap())
}
None => {
@@ -57,14 +59,16 @@ impl AppModeHandler for DiagnosticsMode {
led,
match self.color_iterator.peek() {
Some(color) => {
led_driver.set_color(**color, led);
// led_driver.direct_set_color(**color, led);
led_driver.set_led_color(**color, led, 0);
*color
}
None => {
// Reset the color iterator if it reaches the end
self.color_iterator = DiagnosticsMode::color_iterator();
let color = self.color_iterator.peek().unwrap();
led_driver.set_color(**color, led);
// led_driver.direct_set_color(**color, led);
led_driver.set_led_color(**color, led, 0);
*color
}
},
@@ -75,9 +79,11 @@ impl AppModeHandler for DiagnosticsMode {
led_driver.refresh();
}
self.cycle_count += 1;
Ok(())
}
fn exit(&mut self) {
fn exit(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[Diagnostics] Exiting Diagnostics Mode");
Ok(())
}
}
@@ -10,15 +10,21 @@ impl ManualMode {
}
impl AppModeHandler for ManualMode {
fn enter(&mut self) {
fn enter(&mut self) -> std::result::Result<(), Box<(dyn std::error::Error + 'static)>> {
log::debug!("[Manual] Entering Manual Mode");
Ok(())
}
fn run(&mut self, _: &mut LedDriver) {
fn run(
&mut self,
_: &mut LedDriver,
) -> std::result::Result<(), Box<(dyn std::error::Error + 'static)>> {
log::trace!("[Manual] Running...");
Ok(())
}
fn exit(&mut self) {
fn exit(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[Manual] Exiting Manual Mode");
Ok(())
}
}
@@ -0,0 +1,328 @@
use core::f32;
use crossbeam::channel;
use spectrum_analyzer::windows::hann_window;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Instant;
use rppal::gpio::Gpio;
use spectrum_analyzer::scaling::divide_by_N_sqrt;
use spectrum_analyzer::{FrequencyLimit, FrequencyValue, samples_fft_to_spectrum};
use crate::cputasks::modes::AppModeHandler;
use crate::devices::led_driver::LedDriver;
pub struct StandaloneMode {
_i2s_mic_pin: Vec<rppal::gpio::IoPin>,
audio_processor: Option<AudioProcessorControl>,
}
impl StandaloneMode {
const I2S_PINS: [u8; 3] = [20, 19, 18];
pub fn new() -> Self {
let gpio = Gpio::new().expect("Failed to initialize GPIO");
let i2s_mic_pin: Vec<rppal::gpio::IoPin> = Self::I2S_PINS
.iter()
.map(|&pin| {
gpio.get(pin)
.expect(&format!("Failed to get GPIO pin {}", pin))
.into_io(rppal::gpio::Mode::Alt0)
})
.collect();
StandaloneMode {
_i2s_mic_pin: i2s_mic_pin,
audio_processor: None,
}
}
fn compute_log_spectrum(
fft_data: &[(f32, f32)],
strip_count: usize,
f_min: f32,
f_max: f32,
) -> Vec<f32> {
let mut bands = vec![0.0; strip_count];
let mut counts = vec![0usize; strip_count];
// Precompute band edges logarithmically
let mut edges = Vec::with_capacity(strip_count + 1);
for i in 0..=strip_count {
let fraction = i as f32 / strip_count as f32;
let edge = f_min * (f_max / f_min).powf(fraction);
edges.push(edge);
}
// Assign each frequency to a band
for &(freq, amp) in fft_data {
if freq < f_min || freq > f_max {
continue;
}
if let Some(idx) = edges.windows(2).position(|w| freq >= w[0] && freq < w[1]) {
bands[idx] += amp;
counts[idx] += 1;
}
}
// Normalize
for (b, c) in bands.iter_mut().zip(counts) {
if c > 0 {
*b /= c as f32;
}
}
bands
}
}
impl AppModeHandler for StandaloneMode {
fn enter(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[Standalone] Entering Standalone Mode");
let audio_processor = AudioProcessorControl::new()?;
self.audio_processor = Some(audio_processor);
Ok(())
}
fn run(&mut self, led_driver: &mut LedDriver) -> Result<(), Box<dyn std::error::Error>> {
log::trace!("[Standalone] Running...");
if let Some(audio_processor) = &self.audio_processor {
match audio_processor.get_data() {
Some(data) => {
log::trace!("[Standalone] Received audio data: {:?}", data.len());
log::info!(
"Frequency count: {} MAX([|{}; {}|]) -> {:?}",
data.len(),
data[0].0,
data[data.len() - 1].0,
data.iter()
.fold((0_f32, 0_f32), |(freq_max, val_max), (freq, val)| {
if *val >= val_max {
(*freq, *val)
} else {
(freq_max, val_max)
}
})
);
let spectrum = StandaloneMode::compute_log_spectrum(
&data,
led_driver.get_strip_count(),
data[0].0,
data[data.len() - 1].0,
);
log::debug!(
"[Standalone] Computed spectrum: {:?}",
spectrum
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
);
let avg_intensity = spectrum.iter().fold(0_f32, |x_max, x| x_max.max(*x));
let g = avg_intensity.min(255.0) as u8;
let r = 0_u8;
let b = 255 - avg_intensity.min(255.0) as u8;
let color: u32 = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
let light_number =
(avg_intensity as usize / 50).min(led_driver.get_led_per_strip_count());
log::debug!(
"[Standalone] Average intensity: {}, Color: {:06x}, Light number: {}",
avg_intensity,
color,
light_number
);
for i in 0..light_number {
// Set the color for the first `light_number` LEDs
led_driver.direct_set_color(color, i);
}
for i in light_number..led_driver.get_led_per_strip_count() {
// Set the remaining LEDs to black
led_driver.direct_set_color(0x000000, i);
}
led_driver.refresh();
}
None => {
log::trace!("[Standalone] No audio data received");
}
}
} else {
log::warn!("[Standalone] Audio processor is not initialized");
}
Ok(())
}
fn exit(&mut self) -> Result<(), Box<dyn std::error::Error>> {
log::debug!("[Standalone] Exiting Standalone Mode");
self.audio_processor = None;
Ok(())
}
}
struct AudioProcessorControl {
rx: channel::Receiver<Vec<(f32, f32)>>,
stop_flag: Arc<AtomicBool>,
handle: Option<std::thread::JoinHandle<()>>,
}
impl AudioProcessorControl {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
let stop_flag = Arc::new(AtomicBool::new(false));
let flag_clone = Arc::clone(&stop_flag);
let (tx, rx): (
channel::Sender<Vec<(f32, f32)>>,
channel::Receiver<Vec<(f32, f32)>>,
) = crossbeam::channel::bounded(1);
let mut audio_processor = AudioProcessor::new(tx)?;
let join_handle = thread::spawn(move || {
log::info!("Starting audio processing thread");
while !flag_clone.load(Ordering::Relaxed) {
audio_processor.process_audio();
}
});
Ok(AudioProcessorControl {
rx,
stop_flag,
handle: Some(join_handle),
})
}
pub fn get_data(&self) -> Option<Vec<(f32, f32)>> {
match self.rx.try_recv() {
Ok(data) => Some(data),
Err(crossbeam::channel::TryRecvError::Empty) => None,
Err(e) => {
log::error!("Failed to receive data from channel: {:?}", e);
None
}
}
}
}
impl Drop for AudioProcessorControl {
fn drop(&mut self) {
log::info!("Stopping audio processing thread");
self.stop_flag.store(true, Ordering::Relaxed);
let _ = self.handle.take().unwrap().join().map_err(|e| {
log::error!("Failed to stop audio processing thread: {:?}", e);
});
}
}
struct AudioProcessor {
pcm: alsa::pcm::PCM,
spectrum: Vec<(f32, f32)>,
tx: channel::Sender<Vec<(f32, f32)>>,
}
impl AudioProcessor {
pub fn new(tx: channel::Sender<Vec<(f32, f32)>>) -> Result<Self, Box<dyn std::error::Error>> {
let hints = alsa::device_name::HintIter::new_str(None, "pcm").unwrap();
for hint in hints {
// When Direction is None it means that both the PCM supports both playback and capture
if hint.name.is_some()
&& hint.desc.is_some()
&& (hint.direction.is_none()
|| hint
.direction
.map(|dir| dir == alsa::Direction::Capture)
.unwrap_or_default())
{
log::debug!(
"pcm: {:<35} desc: {:?}",
hint.name.unwrap(),
hint.desc.unwrap()
);
}
}
let pcm = alsa::PCM::new(
"plughw:CARD=sndrpigooglevoi,DEV=0",
alsa::Direction::Capture,
false,
)
.unwrap();
{
// For this example, we assume 44100Hz, one channel, 16 bit audio.
let hwp = alsa::pcm::HwParams::any(&pcm).unwrap();
hwp.set_channels_near(1).unwrap();
hwp.set_rate_near(44100, alsa::ValueOr::Nearest).unwrap();
hwp.set_format(alsa::pcm::Format::float()).unwrap();
hwp.set_access(alsa::pcm::Access::RWInterleaved).unwrap();
pcm.hw_params(&hwp).unwrap();
}
pcm.start()?;
Ok(AudioProcessor {
pcm,
spectrum: Vec::new(),
tx,
})
}
fn process_audio(&mut self) {
// Placeholder for audio processing logic
// This should return a vector of tuples representing frequency and amplitude
let start = Instant::now();
let binding = &self.pcm;
let io = binding.io_f32().unwrap();
let mut buf = [0f32; 2048];
// Block while waiting for 2048 samples to be read from the device.
let nb_samples = io.readi(&mut buf).unwrap();
let elapsed_1 = start.elapsed();
log::trace!(
"[Standalone] Read {} samples in {:?}",
nb_samples,
elapsed_1
);
let start = Instant::now();
if nb_samples >= 2048 {
let data = buf[..2048].to_vec();
let res: spectrum_analyzer::FrequencySpectrum = samples_fft_to_spectrum(
&hann_window(&data),
44100,
FrequencyLimit::Range(20_f32, 20000_f32),
// FrequencyLimit::All,
Some(&divide_by_N_sqrt),
)
.unwrap();
if self.spectrum.is_empty() {
self.spectrum = Vec::from_iter(
res.data()
.iter()
.map(|(fr, fr_val)| (fr.val(), fr_val.val() * 5000.0_f32)),
);
} else {
res.data().iter().zip(self.spectrum.iter_mut()).for_each(
|((fr, fr_val), (fr_old, fr_old_val))| {
*fr_old = fr.val();
let old_val = *fr_old_val * 0.84;
let max = (*fr_val * 5000.0_f32.into()).max(FrequencyValue::from(old_val));
*fr_old_val = max.val();
},
);
}
self.tx
.try_send(self.spectrum.clone())
.expect("Failed to send audio data");
let elapsed_2 = start.elapsed();
log::trace!("{elapsed_1:?} {elapsed_2:?}");
} else {
log::trace!("{elapsed_1:?}");
}
}
}
@@ -0,0 +1 @@
pub use led_driver::LedDriver;
@@ -32,7 +32,7 @@ fn setup() -> GlobalContext {
std::process::exit(0);
})
.expect("Error setting SIGINT/SIGTERM/SIGHUP handler");
let led_driver = LedDriver::new(5);
let led_driver = LedDriver::new(5, 3);
let (tx, rx) = unbounded();
let mode_manager = ModeManager::new(rx);
@@ -57,7 +57,7 @@ fn run(ctx: &mut GlobalContext) {
if elapsed > period {
log::warn!(
"Mode {:?} execution took too long: {:?}/{:?}ms",
"Mode {:?} execution took too long: {:?}/{:?}",
ctx.mode_manager.get_current_mode(),
elapsed,
period
@@ -70,7 +70,6 @@ fn run(ctx: &mut GlobalContext) {
fn cleanup() {
log::info!("Cleaning up before quitting...");
// Perform cleanup here
}
impl LightSabre {
+5 -2
View File
@@ -1,5 +1,8 @@
#!/bin/bash
set -e
set -x
VSCODE_WS="$(pwd)"
SSH_REMOTE="raspberrypi.local"
@@ -12,7 +15,7 @@ TARGET_CWD="/tmp"
cargo build
ssh "${TARGET_USER}@${SSH_REMOTE}" "sudo killall lldb-server ${APP}"
ssh "${TARGET_USER}@${SSH_REMOTE}" "sudo killall lldb-server ${APP}" || true
if ! rsync -avz "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
# If rsync doesn't work, it may not be available on target. Fallback to trying SSH copy.
@@ -26,5 +29,5 @@ if [[ "$1" == "--debug" ]]; then
ssh "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; sudo RUST_LOG=debug lldb -o run ${TARGET_BIN_FILE}'"
else
echo "Running in release mode"
ssh "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; sudo RUST_LOG=info ${TARGET_BIN_FILE}'"
ssh "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; sudo RUST_LOG=${RUST_LOG} ${TARGET_BIN_FILE}'"
fi