Skip to content

Commit 2bd317a

Browse files
llewelldsgreenbury
andcommitted
Update RGBLED digital implementation
Co-authored-by: Sam Greenbury <[email protected]>
1 parent 1a9aa5d commit 2bd317a

File tree

4 files changed

+231
-16
lines changed

4 files changed

+231
-16
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ edition = "2018"
1616

1717
[dependencies]
1818
rppal = "0.12.0"
19-
19+
palette = "0.7.3"

examples/blink_rgb.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
//! Blinks an LED : on_time: 2 seconds and off_time: 3 seconds
22
3+
use palette::rgb::Rgb;
34
use rust_gpiozero::*;
5+
use std::{thread, time};
46

57
fn main() {
68
// Create a new LED attached to Pin 17
7-
let mut led = RGBLED::new(23, 24, 25);
9+
let mut led = RGBLED::new(12, 19, 13);
810

9-
// on_time = 2 secs, off_time=3 secs
10-
led.red.blink(0.11, 0.05);
11-
led.green.blink(0.7, 0.17);
12-
led.blue.blink(0.23, 0.03);
11+
// Display some colours for half a second each
12+
led.set_color(Rgb::new(1.0, 1.0, 0.0));
13+
thread::sleep(time::Duration::from_millis(500));
14+
led.set_color(Rgb::new(0.0, 1.0, 0.0));
15+
thread::sleep(time::Duration::from_millis(500));
16+
led.set_color(Rgb::new(0.0, 1.0, 1.0));
17+
thread::sleep(time::Duration::from_millis(500));
1318

14-
// prevent program from exiting immediately
15-
led.red.wait();
16-
led.green.wait();
17-
led.blue.wait();
19+
// Blink five times
20+
led.set_blink_count(5);
21+
led.blink(0.5, 0.2, Rgb::new(1.0, 1.0, 0.0), Rgb::new(0.0, 0.0, 1.0));
22+
led.wait();
23+
led.off();
24+
25+
// Stay off for a second
26+
thread::sleep(time::Duration::from_millis(1000));
27+
28+
// Blink ten times
29+
led.set_blink_count(10);
30+
led.blink(0.2, 0.5, Rgb::new(1.0, 1.0, 1.0), Rgb::new(1.0, 0.0, 0.0));
31+
led.wait();
32+
33+
// Show white for two seconds
34+
led.on();
35+
led.set_color(Rgb::new(1.0, 1.0, 1.0));
36+
thread::sleep(time::Duration::from_millis(2000));
37+
led.off();
1838
}

