Skip to content

Commit 09c9ab1

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

File tree

4 files changed

+224
-16
lines changed

4 files changed

+224
-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
33
use rust_gpiozero::*;
4+
use palette::rgb::Rgb;
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: 193 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::sync::Mutex;
66
use std::thread;
77
use std::thread::JoinHandle;
88
use std::time::Duration;
9+
use palette::rgb::Rgb;
910

1011
/// Represents a generic GPIO output device.
1112
#[derive(Debug)]
@@ -257,19 +258,205 @@ 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(&mut self, on_time: f32, off_time: f32, on_color: Rgb, off_color: Rgb, n: Option<i32>) {
300+
self.stop();
301+
302+
let devices = [
303+
Arc::clone(&self.devices[0]),
304+
Arc::clone(&self.devices[1]),
305+
Arc::clone(&self.devices[2]),
306+
];
307+
let blinking = Arc::clone(&self.blinking);
308+
309+
self.handle = Some(thread::spawn(move || {
310+
blinking.store(true, Ordering::SeqCst);
311+
match n {
312+
Some(end) => {
313+
for _ in 0..end {
314+
if !blinking.load(Ordering::SeqCst) {
315+
devices[0].lock().unwrap().off();
316+
devices[1].lock().unwrap().off();
317+
devices[2].lock().unwrap().off();
318+
break;
319+
}
320+
Self::write_color(&devices, on_color);
321+
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
322+
Self::write_color(&devices, off_color);
323+
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
324+
}
325+
}
326+
None => loop {
327+
if !blinking.load(Ordering::SeqCst) {
328+
devices[0].lock().unwrap().off();
329+
devices[1].lock().unwrap().off();
330+
devices[2].lock().unwrap().off();
331+
break;
332+
}
333+
Self::write_color(&devices, on_color);
334+
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
335+
Self::write_color(&devices, off_color);
336+
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
337+
},
338+
}
339+
}));
340+
}
341+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
342+
pub fn is_active(&self) -> bool {
343+
self.devices[0].lock().unwrap().is_active()
344+
|| self.devices[1].lock().unwrap().is_active()
345+
|| self.devices[2].lock().unwrap().is_active()
346+
}
347+
/// Turns the device on.
348+
pub fn on(&self) {
349+
self.stop();
350+
self.devices[0].lock().unwrap().on();
351+
self.devices[1].lock().unwrap().on();
352+
self.devices[2].lock().unwrap().on();
353+
}
354+
/// Turns the device off.
355+
pub fn off(&self) {
356+
self.stop();
357+
self.devices[0].lock().unwrap().off();
358+
self.devices[1].lock().unwrap().off();
359+
self.devices[2].lock().unwrap().off();
360+
}
361+
/// Reverse the state of the device. If it's on, turn it off; if it's off, turn it on.
362+
pub fn toggle(&mut self) {
363+
if self.is_active() {
364+
self.on()
365+
} else {
366+
self.off()
367+
}
368+
}
369+
370+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
371+
pub fn value_red(&self) -> bool {
372+
self.devices[0].lock().unwrap().value()
373+
}
374+
375+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
376+
pub fn value_green(&self) -> bool {
377+
self.devices[1].lock().unwrap().value()
378+
}
379+
380+
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
381+
pub fn value_blue(&self) -> bool {
382+
self.devices[2].lock().unwrap().value()
383+
}
384+
385+
fn stop(&self) {
386+
self.blinking.clone().store(false, Ordering::SeqCst);
387+
self.devices[0].lock().unwrap().pin.set_low();
388+
self.devices[1].lock().unwrap().pin.set_low();
389+
self.devices[2].lock().unwrap().pin.set_low();
390+
}
391+
392+
/// When ``True``, the `value` property is ``True`` when the device's
393+
/// `pin` is high. When ``False`` the `value` property is
394+
/// ``True`` when the device's pin is low (i.e. the value is inverted).
395+
/// Be warned that changing it will invert `value` (i.e. changing this property doesn't change
396+
/// the device's pin state - it just changes how that state is interpreted).
397+
pub fn active_high(&self) -> bool {
398+
self.devices[0].lock().unwrap().active_high()
399+
|| self.devices[1].lock().unwrap().active_high()
400+
|| self.devices[2].lock().unwrap().active_high()
401+
}
402+
403+
/// Set the state for active_high
404+
pub fn set_active_high(&mut self, value: bool) {
405+
self.devices[0].lock().unwrap().set_active_high(value);
406+
self.devices[1].lock().unwrap().set_active_high(value);
407+
self.devices[2].lock().unwrap().set_active_high(value);
408+
}
409+
410+
/// The `Pin` that the device is connected to.
411+
pub fn pin_red(&self) -> u8 {
412+
self.devices[0].lock().unwrap().pin.pin()
413+
}
414+
415+
/// The `Pin` that the device is connected to.
416+
pub fn pin_green(&self) -> u8 {
417+
self.devices[1].lock().unwrap().pin.pin()
418+
}
419+
420+
/// The `Pin` that the device is connected to.
421+
pub fn pin_blue(&self) -> u8 {
422+
self.devices[2].lock().unwrap().pin.pin()
423+
}
424+
425+
/// Shut down the device and release all associated resources.
426+
pub fn close(self) {
427+
drop(self)
428+
}
429+
430+
/// Block until background process is done
431+
pub fn wait(&mut self) {
432+
self.handle
433+
.take()
434+
.expect("Called stop on non-running thread")
435+
.join()
436+
.expect("Could not join spawned thread");
437+
}
438+
439+
/// Make the device turn on and off repeatedly in the background.
440+
/// Use `set_blink_count` to set the number of times to blink the device
441+
/// * `on_time` - Number of seconds on
442+
/// * `off_time` - Number of seconds off
443+
///
444+
pub fn blink(&mut self, on_time: f32, off_time: f32, on_color: Rgb, off_color: Rgb) {
445+
match self.blink_count {
446+
None => self.blinker(on_time, off_time, on_color, off_color, None),
447+
Some(n) => self.blinker(on_time, off_time, on_color, off_color, Some(n)),
271448
}
272449
}
450+
451+
/// Set the number of times to blink the device
452+
/// * `n` - Number of times to blink
453+
pub fn set_blink_count(&mut self, n: i32) {
454+
self.blink_count = Some(n)
455+
}
456+
457+
pub fn is_lit(&self) -> bool {
458+
self.is_active()
459+
}
273460
}
274461

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

0 commit comments

Comments
 (0)