Initial commit
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user