src/devices.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ macro_rules! impl_device {
3131
pub struct GpioDevice {
3232
pin: Pin,
3333
active_state: bool,
34+
#[allow(dead_code)]
3435
inactive_state: bool,
3536
}
3637

src/output_devices.rs

Lines changed: 200 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Output device component interfaces for devices such as `LED`, `PWMLED`, etc
2+
use palette::rgb::Rgb;
23
use rppal::gpio::{Gpio, IoPin, Level, Mode};
34
use std::sync::atomic::{AtomicBool, Ordering};
45
use std::sync::Arc;
@@ -257,19 +258,212 @@ impl DigitalOutputDevice {
257258
}
258259

259260
pub struct RGBLED {
260-
pub red: LED,
261-
pub green: LED,
262-
pub blue: LED,
261+
devices: [Arc<Mutex<OutputDevice>>; 3],
262+
blinking: Arc<AtomicBool>,
263+
handle: Option<JoinHandle<()>>,
264+
blink_count: Option<i32>,
263265
}
264266

265267
impl RGBLED {
266268
pub fn new(pin_red: u8, pin_green: u8, pin_blue: u8) -> RGBLED {
267269
RGBLED {
268-
red: LED::new(pin_red),
269-
green: LED::new(pin_green),
270-
blue: LED::new(pin_blue),
270+
devices: [
271+
Arc::new(Mutex::new(OutputDevice::new(pin_red))),
272+
Arc::new(Mutex::new(OutputDevice::new(pin_green))),
273+
Arc::new(Mutex::new(OutputDevice::new(pin_blue))),
274+
],
275+
blinking: Arc::new(AtomicBool::new(false)),
276+
handle: None,
277+
blink_count: None,
278+
}
279+
}
280+
281+
pub fn set_color(&mut self, color: Rgb) {
282+
Self::write_color(&self.devices, color);
283+
}
284+
285+
fn write_color(devices: &[Arc<Mutex<OutputDevice>>; 3], color: Rgb) {
286+
Self::write_state(&devices[0], color.red > 0.5);
287+
Self::write_state(&devices[1], color.green > 0.5);
288+
Self::write_state(&devices[2], color.blue > 0.5);
289+
}
290+
291+
fn write_state(device: &Arc<Mutex<OutputDevice>>, value: bool) {
292+
if device.lock().unwrap().value_to_state(value) {
293+
device.lock().unwrap().pin.set_high()
294+
} else {
295+
device.lock().unwrap().pin.set_low()
296+
}
297+
}
298+
299+
fn blinker(
300+
&mut self,
301+
on_time: f32,
302+
off_time: f32,
303+
on_color: Rgb,
304+
off_color: Rgb,
305+
n: Option<i32>,
306+
) {
307+
self.stop();
308+
309+
let devices = [
310+
Arc::clone(&self.devices[0]),
311+
Arc::clone(&self.devices[1]),
312+
Arc::clone(&self.devices[2]),
313+
];
314+
let blinking = Arc::clone(&self.blinking);
315+
316+
self.handle = Some(thread::spawn(move || {
317+
blinking.store(true, Ordering::SeqCst);
318+
match n {
319+
Some(end) => {
320+
for _ in 0..end {
321+
if !blinking.load(Ordering::SeqCst) {
322+
devices[0].lock().unwrap().off();
323+
devices[1].lock().unwrap().off();
324+
devices[2].lock().unwrap().off();
325+
break;
326+
}
327+
Self::write_color(&devices, on_color);
328+
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
329+
Self::write_color(&devices, off_color);
330+
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
331+
}
332+
}
333+
None => loop {
334+
if !blinking.load(Ordering::SeqCst) {
335+
devices[0].lock().unwrap().off();
336+
devices[1].lock().unwrap().off();
337+
devices[2].lock().unwrap().off();
338+
break;
339+
}
340+
Self::write_color(&devices, on_color);
341+
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
342+
Self::write_color(&devices, off_color);
343+
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
344+
},
345+
}
346+
}));
347+
}
348+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
349+
pub fn is_active(&self) -> bool {
350+
self.devices[0].lock().unwrap().is_active()
351+
|| self.devices[1].lock().unwrap().is_active()
352+
|| self.devices[2].lock().unwrap().is_active()
353+
}
354+
/// Turns the device on.
355+
pub fn on(&self) {
356+
self.stop();
357+
self.devices[0].lock().unwrap().on();
358+
self.devices[1].lock().unwrap().on();
359+
self.devices[2].lock().unwrap().on();
360+
}
361+
/// Turns the device off.
362+
pub fn off(&self) {
363+
self.stop();
364+
self.devices[0].lock().unwrap().off();
365+
self.devices[1].lock().unwrap().off();
366+
self.devices[2].lock().unwrap().off();
367+
}
368+
/// Reverse the state of the device. If it's on, turn it off; if it's off, turn it on.
369+
pub fn toggle(&mut self) {
370+
if self.is_active() {
371+
self.on()
372+
} else {
373+
self.off()
271374
}
272375
}
376+
377+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
378+
pub fn value_red(&self) -> bool {
379+
self.devices[0].lock().unwrap().value()
380+
}
381+
382+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
383+
pub fn value_green(&self) -> bool {
384+
self.devices[1].lock().unwrap().value()
385+
}
386+
387+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
388+
pub fn value_blue(&self) -> bool {
389+
self.devices[2].lock().unwrap().value()
390+
}
391+
392+
fn stop(&self) {
393+
self.blinking.clone().store(false, Ordering::SeqCst);
394+
self.devices[0].lock().unwrap().pin.set_low();
395+
self.devices[1].lock().unwrap().pin.set_low();
396+
self.devices[2].lock().unwrap().pin.set_low();
397+
}
398+
399+
/// When ``True``, the `value` property is ``True`` when the device's
400+
/// `pin` is high. When ``False`` the `value` property is
401+
/// ``True`` when the device's pin is low (i.e. the value is inverted).
402+
/// Be warned that changing it will invert `value` (i.e. changing this property doesn't change
403+
/// the device's pin state - it just changes how that state is interpreted).
404+
pub fn active_high(&self) -> bool {
405+
self.devices[0].lock().unwrap().active_high()
406+
|| self.devices[1].lock().unwrap().active_high()
407+
|| self.devices[2].lock().unwrap().active_high()
408+
}
409+
410+
/// Set the state for active_high
411+
pub fn set_active_high(&mut self, value: bool) {
412+
self.devices[0].lock().unwrap().set_active_high(value);
413+
self.devices[1].lock().unwrap().set_active_high(value);
414+
self.devices[2].lock().unwrap().set_active_high(value);
415+
}
416+
417+
/// The `Pin` that the device is connected to.
418+
pub fn pin_red(&self) -> u8 {
419+
self.devices[0].lock().unwrap().pin.pin()
420+
}
421+
422+
/// The `Pin` that the device is connected to.
423+
pub fn pin_green(&self) -> u8 {
424+
self.devices[1].lock().unwrap().pin.pin()
425+
}
426+
427+
/// The `Pin` that the device is connected to.
428+
pub fn pin_blue(&self) -> u8 {
429+
self.devices[2].lock().unwrap().pin.pin()
430+
}
431+
432+
/// Shut down the device and release all associated resources.
433+
pub fn close(self) {
434+
drop(self)
435+
}
436+
437+
/// Block until background process is done
438+
pub fn wait(&mut self) {
439+
self.handle
440+
.take()
441+
.expect("Called stop on non-running thread")
442+
.join()
443+
.expect("Could not join spawned thread");
444+
}
445+
446+
/// Make the device turn on and off repeatedly in the background.
447+
/// Use `set_blink_count` to set the number of times to blink the device
448+
/// * `on_time` - Number of seconds on
449+
/// * `off_time` - Number of seconds off
450+
///
451+
pub fn blink(&mut self, on_time: f32, off_time: f32, on_color: Rgb, off_color: Rgb) {
452+
match self.blink_count {
453+
None => self.blinker(on_time, off_time, on_color, off_color, None),
454+
Some(n) => self.blinker(on_time, off_time, on_color, off_color, Some(n)),
455+
}
456+
}
457+
458+
/// Set the number of times to blink the device
459+
/// * `n` - Number of times to blink
460+
pub fn set_blink_count(&mut self, n: i32) {
461+
self.blink_count = Some(n)
462+
}
463+
464+
pub fn is_lit(&self) -> bool {
465+
self.is_active()
466+
}
273467
}
274468

275469
/// Represents a light emitting diode (LED)

0 commit comments

Comments
 (0)