mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-09-27 12:21:02 +00:00
Refactor Rgb struct (#265)
* Refactor Rgb struct Moves hsv convertion into an associated function and further implements From<Rgb> for u32. * Update rmt_neopixel.rs * Replace if-else with pattern matching
This commit is contained in:
parent
c03ec8199b
commit
091128a282
@ -28,27 +28,35 @@ fn main() -> Result<()> {
|
||||
let mut tx = TxRmtDriver::new(channel, led, &config)?;
|
||||
|
||||
// 3 seconds white at 10% brightness
|
||||
neopixel(
|
||||
Rgb {
|
||||
r: 25,
|
||||
g: 25,
|
||||
b: 25,
|
||||
},
|
||||
&mut tx,
|
||||
)?;
|
||||
neopixel(Rgb::new(25, 25, 25), &mut tx)?;
|
||||
FreeRtos::delay_ms(3000);
|
||||
|
||||
// rainbow loop at 20% brightness
|
||||
let mut i: u32 = 0;
|
||||
loop {
|
||||
let rgb = hsv2rgb(i, 100, 20)?;
|
||||
neopixel(rgb, &mut tx)?;
|
||||
if i == 360 {
|
||||
i = 0;
|
||||
}
|
||||
i += 1;
|
||||
// infinite rainbow loop at 20% brightness
|
||||
(0..360).cycle().try_for_each(|hue| {
|
||||
FreeRtos::delay_ms(10);
|
||||
let rgb = Rgb::from_hsv(hue, 100, 20)?;
|
||||
neopixel(rgb, &mut tx)
|
||||
})
|
||||
}
|
||||
|
||||
fn neopixel(rgb: Rgb, tx: &mut TxRmtDriver) -> Result<()> {
|
||||
let color: u32 = rgb.into();
|
||||
let ticks_hz = tx.counter_clock()?;
|
||||
let (t0h, t0l, t1h, t1l) = (
|
||||
Pulse::new_with_duration(ticks_hz, PinState::High, &Duration::from_nanos(350))?,
|
||||
Pulse::new_with_duration(ticks_hz, PinState::Low, &Duration::from_nanos(800))?,
|
||||
Pulse::new_with_duration(ticks_hz, PinState::High, &Duration::from_nanos(700))?,
|
||||
Pulse::new_with_duration(ticks_hz, PinState::Low, &Duration::from_nanos(600))?,
|
||||
);
|
||||
let mut signal = FixedLengthSignal::<24>::new();
|
||||
for i in (0..24).rev() {
|
||||
let p = 2_u32.pow(i);
|
||||
let bit: bool = p & color != 0;
|
||||
let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) };
|
||||
signal.set(23 - i as usize, &(high_pulse, low_pulse))?;
|
||||
}
|
||||
tx.start_blocking(&signal)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Rgb {
|
||||
@ -57,73 +65,44 @@ struct Rgb {
|
||||
b: u8,
|
||||
}
|
||||
|
||||
fn ns(nanos: u64) -> Duration {
|
||||
Duration::from_nanos(nanos)
|
||||
impl Rgb {
|
||||
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
Self { r, g, b }
|
||||
}
|
||||
/// Converts hue, saturation, value to RGB
|
||||
pub fn from_hsv(h: u32, s: u32, v: u32) -> Result<Self> {
|
||||
if h > 360 || s > 100 || v > 100 {
|
||||
bail!("The given HSV values are not in valid range");
|
||||
}
|
||||
let s = s as f64 / 100.0;
|
||||
let v = v as f64 / 100.0;
|
||||
let c = s * v;
|
||||
let x = c * (1.0 - (((h as f64 / 60.0) % 2.0) - 1.0).abs());
|
||||
let m = v - c;
|
||||
let (r, g, b) = match h {
|
||||
0..=59 => (c, x, 0.0),
|
||||
60..=119 => (x, c, 0.0),
|
||||
120..=179 => (0.0, c, x),
|
||||
180..=239 => (0.0, x, c),
|
||||
240..=299 => (x, 0.0, c),
|
||||
_ => (c, 0.0, x),
|
||||
};
|
||||
Ok(Self {
|
||||
r: ((r + m) * 255.0) as u8,
|
||||
g: ((g + m) * 255.0) as u8,
|
||||
b: ((b + m) * 255.0) as u8,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn neopixel(rgb: Rgb, tx: &mut TxRmtDriver) -> Result<()> {
|
||||
// e.g. rgb: (1,2,4)
|
||||
// G R B
|
||||
// 7 0 7 0 7 0
|
||||
// 00000010 00000001 00000100
|
||||
let color: u32 = ((rgb.g as u32) << 16) | ((rgb.r as u32) << 8) | rgb.b as u32;
|
||||
let ticks_hz = tx.counter_clock()?;
|
||||
let t0h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(350))?;
|
||||
let t0l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(800))?;
|
||||
let t1h = Pulse::new_with_duration(ticks_hz, PinState::High, &ns(700))?;
|
||||
let t1l = Pulse::new_with_duration(ticks_hz, PinState::Low, &ns(600))?;
|
||||
let mut signal = FixedLengthSignal::<24>::new();
|
||||
for i in (0..24).rev() {
|
||||
let p = 2_u32.pow(i);
|
||||
let bit = p & color != 0;
|
||||
let (high_pulse, low_pulse) = if bit { (t1h, t1l) } else { (t0h, t0l) };
|
||||
signal.set(23 - i as usize, &(high_pulse, low_pulse))?;
|
||||
impl From<Rgb> for u32 {
|
||||
/// Convert RGB to u32 color value
|
||||
///
|
||||
/// e.g. rgb: (1,2,4)
|
||||
/// G R B
|
||||
/// 7 0 7 0 7 0
|
||||
/// 00000010 00000001 00000100
|
||||
fn from(rgb: Rgb) -> Self {
|
||||
((rgb.r as u32) << 16) | ((rgb.g as u32) << 8) | rgb.b as u32
|
||||
}
|
||||
tx.start_blocking(&signal)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts hue, saturation, value to RGB
|
||||
fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<Rgb> {
|
||||
if h > 360 || s > 100 || v > 100 {
|
||||
bail!("The given HSV values are not in valid range");
|
||||
}
|
||||
let s = s as f64 / 100.0;
|
||||
let v = v as f64 / 100.0;
|
||||
let c = s * v;
|
||||
let x = c * (1.0 - (((h as f64 / 60.0) % 2.0) - 1.0).abs());
|
||||
let m = v - c;
|
||||
let (r, g, b);
|
||||
if h < 60 {
|
||||
r = c;
|
||||
g = x;
|
||||
b = 0.0;
|
||||
} else if (60..120).contains(&h) {
|
||||
r = x;
|
||||
g = c;
|
||||
b = 0.0;
|
||||
} else if (120..180).contains(&h) {
|
||||
r = 0.0;
|
||||
g = c;
|
||||
b = x;
|
||||
} else if (180..240).contains(&h) {
|
||||
r = 0.0;
|
||||
g = x;
|
||||
b = c;
|
||||
} else if (240..300).contains(&h) {
|
||||
r = x;
|
||||
g = 0.0;
|
||||
b = c;
|
||||
} else {
|
||||
r = c;
|
||||
g = 0.0;
|
||||
b = x;
|
||||
}
|
||||
|
||||
Ok(Rgb {
|
||||
r: ((r + m) * 255.0) as u8,
|
||||
g: ((g + m) * 255.0) as u8,
|
||||
b: ((b + m) * 255.0) as u8,
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user