Compare commits

..

1 Commits
master ... wled

Author SHA1 Message Date
Florian Jung 641eba5faa Modify UDP protocol to be WLED-compatible. 2023-05-25 21:29:12 +02:00
6 changed files with 30 additions and 669 deletions

View File

@ -14,7 +14,6 @@ type Result<T> = std::result::Result<T, AnimationError>;
pub mod particles;
pub mod sparkles;
pub mod racers;
pub mod fire;
/////////// Error Type and Implementation ////////////

View File

@ -1,185 +0,0 @@
// vim: noet
use crate::animation::{Color, Animation, Result};
use crate::signal_processing::SignalProcessing;
use crate::config;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::VecDeque;
use rand::Rng;
const COOLDOWN_FACTOR : f32 = 0.99995;
const MAX_ENERGY_PROPAGATION : f32 = 0.4;
const RM_ENERGY_SUB : f32 = 0.011;
const RM_ENERGY_MULT : f32 = 0.995;
const EXPONENT : f32 = 1.50;
const W_EXPONENT : f32 = 2.20;
const W_SCALE : f32 = 0.3;
const OVERDRIVE : f32 = 0.3;
// A single-color flame.
// This struct contains the energy generation and propagation algorithm.
pub struct Flame
{
energy: [ [f32; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS],
}
impl Flame
{
fn new() -> Flame
{
Flame {
energy: [ [0.0; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS]
}
}
fn update(&mut self, new_energy: f32)
{
let mut rng = rand::thread_rng();
for strip in 0..config::NUM_STRIPS {
// Add new energy in the bottom row
self.energy[strip][0] += rng.gen::<f32>() * new_energy;
// Remove energy at the top
self.energy[strip][config::NUM_LEDS_PER_STRIP-1] *= 1.0 - rng.gen::<f32>() * MAX_ENERGY_PROPAGATION;
// move energy upwards
for led_out in (1..config::NUM_LEDS_PER_STRIP).rev() {
let led_in = led_out - 1;
let energy_moved = self.energy[strip][led_in] * rng.gen::<f32>() * MAX_ENERGY_PROPAGATION;
self.energy[strip][led_in] -= energy_moved;
self.energy[strip][led_out] += energy_moved;
}
// globally remove energy
for led in 0..config::NUM_LEDS_PER_STRIP {
self.energy[strip][led] *= RM_ENERGY_MULT;
if self.energy[strip][led] > RM_ENERGY_SUB {
self.energy[strip][led] -= RM_ENERGY_SUB;
} else {
self.energy[strip][led] = 0.0;
}
}
}
}
fn print(&self)
{
println!("-----");
for led in 0..config::NUM_LEDS_PER_STRIP {
for strip in 0..config::NUM_STRIPS {
print!("{:8.3} ", self.energy[strip][led]);
}
println!();
}
println!("-END-");
}
fn get_energy(&self, strip: usize, led: usize) -> f32
{
self.energy[strip][led]
}
}
// Merges multiple single-colored flames in a multi-colored one.
pub struct Fire
{
r_flame: Flame,
g_flame: Flame,
b_flame: Flame,
w_flame: Flame,
max_energy: Color,
colorlists: [ [Color; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS],
sigproc: Rc<RefCell<SignalProcessing>>,
}
impl Animation for Fire
{
fn new(sigproc: Rc<RefCell<SignalProcessing>>) -> Fire
{
Fire {
r_flame: Flame::new(),
g_flame: Flame::new(),
b_flame: Flame::new(),
w_flame: Flame::new(),
max_energy: Color{r: 1.0, g: 1.0, b: 1.0, w: 1.0},
colorlists: [ [Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0}; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS],
sigproc: sigproc,
}
}
fn init(&mut self) -> Result<()>
{
Ok(())
}
fn periodic(&mut self) -> Result<()>
{
let sigproc = self.sigproc.borrow();
// extract frequency band energies
let cur_energy = Color{
r: sigproc.get_energy_in_band( 0.0, 400.0),
g: sigproc.get_energy_in_band( 400.0, 4000.0),
b: sigproc.get_energy_in_band( 4000.0, 12000.0),
w: sigproc.get_energy_in_band(12000.0, 22000.0)};
// track the maximum energy with cooldown
self.max_energy.r *= COOLDOWN_FACTOR;
if cur_energy.r > self.max_energy.r {
self.max_energy.r = cur_energy.r;
}
self.max_energy.g *= COOLDOWN_FACTOR;
if cur_energy.g > self.max_energy.g {
self.max_energy.g = cur_energy.g;
}
self.max_energy.b *= COOLDOWN_FACTOR;
if cur_energy.b > self.max_energy.b {
self.max_energy.b = cur_energy.b;
}
self.max_energy.w *= COOLDOWN_FACTOR;
if cur_energy.w > self.max_energy.w {
self.max_energy.w = cur_energy.w;
}
// update the flames
self.r_flame.update((cur_energy.r / self.max_energy.r).powf(EXPONENT));
self.g_flame.update((cur_energy.g / self.max_energy.g).powf(EXPONENT));
self.b_flame.update((cur_energy.b / self.max_energy.b).powf(EXPONENT));
self.w_flame.update((cur_energy.w / self.max_energy.w).powf(W_EXPONENT));
//self.r_flame.print();
// color rendering and post-processing
for strip in 0..config::NUM_STRIPS {
for led in 0..config::NUM_LEDS_PER_STRIP {
self.colorlists[strip][led] = Color {
r: self.r_flame.get_energy(strip, led),
g: self.g_flame.get_energy(strip, led),
b: self.b_flame.get_energy(strip, led),
w: self.w_flame.get_energy(strip, led) * W_SCALE
};
self.colorlists[strip][led].limit();
}
}
Ok(())
}
fn get_colorlist(&self) -> &[ [Color; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS]
{
return &self.colorlists;
}
}

View File

@ -1,396 +0,0 @@
// vim: noet
use crate::animation::{Color, Animation, Result};
use crate::signal_processing::SignalProcessing;
use crate::config;
use std::rc::Rc;
use std::cell::RefCell;
use rand::Rng;
const COOLDOWN_FACTOR : f32 = 0.99980;
const RGB_EXPONENT : f32 = 1.5;
const W_EXPONENT : f32 = 2.2;
const W_SCALE : f32 = 0.3;
const ENERGY_FILTER_ALPHA : f32 = 0.20;
const BRIGHTNESS_FILTER_ALPHA : f32 = 0.10;
<<<<<<< Updated upstream
const NUM_RACERS_R : usize = 20 * config::NUM_LEDS_TOTAL / 300;
const NUM_RACERS_G : usize = 20 * config::NUM_LEDS_TOTAL / 300;
const NUM_RACERS_B : usize = 20 * config::NUM_LEDS_TOTAL / 300;
=======
const NUM_RACERS_R : usize = 20;
const NUM_RACERS_G : usize = 20;
const NUM_RACERS_B : usize = 20;
>>>>>>> Stashed changes
const RACER_MIN_SPEED_R : f32 = 0.5 / config::FPS_ANIMATION;
const RACER_MAX_SPEED_R : f32 = 60.0 / config::FPS_ANIMATION;
const RACER_MIN_BRIGHTNESS_R : f32 = 0.01;
const RACER_MAX_BRIGHTNESS_R : f32 = 1.00;
const RACER_MIN_SPEED_G : f32 = 0.5 / config::FPS_ANIMATION;
const RACER_MAX_SPEED_G : f32 = 60.0 / config::FPS_ANIMATION;
const RACER_MIN_BRIGHTNESS_G : f32 = 0.01;
const RACER_MAX_BRIGHTNESS_G : f32 = 1.00;
const RACER_MIN_SPEED_B : f32 = 0.5 / config::FPS_ANIMATION;
const RACER_MAX_SPEED_B : f32 = 60.0 / config::FPS_ANIMATION;
const RACER_MIN_BRIGHTNESS_B : f32 = 0.01;
const RACER_MAX_BRIGHTNESS_B : f32 = 1.00;
const SPEED_SCALE_RANGE : f32 = 0.10;
fn dbg_bar(min: f32, current: f32, max: f32)
{
const LEN: usize = 60;
let mut bar = ['.'; LEN];
let minpos = ((LEN as f32) * min / max) as usize;
let curpos = ((LEN as f32) * current / max) as usize;
for idx in minpos..LEN {
bar[idx] = '-';
}
if curpos < LEN {
bar[curpos] = '#';
}
print!("{}", bar.iter().collect::<String>());
}
/*
* A racer is a point of light that can move along the LED strips.
*/
struct Racer
{
min_speed: f32, // LEDs per frame
max_speed: f32, // LEDs per frame
direction: i8, // either +1 or -1
min_brightness: f32,
max_brightness: f32,
color: Color,
pos: f32,
brightness: f32,
flare_brightness: f32,
}
impl Racer
{
pub fn new(min_speed: f32, max_speed: f32, min_brightness: f32, max_brightness: f32, color: Color, start_pos: f32, direction: i8) -> Racer
{
Racer {
min_speed: min_speed,
max_speed: max_speed,
min_brightness: min_brightness,
max_brightness: max_brightness,
direction: direction,
color: color,
pos: start_pos,
brightness: min_brightness,
flare_brightness: 0.0,
}
}
fn _pos2ledstrip(pos: i32) -> (i32, i32)
{
let strip = pos / (config::NUM_LEDS_PER_STRIP as i32);
let mut led = pos % (config::NUM_LEDS_PER_STRIP as i32);
if (strip % 2) == 1 {
led = (config::NUM_LEDS_PER_STRIP as i32) - led - 1;
}
(strip, led)
}
pub fn update(&mut self, brightness: f32, flare_brightness: f32)
{
// move along the strip
let cur_speed = self.min_speed + brightness * (self.max_speed - self.min_speed);
self.pos += (self.direction as f32) * cur_speed;
let maxpos = config::NUM_LEDS_TOTAL as f32;
// if the end is reached, reverse the direction
if self.pos >= maxpos {
self.direction = -1;
self.pos = 2.0 * maxpos - self.pos;
} else if self.pos <= 0.0 {
self.direction = 1;
self.pos = -self.pos;
}
self.brightness = brightness;
self.flare_brightness = flare_brightness;
}
pub fn render(&self, colorlists: &mut [ [Color; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS])
{
let brightness = self.min_brightness + self.brightness * (self.max_brightness - self.min_brightness);
let fract_led = self.pos - self.pos.floor();
let led1_idx = self.pos.floor() as i32;
let led2_idx = self.pos.ceil() as i32;
let mut color = self.color;
color.w += self.flare_brightness;
let led1_color = color.scaled_copy((1.0 - fract_led) * brightness);
let led2_color = color.scaled_copy(fract_led * brightness);
if led1_idx >= 0 && led1_idx < (config::NUM_LEDS_TOTAL as i32) {
let (strip, led) = Racer::_pos2ledstrip(led1_idx);
colorlists[strip as usize][led as usize].add(&led1_color);
}
if led2_idx >= 0 && led2_idx < (config::NUM_LEDS_TOTAL as i32) {
let (strip, led) = Racer::_pos2ledstrip(led2_idx);
colorlists[strip as usize][led as usize].add(&led2_color);
}
}
}
pub struct Racers
{
max_energy : Color,
min_energy : Color,
filtered_energy : Color,
filtered_brightness : Color,
racers_r : Vec<Racer>,
racers_g : Vec<Racer>,
racers_b : Vec<Racer>,
colorlists : [ [Color; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS],
frame_count: usize,
sigproc: Rc<RefCell<SignalProcessing>>,
}
impl Animation for Racers
{
fn new(sigproc: Rc<RefCell<SignalProcessing>>) -> Racers
{
Racers {
max_energy: Color{r: 1.0, g: 1.0, b: 1.0, w: 1.0},
min_energy: Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0},
filtered_energy: Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0},
filtered_brightness: Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0},
racers_r: Vec::with_capacity(NUM_RACERS_R),
racers_g: Vec::with_capacity(NUM_RACERS_G),
racers_b: Vec::with_capacity(NUM_RACERS_B),
colorlists: [ [Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0}; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS],
sigproc: sigproc,
frame_count: 0,
}
}
fn init(&mut self) -> Result<()>
{
let mut rng = rand::thread_rng();
for _i in 0 .. NUM_RACERS_R {
let start_pos = rng.gen::<f32>() * (config::NUM_LEDS_TOTAL as f32);
let speed_scale = 1.0 + SPEED_SCALE_RANGE * (rng.gen::<f32>() - 0.5);
let mut dir = rng.gen::<i8>();
if dir > 0 {
dir = 1;
} else {
dir = -1;
}
self.racers_r.push(Racer::new(
RACER_MIN_SPEED_R * speed_scale,
RACER_MAX_SPEED_R * speed_scale,
RACER_MIN_BRIGHTNESS_R,
RACER_MAX_BRIGHTNESS_R,
Color{r: 1.0, g: 0.0, b: 0.0, w: 0.0},
start_pos,
dir));
}
for _i in 0 .. NUM_RACERS_G {
let start_pos = rng.gen::<f32>() * (config::NUM_LEDS_TOTAL as f32);
let speed_scale = 1.0 + SPEED_SCALE_RANGE * (rng.gen::<f32>() - 0.5);
let mut dir = rng.gen::<i8>();
if dir > 0 {
dir = 1;
} else {
dir = -1;
}
self.racers_g.push(Racer::new(
RACER_MIN_SPEED_G * speed_scale,
RACER_MAX_SPEED_G * speed_scale,
RACER_MIN_BRIGHTNESS_G,
RACER_MAX_BRIGHTNESS_G,
Color{r: 0.0, g: 1.0, b: 0.0, w: 0.0},
start_pos,
dir));
}
for _i in 0 .. NUM_RACERS_B {
let start_pos = rng.gen::<f32>() * (config::NUM_LEDS_TOTAL as f32);
let speed_scale = 1.0 + SPEED_SCALE_RANGE * (rng.gen::<f32>() - 0.5);
let mut dir = rng.gen::<i8>();
if dir > 0 {
dir = 1;
} else {
dir = -1;
}
self.racers_b.push(Racer::new(
RACER_MIN_SPEED_B * speed_scale,
RACER_MAX_SPEED_B * speed_scale,
RACER_MIN_BRIGHTNESS_B,
RACER_MAX_BRIGHTNESS_B,
Color{r: 0.0, g: 0.0, b: 1.0, w: 0.0},
start_pos,
dir));
}
Ok(())
}
fn periodic(&mut self) -> Result<()>
{
let sigproc = self.sigproc.borrow();
// extract frequency band energies
let cur_energy = Color{
r: sigproc.get_energy_in_band( 0.0, 400.0),
g: sigproc.get_energy_in_band( 400.0, 4000.0),
b: sigproc.get_energy_in_band( 4000.0, 12000.0),
w: sigproc.get_energy_in_band(12000.0, 22000.0)};
for i in 0..4 {
let f = self.filtered_energy.ref_by_index_mut(i).unwrap();
let n = cur_energy.ref_by_index(i).unwrap();
*f = (1.0 - ENERGY_FILTER_ALPHA) * (*f) + ENERGY_FILTER_ALPHA * (*n);
}
// track the maximum energy with cooldown
self.max_energy.r *= COOLDOWN_FACTOR;
if self.filtered_energy.r > self.max_energy.r {
self.max_energy.r = self.filtered_energy.r;
}
self.max_energy.g *= COOLDOWN_FACTOR;
if self.filtered_energy.g > self.max_energy.g {
self.max_energy.g = self.filtered_energy.g;
}
self.max_energy.b *= COOLDOWN_FACTOR;
if self.filtered_energy.b > self.max_energy.b {
self.max_energy.b = self.filtered_energy.b;
}
self.max_energy.w *= COOLDOWN_FACTOR;
if self.filtered_energy.w > self.max_energy.w {
self.max_energy.w = self.filtered_energy.w;
}
// track the minimum energy with warmup
self.min_energy.r += (1.0 - COOLDOWN_FACTOR) * (self.max_energy.r * 0.5 - self.min_energy.r);
if self.filtered_energy.r < self.min_energy.r {
self.min_energy.r = self.filtered_energy.r;
}
self.min_energy.g += (1.0 - COOLDOWN_FACTOR) * (self.max_energy.g * 0.5 - self.min_energy.g);
if self.filtered_energy.g < self.min_energy.g {
self.min_energy.g = self.filtered_energy.g;
}
self.min_energy.b += (1.0 - COOLDOWN_FACTOR) * (self.max_energy.b * 0.5 - self.min_energy.b);
if self.filtered_energy.b < self.min_energy.b {
self.min_energy.b = self.filtered_energy.b;
}
self.min_energy.w += (1.0 - COOLDOWN_FACTOR) * (self.max_energy.w * 0.5 - self.min_energy.w);
if self.filtered_energy.w < self.min_energy.w {
self.min_energy.w = self.filtered_energy.w;
}
// set all LEDs initially to black
for strip in 0..config::NUM_STRIPS {
for led in 0..config::NUM_LEDS_PER_STRIP {
//self.colorlists[strip][led].scale(FADE_FACTOR);
self.colorlists[strip][led] = Color{r: 0.0, g: 0.0, b: 0.0, w: 0.0};
}
}
// rescaling and normalization of the energies
let brightness = Color{
r: ((self.filtered_energy.r - self.min_energy.r) / (self.max_energy.r - self.min_energy.r)).powf(RGB_EXPONENT),
g: ((self.filtered_energy.g - self.min_energy.g) / (self.max_energy.g - self.min_energy.g)).powf(RGB_EXPONENT),
b: ((self.filtered_energy.b - self.min_energy.b) / (self.max_energy.b - self.min_energy.b)).powf(RGB_EXPONENT),
w: ((self.filtered_energy.w - self.min_energy.w) / (self.max_energy.w - self.min_energy.w)).powf(W_EXPONENT) * W_SCALE,
};
// lowpass-filter brightness to reduce intensive fast flashing
for i in 0..4 {
let f = self.filtered_brightness.ref_by_index_mut(i).unwrap();
let n = brightness.ref_by_index(i).unwrap();
*f = (1.0 - BRIGHTNESS_FILTER_ALPHA) * (*f) + BRIGHTNESS_FILTER_ALPHA * (*n);
}
// update all racers
let f = &self.filtered_brightness;
self.racers_r.iter_mut().for_each(|x| x.update(f.r, f.w));
self.racers_g.iter_mut().for_each(|x| x.update(f.g, f.w));
self.racers_b.iter_mut().for_each(|x| x.update(f.b, f.w));
// render all racers
for racer in self.racers_r.iter() {
racer.render(&mut self.colorlists);
}
for racer in self.racers_g.iter() {
racer.render(&mut self.colorlists);
}
for racer in self.racers_b.iter() {
racer.render(&mut self.colorlists);
}
// color post-processing
for strip in 0..config::NUM_STRIPS {
for led in 0..config::NUM_LEDS_PER_STRIP {
self.colorlists[strip][led].limit();
}
}
// debug stuff
self.frame_count += 1;
if self.frame_count % 100 == 0 {
println!("---");
print!("Red "); dbg_bar(self.min_energy.r, self.filtered_brightness.r, self.max_energy.r); println!("{:11.2}", self.max_energy.r);
print!("Green "); dbg_bar(self.min_energy.g, self.filtered_brightness.g, self.max_energy.g); println!("{:11.2}", self.max_energy.g);
print!("Blue "); dbg_bar(self.min_energy.b, self.filtered_brightness.b, self.max_energy.b); println!("{:11.2}", self.max_energy.b);
print!("White "); dbg_bar(self.min_energy.w, self.filtered_brightness.w, self.max_energy.w); println!("{:11.2}", self.max_energy.w);
}
Ok(())
}
fn get_colorlist(&self) -> &[ [Color; config::NUM_LEDS_PER_STRIP]; config::NUM_STRIPS]
{
return &self.colorlists;
}
}

View File

@ -6,16 +6,16 @@ pub const SAMP_RATE: f32 = 48000.0;
pub const SAMPLES_PER_UPDATE: usize = BLOCK_LEN/2;
// LED configuration
pub const NUM_STRIPS: usize = 8;
pub const NUM_LEDS_PER_STRIP: usize = 16;
pub const NUM_STRIPS: usize = 1;
pub const NUM_LEDS_PER_STRIP: usize = 322;
pub const NUM_LEDS_TOTAL: usize = NUM_STRIPS * NUM_LEDS_PER_STRIP;
// network configuration
pub const UDP_SERVER_ADDR: &str = "192.168.23.118:2703";
pub const UDP_SERVER_ADDR: &str = "wled1:21324";
pub const FPS_ANIMATION: f32 = SAMP_RATE / SAMPLES_PER_UPDATE as f32;
pub const FPS_LEDS: f32 = 60.0;
pub const FPS_LEDS: f32 = 30.0;
// “standby mode” configuration
pub const STANDBY_MAX_SILENT_SAMPLES: usize = SAMP_RATE as usize;

View File

@ -25,7 +25,7 @@ fn main()
let mut stdin = std::io::stdin();
// set up the UDP protocol
let mut udpproto = match UdpProto::new(config::UDP_SERVER_ADDR) {
let mut udpproto = match UdpProto::new(config::UDP_SERVER_ADDR, config::NUM_LEDS_TOTAL) {
Ok(u) => u,
Err(e) => {
println!("Error during UDP client setup:\n{}", e);
@ -45,8 +45,7 @@ fn main()
// TODO: let the user select via the command line
//let mut anim: animation::particles::Particles = animation::Animation::new(sigproc.clone());
//let mut anim: animation::sparkles::Sparkles = animation::Animation::new(sigproc.clone());
//let mut anim: animation::racers::Racers = animation::Animation::new(sigproc.clone());
let mut anim: animation::fire::Fire = animation::Animation::new(sigproc.clone());
let mut anim: animation::racers::Racers = animation::Animation::new(sigproc.clone());
println!("Calling Animation::init()...");
@ -136,7 +135,7 @@ fn main()
let led = i % config::NUM_LEDS_PER_STRIP;
let r = udpproto.set_color(strip as u8,
led as u8,
led,
(colorlists[strip][led].r * 255.0) as u8,
(colorlists[strip][led].g * 255.0) as u8,
(colorlists[strip][led].b * 255.0) as u8,

View File

@ -5,6 +5,8 @@ use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
const MAX_PACKET_LEN: usize = 1470;
const TIMEOUT_SEC: u8 = 3;
const WLED_MODE_DRGBW: u8 = 3;
struct Command
{
@ -17,103 +19,45 @@ struct Command
pub struct UdpProto
{
socket: UdpSocket,
packet: [u8; MAX_PACKET_LEN],
packet_offset: usize,
packet: Vec<u8>,
}
impl UdpProto
{
pub fn new(target_address: &str) -> std::io::Result<UdpProto>
pub fn new(target_address: &str, num_leds_total: usize) -> std::io::Result<UdpProto>
{
let u = UdpProto {
let mut u = UdpProto {
socket: UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))?,
packet: [0u8; MAX_PACKET_LEN],
packet_offset: 0,
packet: vec![0; 2 + 4*num_leds_total],
};
u.packet[0] = WLED_MODE_DRGBW;
u.packet[1] = TIMEOUT_SEC;
u.socket.connect(target_address)?;
Ok(u)
}
fn send_packet(&mut self) -> std::io::Result<()>
{
if self.packet_offset == 0 {
// nothing to do
return Ok( () );
}
self.socket.send(&self.packet[0..self.packet_offset])?;
self.packet_offset = 0;
Ok( () )
}
fn add_command(&mut self, cmd: u8, strip: u8, led: u8, data: &[u8; 4]) -> std::io::Result<()>
{
// put the command into the packet buffer
self.packet[self.packet_offset + 0] = cmd;
self.packet[self.packet_offset + 1] = strip;
self.packet[self.packet_offset + 2] = led;
for i in 0 .. data.len() {
self.packet[self.packet_offset + i + 3] = data[i];
}
self.packet_offset += 7;
if self.packet_offset >= MAX_PACKET_LEN-7 {
self.send_packet()?;
}
Ok( () )
}
pub fn set_color(&mut self, strip: u8, led: u8,
pub fn set_color(&mut self, _strip: u8, led: usize,
r: u8, g: u8, b: u8, w: u8) -> std::io::Result<()>
{
let data = [r,g,b,w];
self.add_command(0x00, strip, led, &data)?;
Ok( () )
}
pub fn fade_color(&mut self, strip: u8, led: u8,
r: u8, g: u8, b: u8, w: u8) -> std::io::Result<()>
{
let data = [r,g,b,w];
self.add_command(0x01, strip, led, &data)?;
Ok( () )
}
pub fn add_color(&mut self, strip: u8, led: u8,
r: u8, g: u8, b: u8, w: u8) -> std::io::Result<()>
{
let data = [r,g,b,w];
self.add_command(0x02, strip, led, &data)?;
Ok( () )
}
pub fn set_fadestep(&mut self, fadestep: u8) -> std::io::Result<()>
{
let data = [fadestep, 0, 0, 0];
self.add_command(0x03, 0, 0, &data)?;
Ok( () )
let offset = 2 + 4*led;
if offset > self.packet.len() {
Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "LED index out of range"))
}
else {
self.packet[offset + 0] = r;
self.packet[offset + 1] = g;
self.packet[offset + 2] = b;
self.packet[offset + 3] = w;
Ok( () )
}
}
pub fn commit(&mut self) -> std::io::Result<()>
{
// add the END_OF_UPDATE command
self.add_command(0xFE, 0, 0, &[0u8; 4])?;
self.send_packet()
self.socket.send(&self.packet)?;
Ok( () )
}
}