Skip to content

Commit dd5e20d

Browse files
committed
Update RGBLED digital implementation
1 parent 1a9aa5d commit dd5e20d

File tree

3 files changed

+230
-16
lines changed

3 files changed

+230
-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: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
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+
led.set_color(Rgb::new(1.0, 1.0, 0.0));
12+
thread::sleep(time::Duration::from_millis(500));
13+
led.set_color(Rgb::new(0.0, 1.0, 0.0));
14+
thread::sleep(time::Duration::from_millis(500));
15+
led.set_color(Rgb::new(0.0, 1.0, 1.0));
16+
thread::sleep(time::Duration::from_millis(500));
1317

14-
// prevent program from exiting immediately
15-
led.red.wait();
16-
led.green.wait();
17-
led.blue.wait();
18+
// // on_time = 2 secs, off_time=3 secs
19+
// led.red.blink(0.11, 0.05);
20+
// led.green.blink(0.7, 0.17);
21+
// led.blue.blink(0.23, 0.03);
22+
23+
// // prevent program from exiting immediately
24+
// led.red.wait();
25+
// led.green.wait();
26+
// led.blue.wait();
1827
}

src/output_devices.rs

Lines changed: 211 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,223 @@ 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+
on_color: Rgb,
263+
off_color: Rgb,
264+
blinking: Arc<AtomicBool>,
265+
handle: Option<JoinHandle<()>>,
266+
blink_count: Option<i32>,
263267
}
264268

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

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

0 commit comments

Comments
 (0)