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
+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));
}
}