Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
jane | 22d36994cf |
|
@ -1,9 +1,2 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
|
||||||
# Added by cargo
|
|
||||||
|
|
||||||
/target
|
|
||||||
|
|
||||||
rls*.log
|
|
|
@ -1,519 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bindgen"
|
|
||||||
version = "0.54.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cexpr",
|
|
||||||
"cfg-if 0.1.10",
|
|
||||||
"clang-sys",
|
|
||||||
"lazy_static",
|
|
||||||
"lazycell",
|
|
||||||
"peeking_take_while",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex",
|
|
||||||
"rustc-hash",
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.72"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cexpr"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
|
|
||||||
dependencies = [
|
|
||||||
"nom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clang-sys"
|
|
||||||
version = "0.29.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "form_urlencoded"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
|
||||||
dependencies = [
|
|
||||||
"matches",
|
|
||||||
"percent-encoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[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 = "getrandom"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "http"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"fnv",
|
|
||||||
"itoa",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "httparse"
|
|
||||||
version = "1.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
|
||||||
dependencies = [
|
|
||||||
"matches",
|
|
||||||
"unicode-bidi",
|
|
||||||
"unicode-normalization",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "0.4.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazycell"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "leds"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"rand",
|
|
||||||
"rs_ws281x",
|
|
||||||
"tungstenite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.112"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matches"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "5.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "opaque-debug"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "peeking_take_while"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "percent-encoding"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
"rand_hc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.5.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
|
||||||
dependencies = [
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rs_ws281x"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "80a0b739bc99b3d8a7a18f914045a279f0dd7e7cffe1fe9d7335f311187f16ca"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
"cc",
|
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-hash"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.132"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.132"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha-1"
|
|
||||||
version = "0.9.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer",
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"cpufeatures",
|
|
||||||
"digest",
|
|
||||||
"opaque-debug",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23a1dfb999630e338648c83e91c59a4e9fb7620f520c3194b6b89e276f2f1959"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "1.0.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "1.0.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tinyvec"
|
|
||||||
version = "1.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
|
||||||
dependencies = [
|
|
||||||
"tinyvec_macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tinyvec_macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tungstenite"
|
|
||||||
version = "0.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"byteorder",
|
|
||||||
"bytes",
|
|
||||||
"http",
|
|
||||||
"httparse",
|
|
||||||
"log",
|
|
||||||
"rand",
|
|
||||||
"sha-1",
|
|
||||||
"thiserror",
|
|
||||||
"url",
|
|
||||||
"utf-8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-bidi"
|
|
||||||
version = "0.3.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-normalization"
|
|
||||||
version = "0.1.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
|
||||||
dependencies = [
|
|
||||||
"tinyvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "url"
|
|
||||||
version = "2.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
|
||||||
dependencies = [
|
|
||||||
"form_urlencoded",
|
|
||||||
"idna",
|
|
||||||
"matches",
|
|
||||||
"percent-encoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf-8"
|
|
||||||
version = "0.7.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,11 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "leds"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
rs_ws281x = "0.4.2"
|
|
||||||
tungstenite = "0.16.0"
|
|
||||||
rand = "0.8.4"
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"leds": 450,
|
||||||
|
"brightness": 150,
|
||||||
|
"gpio": 18,
|
||||||
|
"type": "grb",
|
||||||
|
"fade_ticks": 25,
|
||||||
|
"sleep_time": 100,
|
||||||
|
"log_level": "INFO"
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import * as server from './server.js';
|
||||||
|
import * as lights from './lights.js';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
const cfg = JSON.parse(fs.readFileSync('./config.json'));
|
||||||
|
|
||||||
|
server.recv(
|
||||||
|
(res) => {
|
||||||
|
lights.set_pattern(JSON.parse(res));
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
console.log(`error callback: ${res}`);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
lights.tick();
|
||||||
|
}, cfg.sleep_time || 500);
|
|
@ -0,0 +1,235 @@
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
|
||||||
|
class Adafruit_CharLCD:
|
||||||
|
|
||||||
|
# commands
|
||||||
|
LCD_CLEARDISPLAY = 0x01
|
||||||
|
LCD_RETURNHOME = 0x02
|
||||||
|
LCD_ENTRYMODESET = 0x04
|
||||||
|
LCD_DISPLAYCONTROL = 0x08
|
||||||
|
LCD_CURSORSHIFT = 0x10
|
||||||
|
LCD_FUNCTIONSET = 0x20
|
||||||
|
LCD_SETCGRAMADDR = 0x40
|
||||||
|
LCD_SETDDRAMADDR = 0x80
|
||||||
|
|
||||||
|
# flags for display entry mode
|
||||||
|
LCD_ENTRYRIGHT = 0x00
|
||||||
|
LCD_ENTRYLEFT = 0x02
|
||||||
|
LCD_ENTRYSHIFTINCREMENT = 0x01
|
||||||
|
LCD_ENTRYSHIFTDECREMENT = 0x00
|
||||||
|
|
||||||
|
# flags for display on/off control
|
||||||
|
LCD_DISPLAYON = 0x04
|
||||||
|
LCD_DISPLAYOFF = 0x00
|
||||||
|
LCD_CURSORON = 0x02
|
||||||
|
LCD_CURSOROFF = 0x00
|
||||||
|
LCD_BLINKON = 0x01
|
||||||
|
LCD_BLINKOFF = 0x00
|
||||||
|
|
||||||
|
# flags for display/cursor shift
|
||||||
|
LCD_DISPLAYMOVE = 0x08
|
||||||
|
LCD_CURSORMOVE = 0x00
|
||||||
|
|
||||||
|
# flags for display/cursor shift
|
||||||
|
LCD_DISPLAYMOVE = 0x08
|
||||||
|
LCD_CURSORMOVE = 0x00
|
||||||
|
LCD_MOVERIGHT = 0x04
|
||||||
|
LCD_MOVELEFT = 0x00
|
||||||
|
|
||||||
|
# flags for function set
|
||||||
|
LCD_8BITMODE = 0x10
|
||||||
|
LCD_4BITMODE = 0x00
|
||||||
|
LCD_2LINE = 0x08
|
||||||
|
LCD_1LINE = 0x00
|
||||||
|
LCD_5x10DOTS = 0x04
|
||||||
|
LCD_5x8DOTS = 0x00
|
||||||
|
|
||||||
|
def __init__(self, pin_rs=24, pin_e=23, pin_b=4, pins_db=[17, 25, 27, 22], GPIO=None):
|
||||||
|
# Emulate the old behavior of using RPi.GPIO if we haven't been given
|
||||||
|
# an explicit GPIO interface to use
|
||||||
|
if not GPIO:
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
self.GPIO = GPIO
|
||||||
|
self.pin_rs = pin_rs
|
||||||
|
self.pin_e = pin_e
|
||||||
|
self.pin_b = pin_b
|
||||||
|
self.pins_db = pins_db
|
||||||
|
|
||||||
|
self.GPIO.setwarnings(False)
|
||||||
|
self.GPIO.setmode(GPIO.BCM)
|
||||||
|
self.GPIO.setup(self.pin_e, GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.pin_rs, GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.pin_b, GPIO.OUT)
|
||||||
|
|
||||||
|
for pin in self.pins_db:
|
||||||
|
self.GPIO.setup(pin, GPIO.OUT)
|
||||||
|
|
||||||
|
self.GPIO.output(self.pin_b, True)
|
||||||
|
|
||||||
|
self.write4bits(0x33) # initialization
|
||||||
|
self.write4bits(0x32) # initialization
|
||||||
|
self.write4bits(0x28) # 2 line 5x7 matrix
|
||||||
|
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
|
||||||
|
self.write4bits(0x06) # shift cursor right
|
||||||
|
|
||||||
|
self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
|
||||||
|
|
||||||
|
self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
|
||||||
|
self.displayfunction |= self.LCD_2LINE
|
||||||
|
|
||||||
|
""" Initialize to default text direction (for romance languages) """
|
||||||
|
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
|
||||||
|
self.write4bits(self.LCD_ENTRYMODESET |
|
||||||
|
self.displaymode) # set the entry mode
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def begin(self, cols, lines):
|
||||||
|
|
||||||
|
if (lines > 1):
|
||||||
|
self.numlines = lines
|
||||||
|
self.displayfunction |= self.LCD_2LINE
|
||||||
|
self.currline = 0
|
||||||
|
|
||||||
|
def home(self):
|
||||||
|
|
||||||
|
self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
|
||||||
|
self.delayMicroseconds(3000) # this command takes a long time!
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
|
||||||
|
self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
|
||||||
|
# 3000 microsecond sleep, clearing the display takes a long time
|
||||||
|
self.delayMicroseconds(3000)
|
||||||
|
|
||||||
|
def setCursor(self, col, row):
|
||||||
|
|
||||||
|
self.row_offsets = [0x00, 0x40, 0x14, 0x54]
|
||||||
|
|
||||||
|
if (row > self.numlines):
|
||||||
|
row = self.numlines - 1 # we count rows starting w/0
|
||||||
|
|
||||||
|
self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
|
||||||
|
|
||||||
|
def noDisplay(self):
|
||||||
|
""" Turn the display off (quickly) """
|
||||||
|
self.GPIO.output(self.pin_b, False)
|
||||||
|
self.displaycontrol &= ~self.LCD_DISPLAYON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def display(self):
|
||||||
|
""" Turn the display on (quickly) """
|
||||||
|
self.GPIO.output(self.pin_b, True)
|
||||||
|
self.displaycontrol |= self.LCD_DISPLAYON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def noCursor(self):
|
||||||
|
""" Turns the underline cursor on/off """
|
||||||
|
|
||||||
|
self.displaycontrol &= ~self.LCD_CURSORON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def cursor(self):
|
||||||
|
""" Cursor On """
|
||||||
|
|
||||||
|
self.displaycontrol |= self.LCD_CURSORON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def noBlink(self):
|
||||||
|
""" Turn on and off the blinking cursor """
|
||||||
|
|
||||||
|
self.displaycontrol &= ~self.LCD_BLINKON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def noBlink(self):
|
||||||
|
""" Turn on and off the blinking cursor """
|
||||||
|
|
||||||
|
self.displaycontrol &= ~self.LCD_BLINKON
|
||||||
|
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
|
||||||
|
|
||||||
|
def DisplayLeft(self):
|
||||||
|
""" These commands scroll the display without changing the RAM """
|
||||||
|
|
||||||
|
self.write4bits(self.LCD_CURSORSHIFT |
|
||||||
|
self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
|
||||||
|
|
||||||
|
def scrollDisplayRight(self):
|
||||||
|
""" These commands scroll the display without changing the RAM """
|
||||||
|
|
||||||
|
self.write4bits(self.LCD_CURSORSHIFT |
|
||||||
|
self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)
|
||||||
|
|
||||||
|
def leftToRight(self):
|
||||||
|
""" This is for text that flows Left to Right """
|
||||||
|
|
||||||
|
self.displaymode |= self.LCD_ENTRYLEFT
|
||||||
|
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
|
||||||
|
|
||||||
|
def rightToLeft(self):
|
||||||
|
""" This is for text that flows Right to Left """
|
||||||
|
self.displaymode &= ~self.LCD_ENTRYLEFT
|
||||||
|
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
|
||||||
|
|
||||||
|
def autoscroll(self):
|
||||||
|
""" This will 'right justify' text from the cursor """
|
||||||
|
|
||||||
|
self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
|
||||||
|
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
|
||||||
|
|
||||||
|
def noAutoscroll(self):
|
||||||
|
""" This will 'left justify' text from the cursor """
|
||||||
|
|
||||||
|
self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
|
||||||
|
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
|
||||||
|
|
||||||
|
def write4bits(self, bits, char_mode=False):
|
||||||
|
""" Send command to LCD """
|
||||||
|
|
||||||
|
self.delayMicroseconds(1000) # 1000 microsecond sleep
|
||||||
|
|
||||||
|
bits = bin(bits)[2:].zfill(8)
|
||||||
|
|
||||||
|
self.GPIO.output(self.pin_rs, char_mode)
|
||||||
|
|
||||||
|
for pin in self.pins_db:
|
||||||
|
self.GPIO.output(pin, False)
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
if bits[i] == "1":
|
||||||
|
self.GPIO.output(self.pins_db[::-1][i], True)
|
||||||
|
|
||||||
|
self.pulseEnable()
|
||||||
|
|
||||||
|
for pin in self.pins_db:
|
||||||
|
self.GPIO.output(pin, False)
|
||||||
|
|
||||||
|
for i in range(4, 8):
|
||||||
|
if bits[i] == "1":
|
||||||
|
self.GPIO.output(self.pins_db[::-1][i-4], True)
|
||||||
|
|
||||||
|
self.pulseEnable()
|
||||||
|
|
||||||
|
def delayMicroseconds(self, microseconds):
|
||||||
|
# divide microseconds by 1 million for seconds
|
||||||
|
seconds = microseconds / float(1000000)
|
||||||
|
sleep(seconds)
|
||||||
|
|
||||||
|
def pulseEnable(self):
|
||||||
|
self.GPIO.output(self.pin_e, False)
|
||||||
|
# 1 microsecond pause - enable pulse must be > 450ns
|
||||||
|
self.delayMicroseconds(1)
|
||||||
|
self.GPIO.output(self.pin_e, True)
|
||||||
|
# 1 microsecond pause - enable pulse must be > 450ns
|
||||||
|
self.delayMicroseconds(1)
|
||||||
|
self.GPIO.output(self.pin_e, False)
|
||||||
|
self.delayMicroseconds(1) # commands need > 37us to settle
|
||||||
|
|
||||||
|
def message(self, text):
|
||||||
|
""" Send string to LCD. Newline wraps to second line"""
|
||||||
|
|
||||||
|
for char in text:
|
||||||
|
if char == '\n':
|
||||||
|
self.write4bits(0xC0) # next line
|
||||||
|
else:
|
||||||
|
self.write4bits(ord(char), True)
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#
|
||||||
|
# based on code from lrvick and LiquidCrystal
|
||||||
|
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
|
||||||
|
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
|
||||||
|
#
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
import sys
|
||||||
|
import lcd_manager
|
||||||
|
import light_manager
|
||||||
|
import pattern
|
||||||
|
import logger
|
||||||
|
import threading
|
||||||
|
import socket
|
||||||
|
|
||||||
|
this = sys.modules[__name__]
|
||||||
|
|
||||||
|
this.level = 0
|
||||||
|
this.level_max = 14
|
||||||
|
this.level_state = 0
|
||||||
|
this.color_state = 0
|
||||||
|
|
||||||
|
|
||||||
|
def lightlevel(lcd, level):
|
||||||
|
logger.debug("display level")
|
||||||
|
lcd.clear()
|
||||||
|
lcd.message("Light Level:\n]" + "-"*level + "[")
|
||||||
|
|
||||||
|
|
||||||
|
def query():
|
||||||
|
level_state = 2
|
||||||
|
|
||||||
|
|
||||||
|
def color(lcd):
|
||||||
|
lcd.clear()
|
||||||
|
lcd.message("new pattern loaded.")
|
||||||
|
logger.debug("NYI")
|
||||||
|
|
||||||
|
|
||||||
|
def get_state():
|
||||||
|
if this.level_state > 0:
|
||||||
|
this.level_state -= 1
|
||||||
|
return "level"
|
||||||
|
elif this.color_state > 0:
|
||||||
|
this.color_state -= 1
|
||||||
|
return "color"
|
||||||
|
else:
|
||||||
|
return "idle"
|
||||||
|
|
||||||
|
|
||||||
|
def displayon(lcd):
|
||||||
|
if lcd.displaycontrol & lcd.LCD_DISPLAYON != lcd.displaycontrol:
|
||||||
|
lcd.display()
|
||||||
|
|
||||||
|
|
||||||
|
def socket_loop():
|
||||||
|
injected = False
|
||||||
|
s = socket.create_server(('0.0.0.0', 29999))
|
||||||
|
while True:
|
||||||
|
if not injected:
|
||||||
|
this.lights.set_pattern(pattern.pat)
|
||||||
|
injected = True
|
||||||
|
sock, addr = s.accept()
|
||||||
|
with sock:
|
||||||
|
length_data = sock.recv(4)
|
||||||
|
logger.debug(length_data)
|
||||||
|
length = int(length_data.decode())
|
||||||
|
logger.debug(length)
|
||||||
|
pattern_data = sock.recv(length)
|
||||||
|
logger.debug(pattern_data)
|
||||||
|
pattern.parse(pattern_data.decode())
|
||||||
|
this.color_state = 7
|
||||||
|
|
||||||
|
|
||||||
|
def loop():
|
||||||
|
socket_thread = threading.Thread(target=socket_loop)
|
||||||
|
lcd = lcd_manager.Adafruit_CharLCD()
|
||||||
|
this.lights = light_manager.LightStrip(string_length=450, brightness=0.6, max_changes=10)
|
||||||
|
socket_thread.start()
|
||||||
|
while True:
|
||||||
|
logger.debug("loop")
|
||||||
|
this.lights.tick()
|
||||||
|
query()
|
||||||
|
state = get_state()
|
||||||
|
|
||||||
|
if state == "level":
|
||||||
|
if this.lights.get_light_level() != (this.level / this.level_max):
|
||||||
|
this.lights.set_light_level(this.level / this.level_max)
|
||||||
|
lightlevel(lcd, this.level)
|
||||||
|
elif state == "color":
|
||||||
|
color(lcd)
|
||||||
|
else:
|
||||||
|
lcd.noDisplay()
|
||||||
|
sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop()
|
|
@ -0,0 +1,67 @@
|
||||||
|
from time import sleep
|
||||||
|
import neopixel
|
||||||
|
import board
|
||||||
|
import logger
|
||||||
|
import pattern
|
||||||
|
|
||||||
|
|
||||||
|
def defaultPattern(n, t, pv):
|
||||||
|
return (t % 255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
|
class LightStrip:
|
||||||
|
def __init__(self, data_pin=board.D18, string_length=300, brightness=0.7, pixel_order=neopixel.GRB, max_changes=5):
|
||||||
|
self.data_pin = data_pin
|
||||||
|
|
||||||
|
self.np = neopixel.NeoPixel(
|
||||||
|
self.data_pin, string_length, brightness=brightness, auto_write=True, pixel_order=pixel_order)
|
||||||
|
self.pattern = defaultPattern
|
||||||
|
self.cur_tick = 0
|
||||||
|
self.cur_index = 0
|
||||||
|
self.max_changes = max_changes
|
||||||
|
self.cur_pattern = []
|
||||||
|
|
||||||
|
def get_light_level(self):
|
||||||
|
return self.np.brightness
|
||||||
|
|
||||||
|
def set_light_level(self, level):
|
||||||
|
self.np.brightness = level
|
||||||
|
|
||||||
|
def set_pattern(self, pattern_callback):
|
||||||
|
self.pattern = pattern_callback
|
||||||
|
|
||||||
|
def get_next_pattern_tick(self):
|
||||||
|
np = self.np
|
||||||
|
n = np.n
|
||||||
|
t = self.cur_tick
|
||||||
|
if not len(self.cur_pattern) >= n - 1:
|
||||||
|
li = [(255, 255, 255)] * (n - len(self.cur_pattern))
|
||||||
|
self.cur_pattern.extend(li)
|
||||||
|
for i in range(n):
|
||||||
|
self.cur_pattern[i] = self.pattern(i, t, np[i])
|
||||||
|
self.cur_tick = t + 1
|
||||||
|
|
||||||
|
def tick(self):
|
||||||
|
np = self.np
|
||||||
|
t = self.cur_tick
|
||||||
|
n = np.n
|
||||||
|
|
||||||
|
if not len(self.cur_pattern) >= n - 1:
|
||||||
|
self.get_next_pattern_tick()
|
||||||
|
changes = 0
|
||||||
|
ind = self.cur_index
|
||||||
|
for i in range(ind, n):
|
||||||
|
col = self.cur_pattern[i]
|
||||||
|
self.cur_index = i
|
||||||
|
logger.debug("TEST VALUES: np {} col {} same {}".format(
|
||||||
|
tuple(np[i]), col, tuple(np[i]) != col))
|
||||||
|
if tuple(np[i]) != col:
|
||||||
|
changes = changes + 1
|
||||||
|
np[i] = col
|
||||||
|
logger.debug(
|
||||||
|
"CHANGE COLOR OF PIXEL {} TO {} ON TICK {}".format(i, col, t))
|
||||||
|
if changes >= self.max_changes:
|
||||||
|
break
|
||||||
|
if self.cur_index >= (n-1):
|
||||||
|
self.get_next_pattern_tick()
|
||||||
|
self.cur_index = 0
|
|
@ -0,0 +1,308 @@
|
||||||
|
import ws281x from "rpi-ws281x";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import Logger, { levels } from "./logger.js";
|
||||||
|
|
||||||
|
const cfg = JSON.parse(fs.readFileSync("./config.json"));
|
||||||
|
const log = new Logger(
|
||||||
|
"lights",
|
||||||
|
cfg.log_level ? levels[cfg.log_level] : levels.INFO
|
||||||
|
);
|
||||||
|
|
||||||
|
const fade_ticks = cfg.fade_ticks || 20;
|
||||||
|
var num_ticks = 0;
|
||||||
|
var pixels = new Uint32Array(cfg.leds);
|
||||||
|
var pixel_cache = new Uint32Array(cfg.leds);
|
||||||
|
var next_pattern = new Uint32Array(cfg.leds);
|
||||||
|
const targets = {};
|
||||||
|
var pattern = {};
|
||||||
|
|
||||||
|
function rgb_to_int(r, g, b) {
|
||||||
|
let rgb = r;
|
||||||
|
rgb = (rgb << 8) + g;
|
||||||
|
rgb = (rgb << 8) + b;
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
function int_to_rgb(int) {
|
||||||
|
var r = (int >> 16) & 0xff;
|
||||||
|
var g = (int >> 8) & 0xff;
|
||||||
|
var b = int & 0xff;
|
||||||
|
return { r: r, g: g, b: b };
|
||||||
|
}
|
||||||
|
|
||||||
|
ws281x.configure({
|
||||||
|
leds: cfg.leds || 300,
|
||||||
|
brightness: cfg.brightness || 200,
|
||||||
|
gpio: cfg.gpio || 18,
|
||||||
|
stripType: cfg.type || "grb",
|
||||||
|
});
|
||||||
|
|
||||||
|
export function set_pattern(pat) {
|
||||||
|
pattern = pat;
|
||||||
|
log.debug("pattern set");
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Function {
|
||||||
|
func;
|
||||||
|
options;
|
||||||
|
|
||||||
|
constructor(func, options) {
|
||||||
|
this.func = func;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const functions = {
|
||||||
|
random: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return Math.floor(Math.random() * 256);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: false,
|
||||||
|
convert_args: false,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
move: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return arg2;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
modulo: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return arg1 % arg2;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
swap: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
let temp = targets[arg2];
|
||||||
|
targets[arg2] = targets[arg1];
|
||||||
|
return temp;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: false,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
add: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return arg1 + arg2;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
subtract: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return arg1 - arg2;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
stagger: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return (index + arg2) % 255;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
slide: new Function(
|
||||||
|
(index, arg1, arg2) => {
|
||||||
|
return (num_ticks + arg2) % 255;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requires_arg1: true,
|
||||||
|
requires_arg2: true,
|
||||||
|
convert_args: true,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
function tick_pattern() {
|
||||||
|
// do the parsing stuff here
|
||||||
|
log.debug("TICKING PATTERN");
|
||||||
|
|
||||||
|
let parsed = pattern.parsed;
|
||||||
|
log.debug(`${JSON.stringify(pattern)} ${JSON.stringify(parsed)}`);
|
||||||
|
|
||||||
|
if (parsed && parsed.length > 0) {
|
||||||
|
for (let i = 0; i < cfg.leds; i++) {
|
||||||
|
for (let id in parsed) {
|
||||||
|
let command = parsed[id];
|
||||||
|
log.debug(`pattern ${id} ${command}`);
|
||||||
|
let name = command["command"];
|
||||||
|
log.debug(`${name} matches: ${functions[name]}`);
|
||||||
|
if (functions[name] != undefined) {
|
||||||
|
if (
|
||||||
|
functions[name].options &&
|
||||||
|
functions[name].options["convert_args"]
|
||||||
|
) {
|
||||||
|
let param_arg1 = parseInt(command.arg1) || targets[command.arg1];
|
||||||
|
let param_arg2 = parseInt(command.arg2) || targets[command.arg2];
|
||||||
|
let result = functions[name].func(i, param_arg1, param_arg2);
|
||||||
|
log.debug(
|
||||||
|
`convert ${command.arg1} ${param_arg1} ${command.arg2} ${param_arg2} ${result}`
|
||||||
|
);
|
||||||
|
targets[command.arg1] = result;
|
||||||
|
} else {
|
||||||
|
let result = functions[name].func(i, command.arg1, command.arg2);
|
||||||
|
log.debug(`no convert ${command.arg1} = ${result}`);
|
||||||
|
targets[command.arg1] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug(`next: ${targets["r"]}, ${targets["g"]}, ${targets["b"]}`);
|
||||||
|
next_pattern[i] = rgb_to_int(
|
||||||
|
targets["r"] || 0,
|
||||||
|
targets["g"] || 0,
|
||||||
|
targets["b"] || 0
|
||||||
|
);
|
||||||
|
targets["r"] = 0;
|
||||||
|
targets["g"] = 0;
|
||||||
|
targets["b"] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getRandom();
|
||||||
|
}
|
||||||
|
num_ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom() {
|
||||||
|
for (let i = 0; i < cfg.leds; i++) {
|
||||||
|
var r = Math.floor(Math.random() * 256);
|
||||||
|
var g = Math.floor(Math.random() * 256);
|
||||||
|
var b = Math.floor(Math.random() * 256);
|
||||||
|
next_pattern[i] = rgb_to_int(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tick() {
|
||||||
|
var changed = false;
|
||||||
|
for (let i = 0; i < cfg.leds; i++) {
|
||||||
|
if (next_pattern[i] != pixels[i]) {
|
||||||
|
if (next_pattern[i] == pixel_cache[i]) {
|
||||||
|
log.debug("INCONGRUENCE WITH " + i);
|
||||||
|
pixels[i] = next_pattern[i];
|
||||||
|
} else {
|
||||||
|
changed = true;
|
||||||
|
fade(i);
|
||||||
|
}
|
||||||
|
} else if (pixel_cache[i] != pixels[i]) {
|
||||||
|
log.debug("PATTERN NOT STORED " + i);
|
||||||
|
pixel_cache[i] = pixels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!changed) {
|
||||||
|
tick_pattern();
|
||||||
|
} else {
|
||||||
|
ws281x.render(pixels);
|
||||||
|
}
|
||||||
|
//ws281x.sleep(cfg.sleep_time || 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fade(index) {
|
||||||
|
var original = int_to_rgb(pixel_cache[index]);
|
||||||
|
var current = int_to_rgb(pixels[index]);
|
||||||
|
var final = int_to_rgb(next_pattern[index]);
|
||||||
|
var diff_r = final.r - original.r;
|
||||||
|
var diff_cr = current.r - original.r;
|
||||||
|
var diff_g = final.g - original.g;
|
||||||
|
var diff_cg = current.g - original.g;
|
||||||
|
var diff_b = final.b - original.b;
|
||||||
|
var diff_cb = current.b - original.b;
|
||||||
|
var sign_r = diff_r === Math.abs(diff_r) ? 1 : -1;
|
||||||
|
var sign_g = diff_g === Math.abs(diff_g) ? 1 : -1;
|
||||||
|
var sign_b = diff_b === Math.abs(diff_b) ? 1 : -1;
|
||||||
|
log.debug(`${diff_r} ${sign_r} ${diff_g} ${sign_g} ${diff_b} ${sign_b}`);
|
||||||
|
var interval_r = sign_r * Math.ceil(Math.abs(diff_r) / fade_ticks);
|
||||||
|
var interval_g = sign_g * Math.ceil(Math.abs(diff_g) / fade_ticks);
|
||||||
|
var interval_b = sign_b * Math.ceil(Math.abs(diff_b) / fade_ticks);
|
||||||
|
log.debug(
|
||||||
|
`r${Math.abs(diff_r) / fade_ticks} ${Math.ceil(
|
||||||
|
Math.abs(diff_r) / fade_ticks
|
||||||
|
)}` +
|
||||||
|
`g${Math.abs(diff_g) / fade_ticks} ${Math.ceil(
|
||||||
|
Math.abs(diff_g) / fade_ticks
|
||||||
|
)}` +
|
||||||
|
`b${Math.abs(diff_b) / fade_ticks} ${Math.ceil(
|
||||||
|
Math.abs(diff_b) / fade_ticks
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
var current_tick_r = Math.floor(Math.abs(diff_cr / diff_r) * fade_ticks);
|
||||||
|
var current_tick_g = Math.floor(Math.abs(diff_cg / diff_g) * fade_ticks);
|
||||||
|
var current_tick_b = Math.floor(Math.abs(diff_cb / diff_b) * fade_ticks);
|
||||||
|
if (
|
||||||
|
diff_r == 0 ||
|
||||||
|
(sign_r == 1 && current.r + interval_r >= final.r) ||
|
||||||
|
(sign_r == -1 && current.r + interval_r <= final.r) ||
|
||||||
|
current_tick_r + 1 >= fade_ticks
|
||||||
|
) {
|
||||||
|
current.r = final.r;
|
||||||
|
interval_r = 0;
|
||||||
|
current_tick_r = fade_ticks;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
diff_g == 0 ||
|
||||||
|
(sign_g == 1 && current.g + interval_g >= final.g) ||
|
||||||
|
(sign_g == -1 && current.g + interval_g <= final.g) ||
|
||||||
|
current_tick_g + 1 >= fade_ticks
|
||||||
|
) {
|
||||||
|
current.g = final.g;
|
||||||
|
interval_g = 0;
|
||||||
|
current_tick_g = fade_ticks;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
diff_b == 0 ||
|
||||||
|
(sign_b == 1 && current.b + interval_b >= final.b) ||
|
||||||
|
(sign_b == -1 && current.b + interval_b <= final.b) ||
|
||||||
|
current_tick_b + 1 >= fade_ticks
|
||||||
|
) {
|
||||||
|
current.b = final.b;
|
||||||
|
interval_b = 0;
|
||||||
|
current_tick_b = fade_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
current_tick_r + 1 >= fade_ticks &&
|
||||||
|
current_tick_g + 1 >= fade_ticks &&
|
||||||
|
current_tick_b + 1 >= fade_ticks
|
||||||
|
) {
|
||||||
|
log.debug("FINISHED");
|
||||||
|
pixel_cache[index] = next_pattern[index];
|
||||||
|
} else {
|
||||||
|
pixels[index] = rgb_to_int(
|
||||||
|
current.r + interval_r,
|
||||||
|
current.g + interval_g,
|
||||||
|
current.b + interval_b
|
||||||
|
);
|
||||||
|
let prev = int_to_rgb(pixel_cache[index]);
|
||||||
|
log.debug(
|
||||||
|
`${current_tick_r} ${current_tick_g} ${current_tick_b}: ` +
|
||||||
|
`CURRENT COLOR: ${current.r} ${current.g} ${current.b} NEW COLOR: ${
|
||||||
|
current.r + interval_r
|
||||||
|
} ${current.g + interval_g} ${current.b + interval_b} ` +
|
||||||
|
`FINAL: ${final.r} ${final.g} ${final.b} ` +
|
||||||
|
`\nINTERVAL: ${interval_r} ${interval_g} ${interval_b} ` +
|
||||||
|
`PREVIOUS: ${prev.r} ${prev.g} ${prev.b}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
export const levels = {
|
||||||
|
DEBUG: 4,
|
||||||
|
INFO: 3,
|
||||||
|
WARN: 2,
|
||||||
|
ERROR: 1,
|
||||||
|
PANIC: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Logger {
|
||||||
|
constructor(name, level) {
|
||||||
|
console.log(`created new logger for ${name} with level ${level}`);
|
||||||
|
this.sn(name);
|
||||||
|
this.s(level);
|
||||||
|
}
|
||||||
|
n = 'DEFAULT';
|
||||||
|
l = 0;
|
||||||
|
sn(n) {
|
||||||
|
this.n = n;
|
||||||
|
}
|
||||||
|
s(l) {
|
||||||
|
if (l && l.constructor === Number) {
|
||||||
|
this.l = l;
|
||||||
|
} else {
|
||||||
|
this.l = levels[l];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lo(l, m) {
|
||||||
|
if (l <= this.l) {
|
||||||
|
let level = Object.keys(levels).find((key) => levels[key] === l);
|
||||||
|
let ms = typeof m == 'object' ? JSON.stringify(m) : m;
|
||||||
|
console.log(`${level} [${this.n}]: ${ms}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(msg) {
|
||||||
|
this.lo(levels.DEBUG, msg);
|
||||||
|
}
|
||||||
|
info(msg) {
|
||||||
|
this.lo(levels.INFO, msg);
|
||||||
|
}
|
||||||
|
warn(msg) {
|
||||||
|
this.lo(levels.WARN, msg);
|
||||||
|
}
|
||||||
|
error(msg) {
|
||||||
|
this.lo(levels.ERROR, msg);
|
||||||
|
}
|
||||||
|
panic(msg) {
|
||||||
|
this.lo(levels.PANIC, msg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
debug_statements = False
|
||||||
|
|
||||||
|
|
||||||
|
def debug(msg):
|
||||||
|
if debug_statements:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def info(msg):
|
||||||
|
print(msg)
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"name": "leds",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@ssh.gitdab.com:jane/leds"
|
||||||
|
},
|
||||||
|
"author": "jane@j4.pm",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"dependencies": {
|
||||||
|
"rpi-ws281x": "^1.0.36"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import Logger, { levels } from './logger.js';
|
||||||
|
import { functions } from './lights.js';
|
||||||
|
|
||||||
|
const cfg = JSON.parse(fs.readFileSync('./config.json'));
|
||||||
|
const log = new Logger("server", cfg.log_level ? levels[cfg.log_level] : levels.INFO);
|
||||||
|
|
||||||
|
|
||||||
|
export default function parse(data) {
|
||||||
|
let parsed = []
|
||||||
|
let errors = []
|
||||||
|
log.info(data);
|
||||||
|
// errors.push("not yet implemented");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
let line = data.split("\n");
|
||||||
|
for (let lineNumber in line) {
|
||||||
|
let currentLine = line[lineNumber];
|
||||||
|
let split = currentLine.split(" ");
|
||||||
|
let command = split[0];
|
||||||
|
let arg1 = split[1];
|
||||||
|
let arg2 = split[2];
|
||||||
|
|
||||||
|
let match = functions[command];
|
||||||
|
if (match != undefined) {
|
||||||
|
if (
|
||||||
|
(match.options["requires_arg1"] && arg1 == undefined) ||
|
||||||
|
(match.options["requires_arg2"] && arg2 == undefined)
|
||||||
|
) {
|
||||||
|
errors.push(`error parsing line ${lineNumber}, invalid number of args`);
|
||||||
|
}
|
||||||
|
else if (!match.options["convert_args"] && parseInt(arg1)) {
|
||||||
|
errors.push(`error parsing line ${lineNumber}, argument ${arg1} cannot be a number`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parsed.push(
|
||||||
|
{
|
||||||
|
command: command,
|
||||||
|
arg1: arg1 || undefined,
|
||||||
|
arg2: arg2 || undefined
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
parsed: parsed,
|
||||||
|
data: data,
|
||||||
|
errors: errors
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,189 @@
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import logger
|
||||||
|
|
||||||
|
this = sys.modules[__name__]
|
||||||
|
|
||||||
|
this.encoded = None
|
||||||
|
this.pattern = None
|
||||||
|
this.values = {
|
||||||
|
"stack": 0,
|
||||||
|
"stack2": 0,
|
||||||
|
"stack3": 0,
|
||||||
|
"stack4": 0,
|
||||||
|
"stack5": 0,
|
||||||
|
"stack6": 0,
|
||||||
|
"stackr": 0,
|
||||||
|
"stackg": 0,
|
||||||
|
"stackb": 0,
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"tick": 0,
|
||||||
|
"index": 0,
|
||||||
|
"fadeval": 0,
|
||||||
|
"fadeinc": True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def constant(target, arg, index):
|
||||||
|
return (arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def add(target, arg, index):
|
||||||
|
return (target + arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def sub(target, arg, index):
|
||||||
|
return (target - arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def mult(target, arg, index):
|
||||||
|
return (target * arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def div(target, arg, index):
|
||||||
|
return (target / arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def mod(target, arg, index):
|
||||||
|
if arg <= 0:
|
||||||
|
return target
|
||||||
|
return (target % arg, index)
|
||||||
|
|
||||||
|
|
||||||
|
def fade(target, arg, index):
|
||||||
|
value = this.values['fadeval']
|
||||||
|
if this.values['fadeinc']:
|
||||||
|
value += 1
|
||||||
|
if value >= arg:
|
||||||
|
this.values['fadeinc'] = False
|
||||||
|
else:
|
||||||
|
value -= 1
|
||||||
|
if value <= 0:
|
||||||
|
this.values['fadeinc'] = True
|
||||||
|
this.values['fadeval'] = value
|
||||||
|
return (value, index)
|
||||||
|
|
||||||
|
|
||||||
|
def rand(target, arg, index):
|
||||||
|
return (random.randrange(0, 255), index)
|
||||||
|
|
||||||
|
|
||||||
|
def jmp(target, arg, index):
|
||||||
|
return (target, target)
|
||||||
|
|
||||||
|
|
||||||
|
def jnz(target, arg, index):
|
||||||
|
if target != 0:
|
||||||
|
return (target, arg)
|
||||||
|
else:
|
||||||
|
return (target, index)
|
||||||
|
|
||||||
|
|
||||||
|
def jez(target, arg, index):
|
||||||
|
if target == 0:
|
||||||
|
return (target, arg)
|
||||||
|
else:
|
||||||
|
return (target, index)
|
||||||
|
|
||||||
|
|
||||||
|
def _apply(index, target, arg, func):
|
||||||
|
if type(arg) is int:
|
||||||
|
logger.debug("ran: {} {} {} {}".format(index, func.__name__, target, arg))
|
||||||
|
return func(target, arg, index)
|
||||||
|
elif type(arg) is str and arg in this.values:
|
||||||
|
logger.debug("ran: {} {} {} {}".format(
|
||||||
|
index, func.__name__, target, this.values[arg]))
|
||||||
|
return func(target, this.values[arg], index)
|
||||||
|
|
||||||
|
|
||||||
|
def apply(index, targets, args, func):
|
||||||
|
j = index
|
||||||
|
for target in range(len(targets)):
|
||||||
|
if this.values[targets[target]['channel']] != None:
|
||||||
|
logger.debug("target: {}".format(targets[target]['channel']))
|
||||||
|
if target < len(args):
|
||||||
|
val, jump = _apply(
|
||||||
|
index, this.values[targets[target]['channel']], args[target], func)
|
||||||
|
if val != this.values[targets[target]['channel']]:
|
||||||
|
this.values[targets[target]['channel']] = val
|
||||||
|
j = jump
|
||||||
|
else:
|
||||||
|
val, jump = _apply(
|
||||||
|
index, this.values[targets[target]['channel']], 0, func)
|
||||||
|
if val != this.values[targets[target]['channel']]:
|
||||||
|
this.values[targets[target]['channel']] = val
|
||||||
|
j = jump
|
||||||
|
return j
|
||||||
|
|
||||||
|
|
||||||
|
this.instructions = {
|
||||||
|
"CONSTANT": constant,
|
||||||
|
"ADD": add,
|
||||||
|
"SUBTRACT": sub,
|
||||||
|
"MULTIPLY": mult,
|
||||||
|
"DIVIDE": div,
|
||||||
|
"MODULO": mod,
|
||||||
|
"FADE": fade,
|
||||||
|
"RANDOM": rand,
|
||||||
|
"JMP": jmp,
|
||||||
|
"JNZ": jnz,
|
||||||
|
"JEZ": jez
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def default(index, tick):
|
||||||
|
return (((index + tick) * 5) % 255, (tick * 42) % 255, (tick * 50) % 255)
|
||||||
|
|
||||||
|
|
||||||
|
def pat(index, tick, previous_values):
|
||||||
|
this.values['tick'] = tick
|
||||||
|
this.values['index'] = index
|
||||||
|
if this.pattern != None:
|
||||||
|
i = 0
|
||||||
|
while i < len(this.pattern):
|
||||||
|
if i < len(this.pattern):
|
||||||
|
name = this.pattern[i]['instruction']['name']
|
||||||
|
targets = this.pattern[i]['instruction']['targets']
|
||||||
|
args = []
|
||||||
|
if 'args' in this.pattern[i]['instruction']:
|
||||||
|
args = this.pattern[i]['instruction']['args']
|
||||||
|
if this.instructions[name] != None:
|
||||||
|
jump = apply(i, targets, args, this.instructions[name])
|
||||||
|
logger.debug("{} {} {} {} {}".format(jump, i, len(
|
||||||
|
this.pattern), jump != i, jump <= len(this.pattern)))
|
||||||
|
if jump != i and jump <= len(this.pattern):
|
||||||
|
logger.debug("jumping to {}".format(jump - 1))
|
||||||
|
i = jump - 1
|
||||||
|
i += 1
|
||||||
|
r = this.values["r"]
|
||||||
|
g = this.values["g"]
|
||||||
|
b = this.values["b"]
|
||||||
|
this.values["r"] = 0
|
||||||
|
this.values["g"] = 0
|
||||||
|
this.values["b"] = 0
|
||||||
|
this.values["stack"] = 0
|
||||||
|
if r > 255:
|
||||||
|
r = 255
|
||||||
|
elif r < 0:
|
||||||
|
r = 0
|
||||||
|
if g > 255:
|
||||||
|
g = 255
|
||||||
|
elif g < 0:
|
||||||
|
g = 0
|
||||||
|
if b > 255:
|
||||||
|
b = 255
|
||||||
|
elif b < 0:
|
||||||
|
b = 0
|
||||||
|
logger.debug("final color: {}".format((r, g, b)))
|
||||||
|
return (r, g, b)
|
||||||
|
else:
|
||||||
|
return default(index, tick)
|
||||||
|
|
||||||
|
|
||||||
|
def parse(str):
|
||||||
|
this.encoded = str
|
||||||
|
logger.debug(this.encoded)
|
||||||
|
this.pattern = json.loads(this.encoded)
|
|
@ -0,0 +1,20 @@
|
||||||
|
lockfileVersion: 5.3
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
rpi-ws281x: ^1.0.36
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
rpi-ws281x: 1.0.36
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
/nan/2.14.2:
|
||||||
|
resolution: {integrity: sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/rpi-ws281x/1.0.36:
|
||||||
|
resolution: {integrity: sha512-iKmc4lKA0/V83q7rdYmFJV3nsQTXaJ8wqyYqdamUn6krDPRevkOhkty9Zj0ZcsYeXBVzxWKzd3VdenDYDQKAGg==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
nan: 2.14.2
|
||||||
|
dev: false
|
|
@ -0,0 +1,2 @@
|
||||||
|
rpi_ws281x==4.2.5
|
||||||
|
adafruit-circuitpython-neopixel==6.0.0
|
|
@ -0,0 +1,62 @@
|
||||||
|
import * as net from 'net';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import Logger, { levels } from './logger.js';
|
||||||
|
import parse from './parse.js'
|
||||||
|
|
||||||
|
const cfg = JSON.parse(fs.readFileSync('./config.json'));
|
||||||
|
const log = new Logger("server", cfg.log_level ? levels[cfg.log_level] : levels.INFO);
|
||||||
|
|
||||||
|
|
||||||
|
const hostname = '0.0.0.0';
|
||||||
|
const port = 29999;
|
||||||
|
|
||||||
|
export function recv(callback, errorCallback) {
|
||||||
|
let server = new net.Server();
|
||||||
|
server.listen(port, hostname, () => {
|
||||||
|
server.on('connection', (con) => {
|
||||||
|
console.log('connection recieved: ' +
|
||||||
|
con.remoteAddress + ":" + con.remotePort);
|
||||||
|
// let data = [];
|
||||||
|
// for (let key of Object.keys(functions)) {
|
||||||
|
// data.push({
|
||||||
|
// n: key.toUpperCase(),
|
||||||
|
// a: reqs[key.toLowerCase()] != undefined ? reqs[key.toLowerCase()] : true
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// let functions_str = JSON.stringify(data);
|
||||||
|
// con.write(functions_str);
|
||||||
|
// log.debug(`sending ${functions_str}`);
|
||||||
|
con.on('data', (data) => {
|
||||||
|
let parsed_data = parse(String(data));
|
||||||
|
|
||||||
|
if (parsed_data.errors != undefined && parsed_data.errors.length > 0) {
|
||||||
|
con.write(`error ..\n${JSON.stringify(parsed_data)}`);
|
||||||
|
errorCallback(JSON.stringify(parsed_data));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
con.write(`success ..\n${JSON.stringify(parsed_data)}`);
|
||||||
|
callback(JSON.stringify(parsed_data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
con.on('close', () => {
|
||||||
|
console.log('recieved close for ' +
|
||||||
|
con.remoteAddress + ":" + con.remotePort);
|
||||||
|
con.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
server.getConnections((err, cons) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(`connections: ${cons}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
server.on('error', (e) => {
|
||||||
|
server.close();
|
||||||
|
errorCallback(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
16
shell.nix
16
shell.nix
|
@ -1,16 +0,0 @@
|
||||||
let
|
|
||||||
pkgs = import <nixpkgs> {};
|
|
||||||
in
|
|
||||||
with pkgs;
|
|
||||||
mkShell {
|
|
||||||
buildInputs = [
|
|
||||||
cargo
|
|
||||||
rustc
|
|
||||||
rustfmt
|
|
||||||
rls
|
|
||||||
protobuf
|
|
||||||
llvm
|
|
||||||
];
|
|
||||||
|
|
||||||
RUST_SRC_PATH= "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
|
||||||
}
|
|
56
src/main.rs
56
src/main.rs
|
@ -1,56 +0,0 @@
|
||||||
pub mod util;
|
|
||||||
|
|
||||||
use util::lights::*;
|
|
||||||
use util::pattern::*;
|
|
||||||
use util::webserver::*;
|
|
||||||
use std::sync::{Arc, RwLock, Mutex};
|
|
||||||
use rs_ws281x::{RawColor, Controller, ControllerBuilder, ChannelBuilder, StripType};
|
|
||||||
use std::{thread, time};
|
|
||||||
|
|
||||||
pub const LED_SIZE: usize = 450; //450
|
|
||||||
pub const BRIGHTNESS: u8 = 100;
|
|
||||||
pub const LOOP_WAIT: u64 = 250;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let p: RawColor = [0, 0, 0, 0];
|
|
||||||
let lock = Arc::new(RwLock::new([p; LED_SIZE]));
|
|
||||||
let pattern: Arc<Mutex<Vec<Box<dyn Pattern>>>> = Arc::new(Mutex::new(Vec::new()));
|
|
||||||
let read = Arc::clone(&lock);
|
|
||||||
//light management
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut controller: Controller = ControllerBuilder::new()
|
|
||||||
.channel(0, ChannelBuilder::new()
|
|
||||||
.pin(18)
|
|
||||||
.count(i32::try_from(LED_SIZE).unwrap())
|
|
||||||
.strip_type(StripType::Ws2812)
|
|
||||||
.brightness(BRIGHTNESS)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
.expect("Could not construct LED Controller.");
|
|
||||||
loop {
|
|
||||||
let lights = read.read().expect("Could not read array lock.");
|
|
||||||
run_lights(&mut controller, &lights).expect("Error running lights controller.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let pat_clone = Arc::clone(&pattern);
|
|
||||||
thread::spawn(move || loop {
|
|
||||||
websocket(&pat_clone);
|
|
||||||
});
|
|
||||||
|
|
||||||
//pattern management
|
|
||||||
let mut ticks = 0;
|
|
||||||
loop {
|
|
||||||
thread::sleep(time::Duration::from_millis(LOOP_WAIT));
|
|
||||||
let c_lock = Arc::clone(&lock);
|
|
||||||
let mut lights = c_lock.write().unwrap();
|
|
||||||
let data = pattern.lock().unwrap();
|
|
||||||
for p in &*data {
|
|
||||||
//let c_lock = Arc::clone(&lock);
|
|
||||||
//let mut lights = c_lock.write().unwrap();
|
|
||||||
p.execute(&mut lights, ticks);
|
|
||||||
}
|
|
||||||
ticks+= 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub mod lights;
|
|
||||||
pub mod pattern;
|
|
||||||
pub mod webserver;
|
|
|
@ -1,17 +0,0 @@
|
||||||
use rs_ws281x::RawColor;
|
|
||||||
use rs_ws281x::Controller;
|
|
||||||
use rs_ws281x::WS2811Error;
|
|
||||||
// use std::{thread, time};
|
|
||||||
|
|
||||||
pub fn run_lights(controller: &mut Controller, values: &[RawColor; crate::LED_SIZE]) -> Result<(), WS2811Error> {
|
|
||||||
//println!("Value: {:?}", values[0]);
|
|
||||||
//thread::sleep(time::Duration::from_millis(10));
|
|
||||||
let channels: Vec<usize> = controller.channels();
|
|
||||||
let strip = controller.leds_mut(channels[0]);
|
|
||||||
for i in 0..strip.len() {
|
|
||||||
strip[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.render().expect("Error rendering.");
|
|
||||||
controller.wait()
|
|
||||||
}
|
|
|
@ -1,240 +0,0 @@
|
||||||
use rs_ws281x::RawColor;
|
|
||||||
use std::{
|
|
||||||
vec::Vec,
|
|
||||||
string::String
|
|
||||||
};
|
|
||||||
use std::sync::RwLockWriteGuard;
|
|
||||||
|
|
||||||
pub type ParseError = Box<dyn std::error::Error>;
|
|
||||||
|
|
||||||
pub trait Pattern: Send {
|
|
||||||
fn execute(&self, values: &mut RwLockWriteGuard<'_, [RawColor; crate::LED_SIZE]>, ticks: u64);
|
|
||||||
fn parse(args: Vec<String>) -> Result<Self, ParseError> where Self: Sized;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Vec<String>> for Box<dyn Pattern> {
|
|
||||||
type Error = ParseError;
|
|
||||||
fn try_from(s: Vec<String>) -> Result<Self, Self::Error> {
|
|
||||||
match s[0].as_str() {
|
|
||||||
"unit" => Ok(Box::new(Unit::parse(s).unwrap()) as Box<dyn Pattern>),
|
|
||||||
"val" => Ok(Box::new(Value::parse(s).unwrap()) as Box<dyn Pattern>),
|
|
||||||
"rand" => Ok(Box::new(Random::parse(s).unwrap()) as Box<dyn Pattern>),
|
|
||||||
_ => Err("No Match".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Unit;
|
|
||||||
impl Pattern for Unit {
|
|
||||||
fn execute(&self, _values: &mut RwLockWriteGuard<'_, [RawColor; crate::LED_SIZE]>, _ticks: u64) {}
|
|
||||||
fn parse(_args: Vec<String>) -> Result<Self, ParseError> {
|
|
||||||
Ok(Unit {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Value {
|
|
||||||
r: Option<u8>,
|
|
||||||
g: Option<u8>,
|
|
||||||
b: Option<u8>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pattern for Value {
|
|
||||||
fn execute(&self, values: &mut RwLockWriteGuard<'_, [RawColor; crate::LED_SIZE]>, _ticks: u64) {
|
|
||||||
|
|
||||||
|
|
||||||
for i in 0..crate::LED_SIZE {
|
|
||||||
let mut color: RawColor = (*values)[i];
|
|
||||||
if self.r.is_some() {
|
|
||||||
color[2] = self.r.unwrap();
|
|
||||||
}
|
|
||||||
if self.g.is_some() {
|
|
||||||
color[1] = self.g.unwrap();
|
|
||||||
}
|
|
||||||
if self.b.is_some() {
|
|
||||||
color[0] = self.b.unwrap();
|
|
||||||
}
|
|
||||||
(*values)[i] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn parse(args: Vec<String>) -> Result<Self, ParseError> {
|
|
||||||
let param1 = if args.len() > 1 {
|
|
||||||
match args[1].parse::<u8>() {
|
|
||||||
Ok(i) => Some(i),
|
|
||||||
Err(_) => None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let param2 = if args.len() > 2 {
|
|
||||||
match args[2].parse::<u8>() {
|
|
||||||
Ok(i) => Some(i),
|
|
||||||
Err(_) => None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let param3 = if args.len() > 3 {
|
|
||||||
match args[3].parse::<u8>() {
|
|
||||||
Ok(i) => Some(i),
|
|
||||||
Err(_) => None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if param1.is_some() && param2.is_some() && param3.is_some() {
|
|
||||||
Ok(Value{
|
|
||||||
r: param1,
|
|
||||||
g: param2,
|
|
||||||
b: param3
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else if args.len() >= 2 {
|
|
||||||
match param2 {
|
|
||||||
Some(i) => match args[1].as_str() {
|
|
||||||
"r" => {
|
|
||||||
Ok(Value {
|
|
||||||
r: Some(i),
|
|
||||||
g: None,
|
|
||||||
b: None
|
|
||||||
})
|
|
||||||
},
|
|
||||||
"g" => {
|
|
||||||
Ok(Value {
|
|
||||||
r: None,
|
|
||||||
g: Some(i),
|
|
||||||
b: None
|
|
||||||
})
|
|
||||||
},
|
|
||||||
"b" => {
|
|
||||||
Ok(Value {
|
|
||||||
r: None,
|
|
||||||
g: None,
|
|
||||||
b: Some(i)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => Err("no rgb".into())
|
|
||||||
},
|
|
||||||
None => Err("no param2".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Err("incorrect number of arguments".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Random {
|
|
||||||
r: bool,
|
|
||||||
g: bool,
|
|
||||||
b: bool,
|
|
||||||
min: u8,
|
|
||||||
max: u8
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pattern for Random {
|
|
||||||
fn execute(&self, values: &mut RwLockWriteGuard<'_, [RawColor; crate::LED_SIZE]>, _ticks: u64) {
|
|
||||||
use rand::prelude::*;
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
for i in 0..values.len() {
|
|
||||||
let mut color = (*values)[i];
|
|
||||||
let min = self.min;
|
|
||||||
let max = self.max;
|
|
||||||
if self.r {
|
|
||||||
let y: f64 = rng.gen();
|
|
||||||
color[2] = (y * (max - min) as f64) as u8 + min;
|
|
||||||
//println!("r {} {}", y, color[2]);
|
|
||||||
}
|
|
||||||
if self.g {
|
|
||||||
let y: f64 = rng.gen();
|
|
||||||
color[1] = (y * (max - min) as f64) as u8 + min;
|
|
||||||
//println!("g {} {}", y, color[1]);
|
|
||||||
}
|
|
||||||
if self.b {
|
|
||||||
let y: f64 = rng.gen();
|
|
||||||
color[0] = (y * (max - min) as f64) as u8 + min;
|
|
||||||
//println!("b {} {}", y, color[0]);
|
|
||||||
}
|
|
||||||
(*values)[i] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn parse(args: Vec<String>) -> Result<Self, ParseError> {
|
|
||||||
let end = args.len() - 1;
|
|
||||||
let e = args[end].parse::<u8>();
|
|
||||||
let en = args[end-1].parse::<u8>();
|
|
||||||
let mut r = false;
|
|
||||||
let mut g = false;
|
|
||||||
let mut b = false;
|
|
||||||
let (min, max) = match en {
|
|
||||||
Ok(i) => {
|
|
||||||
match e {
|
|
||||||
Ok(j) => (i, j),
|
|
||||||
Err(_) => (0, 255)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_) => {
|
|
||||||
match e {
|
|
||||||
Ok(i) => (0, i),
|
|
||||||
Err(_) => (0, 255)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for x in 0..end+1 {
|
|
||||||
match args[x].as_str() {
|
|
||||||
"r" => {r = true;},
|
|
||||||
"g" => {g = true;},
|
|
||||||
"b" => {b = true;},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//println!("{} {} {}", r,g,b);
|
|
||||||
Ok(Random {
|
|
||||||
r: r,
|
|
||||||
g: g,
|
|
||||||
b: b,
|
|
||||||
min: min,
|
|
||||||
max: max
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Rainbow {
|
|
||||||
offset_r: Option<usize>,
|
|
||||||
offset_g: Option<usize>,
|
|
||||||
offset_b: Option<usize>
|
|
||||||
}
|
|
||||||
// todo
|
|
||||||
|
|
||||||
|
|
||||||
// iterate over but pull
|
|
||||||
// VecDeque::rotate_right()
|
|
||||||
|
|
||||||
//let mut v = (1..6).collect::<VecDeque<_>>();
|
|
||||||
//v.rotate_right(1);
|
|
||||||
//println!("{:?}", v);
|
|
||||||
|
|
||||||
// IF intented vec is the same as current vec
|
|
||||||
// dupe & rotate current vec
|
|
||||||
// change value so it is only gathered once per tick, and only for the first pixel
|
|
||||||
// set new intended vec to rotated vec
|
|
||||||
// exit IF
|
|
||||||
// slowly transform current vec to intended vec by a constant fade value
|
|
||||||
// reply inside execute fn
|
|
||||||
|
|
||||||
struct Ticker {
|
|
||||||
ticks: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_line(v: Vec<String>) -> Result<Box<dyn Pattern>, ParseError> {
|
|
||||||
println!("{:?}", v);
|
|
||||||
v.try_into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format_multiline(input: &str) -> Vec<Vec<String>> {
|
|
||||||
input.lines()
|
|
||||||
.map(|x: &str|
|
|
||||||
x.split_whitespace()
|
|
||||||
.map(|y| String::from(y))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
)
|
|
||||||
.collect()
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
use std::net::TcpListener;
|
|
||||||
use std::{thread, sync::{Arc, Mutex}};
|
|
||||||
use tungstenite::accept;
|
|
||||||
use crate::util::pattern::*;
|
|
||||||
|
|
||||||
pub fn websocket(pattern: &Arc<Mutex<Vec<Box<dyn Pattern>>>>) {
|
|
||||||
let server = TcpListener::bind("0.0.0.0:29999").unwrap();
|
|
||||||
for stream in server.incoming() {
|
|
||||||
let clone = Arc::clone(pattern);
|
|
||||||
thread::spawn (move || {
|
|
||||||
let mut websocket = accept(stream.unwrap()).unwrap();
|
|
||||||
loop {
|
|
||||||
let input = websocket.read_message().unwrap();
|
|
||||||
if input.is_text() {
|
|
||||||
let string = input.to_text().unwrap_or("unit");
|
|
||||||
let mul_string = format_multiline(string);
|
|
||||||
match mul_string.iter().cloned().map(parse_line).collect() {
|
|
||||||
Ok(patterns) => {
|
|
||||||
let mut data = clone.lock().unwrap();
|
|
||||||
*data = patterns;
|
|
||||||
let text = format!("Ok!\n\n{}", string);
|
|
||||||
let msg = tungstenite::Message::from(text);
|
|
||||||
websocket.write_message(msg).unwrap();
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
println!("ret err {:?}", err);
|
|
||||||
let msg = tungstenite::Message::from(err.to_string());
|
|
||||||
websocket.write_message(msg).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let msg = tungstenite::Message::from("Not text");
|
|
||||||
match websocket.write_message(msg) {
|
|
||||||
// fuck this result in particular
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue