Initial commit

This commit is contained in:
2025-05-25 18:14:25 +00:00
commit 86fbf1670c
17 changed files with 846 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
[target.aarch64-unknown-linux-gnu]
linker = "/usr/bin/aarch64-linux-gnu-gcc"
[target.armv7-unknown-linux-gnueabihf]
linker = "/usr/bin/arm-linux-gnueabihf-gcc"
[build]
target = "armv7-unknown-linux-gnueabihf"
+14
View File
@@ -0,0 +1,14 @@
# Start from the official Rust dev container image for Debian 12 (bookworm)
FROM mcr.microsoft.com/devcontainers/rust:1-1-bookworm
# Install ARM cross-compilation toolchain packages
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gdb-multiarch \
gcc-arm-linux-gnueabihf \
g++-arm-linux-gnueabihf \
binutils-arm-linux-gnueabihf && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN rustup target add armv7-unknown-linux-gnueabihf
+41
View File
@@ -0,0 +1,41 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
"name": "lightsabre-devcontainer",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"dockerFile": "Dockerfile",
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
"mounts": [
{
"source": "devcontainer-cargo-cache-lightsabre",
"target": "/usr/local/cargo",
"type": "volume"
},
"type=bind,source=/home/${localEnv:USER}/.ssh,target=/home/vscode/.ssh,readonly",
"type=bind,source=/home/${localEnv:USER}/.bashrc,target=/home/vscode/.bashrc,readonly",
"type=bind,source=/home/${localEnv:USER}/.bashrc.d,target=/home/vscode/.bashrc.d,readonly"
],
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "rustc --version",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"rust-lang.rust-analyzer",
"vadimcn.vscode-lldb"]
}
}
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
+1
View File
@@ -0,0 +1 @@
/target
+23
View File
@@ -0,0 +1,23 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Remote executable 'lightsabre_backend'",
"preLaunchTask": "rust: remote Rpi debug setup",
"targetCreateCommands": [
"target create ${workspaceFolder}/target/armv7-unknown-linux-gnueabihf/debug/lightsabre_backend"
],
"processCreateCommands": [
"gdb-remote raspberrypi.local:17777"
],
"env": {
"RUST_LOG": "debug"
}
}
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.target": "armv7-unknown-linux-gnueabihf"
}
+38
View File
@@ -0,0 +1,38 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "rust: cargo ARM build (default)",
"type": "cargo",
"command": "build",
"args": ["--target", "armv7-unknown-linux-gnueabihf"],
"options": {
"cwd": "${workspaceFolder}",
"env": {
"CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER": "/usr/bin/arm-linux-gnueabihf-gcc",
"CARGO_BUILD_TARGET": "armv7-unknown-linux-gnueabihf"
}
},
"problemMatcher": [
"$rustc"
],
"group": "build",
},
{
"label": "rust: remote Rpi debug setup",
"type": "shell",
"command": "${workspaceFolder}/tools/remote_debug.sh",
"args": [
"${workspaceFolder}",
"raspberrypi.local",
"17777"
],
"group": "none",
"dependsOn": [
"rust: cargo ARM build (default)",
],
},
]
}
Generated
+341
View File
@@ -0,0 +1,341 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "jiff"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "lightsabre_backend"
version = "0.1.0"
dependencies = [
"env_logger",
"log",
"rppal",
]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rppal"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ce3b019009cff02cb6b0e96e7cc2e5c5b90187dc1a490f8ef1521d0596b026"
dependencies = [
"libc",
]
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
Executable
+3
View File
@@ -0,0 +1,3 @@
[workspace]
resolver = "3"
members = ["lightsabre_backend"]
Executable
+50
View File
@@ -0,0 +1,50 @@
# 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.
## Features
- **WS281x LED Control:** High-performance driving of addressable RGB LEDs via the Raspberry Pi SMI.
- **ArtNet Support:** Receives color data over the ArtNet protocol, allowing the Raspberry Pi to function as a DMX controller.
- **Autonomous Mode:** Analyzes audio input from an I2S microphone, performing spectral decomposition to generate dynamic lighting effects.
- **Web Interface:** Local web server for configuring and tweaking autonomous behavior.
- **MIDI Integration:** Supports real-time control and parameter adjustment via MIDI controllers.
## Technology Stack
- **Backend:** Written in Rust for robust and efficient controller logic. Some low-level operations may be implemented in C or Assembly (to be determined) for optimal performance.
- **Frontend:** Built with Vue.js, providing a modern and responsive web interface for configuration and control.
## Use Cases
- Stage lighting and scenography
- Interactive art installations
- Music-synchronized light shows
## Getting Started
1. **Hardware Requirements**
- Raspberry Pi (any model with SMI support)
- WS281x-compatible RGB LED strip
- I2S microphone (for autonomous mode)
- Optional: MIDI controller
2. **Software Setup**
- Install dependencies (see `requirements.txt`)
- Configure network for ArtNet or connect MIDI controller
- Access the web interface via your browser
## Documentation
- [ArtNet Protocol](https://art-net.org.uk/)
- [WS281x LEDs](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf)
- [Raspberry Pi SMI](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html)
- [MIDI Protocol](https://www.midi.org/)
## License
MIT License
---
*For detailed setup and usage instructions, see the [Wiki](./Wiki.md).*
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "lightsabre_backend"
version = "0.1.0"
edition = "2024"
[dependencies]
env_logger = "0.11.8"
log = "0.4.27"
rppal = "0.22.1"
[features]
default = ["rpizero2", "16channel"]
rpizero2 = ["rpi3"]
rpizero = ["rpi"]
rpi4 = []
rpi3 = []
rpi2 = []
rpi = []
16channel = []
@@ -0,0 +1,160 @@
#![allow(dead_code)]
pub mod led {
// Constants
pub const TX_TEST: u8 = 0;
pub const LED_NBITS: usize = 24;
pub const LED_PREBITS: usize = 4;
pub const LED_POSTBITS: usize = 4;
pub const BIT_NPULSES: usize = 3;
// Helper macros as functions
#[inline]
pub const fn led_dlen() -> usize {
LED_NBITS * BIT_NPULSES
}
#[inline]
pub const fn led_tx_oset(n: usize) -> usize {
LED_PREBITS + (led_dlen() * n)
}
#[inline]
pub const fn tx_buff_len(n: usize) -> usize {
led_tx_oset(n) + LED_POSTBITS
}
// TXDATA_T: u8 or u16 depending on channel count
#[cfg(feature = "led_nchans_gt_8")]
pub type TxData = u16;
#[cfg(not(feature = "led_nchans_gt_8"))]
pub type TxData = u8;
// Dummy types for external dependencies
pub struct MemMap;
pub struct VC_MEM;
pub struct DMA_CHAN_A;
// Dummy global variables
pub static mut VC_MEM: Option<MemMap> = None;
pub static mut TXDATA: Option<*mut TxData> = None;
// Buffer for TX data
pub static mut TX_BUFFER: [TxData; tx_buff_len(1)] = [0; tx_buff_len(1)];
pub fn swap_bytes(tx_buffer: &mut [u16]) {
for word in tx_buffer.iter_mut() {
*word = word.swap_bytes();
}
}
pub fn leddriver_setup() {
// Placeholder for setup logic
// videocore_setup, gpio_setup, smi_setup
}
pub fn leddriver_close() {
// Placeholder for close logic
// videocore_close, smi_close, gpio_close
}
pub fn set_color(rgb: u32, index: usize, tx_buffer: &mut [TxData]) {
let mut msk = 0b1 << 23; // Start with the highest bit for the first color channel
let mut txd_index = led_tx_oset(index);
for n in 0..LED_NBITS {
msk = match n {
0 => 0x80_0000,
8 => 0x8000,
16 => 0x80,
_ => msk >> 1,
};
tx_buffer[txd_index + 0] = TxData::MAX;
tx_buffer[txd_index + 1] = 0;
tx_buffer[txd_index + 2] = 0;
if (rgb & msk) != 0 {
tx_buffer[txd_index + 1] = TxData::MAX;
}
txd_index += BIT_NPULSES;
}
}
pub fn rgb_txdata(rgbs: &[u32], index: usize, tx_buffer: &mut [TxData], led_nchans: usize) {
let mut msk = 0;
let mut txd_index = led_tx_oset(index);
for n in 0..LED_NBITS {
msk = match n {
0 => 0x800000,
8 => 0x8000,
16 => 0x80,
_ => msk >> 1,
};
tx_buffer[txd_index + 0] = TxData::MAX;
tx_buffer[txd_index + 1] = 0;
tx_buffer[txd_index + 2] = 0;
for i in 0..led_nchans {
if (rgbs[i] & msk) != 0 {
tx_buffer[txd_index + 1] |= 1 << i;
}
}
txd_index += BIT_NPULSES;
}
}
pub fn leddriver_refresh() {
// Placeholder for refresh logic
// swap_bytes, dma_active, memcpy, enable_dma, start_smi, usleep
}
/// Convert HSV to packed RGB (GRB order)
pub fn color_hsv(hue: u16, sat: u8, val: u8) -> u32 {
let mut r: u8 = 0;
let mut g: u8 = 0;
let mut b: u8 = 0;
let mut hue = ((hue as u32 * 1530 + 32768) / 65536) as u16;
if hue < 510 {
b = 0;
if hue < 255 {
r = 255;
g = hue as u8;
} else {
r = (510 - hue) as u8;
g = 255;
}
} else if hue < 1020 {
r = 0;
if hue < 765 {
g = 255;
b = (hue - 510) as u8;
} else {
g = (1020 - hue) as u8;
b = 255;
}
} else if hue < 1530 {
g = 0;
if hue < 1275 {
r = (hue - 1020) as u8;
b = 255;
} else {
r = 255;
b = (1530 - hue) as u8;
}
} else {
r = 255;
g = 0;
b = 0;
}
let v1 = 1 + val as u32;
let s1 = 1 + sat as u32;
let s2 = 255 - sat as u32;
((((((r as u32 * s1) >> 8) + s2) * v1) & 0xff00) << 8)
| (((((g as u32 * s1) >> 8) + s2) * v1) & 0xff00)
| (((((b as u32 * s1) >> 8) + s2) * v1) >> 8)
}
}
@@ -0,0 +1,59 @@
// Constants
const LED_NBITS: usize = 24; // Number of data bits per LED
const LED_PREBITS: usize = 4; // Number of zero bits before LED data
const LED_POSTBITS: usize = 4; // Number of zero bits after LED data
const BIT_NPULSES: usize = 3; // Number of O/P pulses per LED bit
#[cfg(feature = "rpi4")] // Timings for RPi v4 (1.5 GHz)
const SMI_TIMING: [u32; 4] = [10, 15, 30, 15]; // 400 ns cycle time
#[cfg(not(feature = "rpi4"))] // Timings for RPi v0-3 (1 GHz)
const SMI_TIMING: [u32; 4] = [10, 10, 20, 10]; // 400 ns cycle time
// Use 16-bit data type for TxDataT
#[cfg(feature = "16channel")]
type TxDataT = u16;
// Use 8-bit data type for TxDataT
#[cfg(not(feature = "16channel"))]
type TxDataT = u8;
// Helper macros as functions
#[inline]
const fn led_dlen() -> usize {
LED_NBITS * BIT_NPULSES
}
#[inline]
const fn led_tx_oset(n: usize) -> usize {
LED_PREBITS + (led_dlen() * n)
}
#[inline]
const fn tx_buff_len(n: usize) -> usize {
led_tx_oset(n) + LED_POSTBITS
}
pub struct LedDriver {
// Placeholder for LED driver state
tx_buffer: [TxDataT; tx_buff_len(30)],
}
impl LedDriver {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
// Initialize the LED driver
Ok(LedDriver {
tx_buffer: [TxDataT::default(); 4856],
})
}
pub fn set_color(&self, rgb: u32, index: usize) -> Result<(), Box<dyn std::error::Error>> {
// Set the color for the LED at the specified index
// Placeholder for actual implementation
Ok(())
}
pub fn refresh(&self) -> Result<(), Box<dyn std::error::Error>> {
// Refresh the LED states
// Placeholder for actual implementation
Ok(())
}
}
+6
View File
@@ -0,0 +1,6 @@
pub mod led_driver;
pub mod selector;
pub trait Device {
fn read(&self) -> Vec<bool>;
}
@@ -0,0 +1,31 @@
use rppal::gpio::{Gpio, InputPin};
use super::Device;
use rppal::gpio::Error;
const SELECTOR_PINS: [u8; 4] = [27, 5, 6, 26]; // GPIO pin number for the LED
pub struct Selector {
selector_pins: Vec<InputPin>,
}
impl Selector {
pub fn new() -> Result<Selector, Error> {
let gpio = Gpio::new()?;
// Set up the GPIO pins for the selector, use pull-down resistors to ensure a known state when not pressed
let selector_pins: Vec<InputPin> = SELECTOR_PINS
.iter()
.map(|&pin| gpio.get(pin).unwrap().into_input_pulldown())
.collect();
Ok(Selector { selector_pins })
}
}
impl Device for Selector {
fn read(&self) -> Vec<bool> {
self.selector_pins
.iter()
.map(|pin| pin.read() == rppal::gpio::Level::High)
.collect()
}
}
+26
View File
@@ -0,0 +1,26 @@
use devices::Device;
use devices::led_driver::LedDriver;
use devices::selector::Selector;
use log::{debug, info};
use rppal::system::DeviceInfo;
mod devices;
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
info!("Executing on device: {}", DeviceInfo::new()?.model());
// Initialize GPIO
let selector = Selector::new()?;
let ledDriver = devices::led_driver::LedDriver::new()?;
debug!("Selector initialized.");
// Main loop
loop {
// Read the selector state
let selector_state = selector.read();
debug!("Selector state: {:?}", selector_state);
// Sleep for a short duration to avoid busy-waiting
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
VSCODE_WS="$1"
SSH_REMOTE="$2"
GDBPORT="$3"
APP="lightsabre_backend"
TARGET_ARCH="armv7-unknown-linux-gnueabihf"
BUILD_BIN_FILE="${VSCODE_WS}/target/${TARGET_ARCH}/debug/${APP}"
TARGET_USER="pi"
TARGET_BIN_FILE="/tmp/${APP}"
TARGET_CWD="/tmp"
ssh "${TARGET_USER}@${SSH_REMOTE}" "killall lldb-server ${APP}"
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.
if ! scp "${BUILD_BIN_FILE}" "${TARGET_USER}@${SSH_REMOTE}:${TARGET_BIN_FILE}"; then
exit 2
fi
fi
ssh -f "${TARGET_USER}@${SSH_REMOTE}" "sh -c 'cd ${TARGET_CWD}; RUST_LOG=debug nohup lldb-server g *:${GDBPORT} ${TARGET_BIN_FILE} > /dev/null 2>&1 &'"