Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ edition = "2018"

[dependencies]
rppal = "0.12.0"

palette = "0.7.3"
38 changes: 38 additions & 0 deletions examples/blink_rgb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Blinks an LED : on_time: 2 seconds and off_time: 3 seconds

use palette::rgb::Rgb;
use rust_gpiozero::*;
use std::{thread, time};

fn main() {
// Create a new LED attached to Pin 17
let mut led = RGBLED::new(12, 19, 13, true);

// Display some colours for half a second each
led.set_color(Rgb::new(1.0, 1.0, 0.0));
thread::sleep(time::Duration::from_millis(1500));
led.set_color(Rgb::new(0.0, 1.0, 0.0));
thread::sleep(time::Duration::from_millis(1500));
led.set_color(Rgb::new(0.0, 1.0, 1.0));
thread::sleep(time::Duration::from_millis(1500));

// Blink five times
led.set_blink_count(50);
led.blink(2.5, 1.2, Rgb::new(1.0, 1.0, 0.0), Rgb::new(0.0, 0.0, 1.0));
led.wait();
led.off();

// Stay off for a second
thread::sleep(time::Duration::from_millis(1000));

// Blink ten times
led.set_blink_count(10);
led.blink(0.2, 0.5, Rgb::new(1.0, 1.0, 1.0), Rgb::new(1.0, 0.0, 0.0));
led.wait();

// Show white for two seconds
led.on();
led.set_color(Rgb::new(1.0, 1.0, 1.0));
thread::sleep(time::Duration::from_millis(2000));
led.off();
}
1 change: 1 addition & 0 deletions src/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ macro_rules! impl_device {
pub struct GpioDevice {
pin: Pin,
active_state: bool,
#[allow(dead_code)]
inactive_state: bool,
}

Expand Down
236 changes: 226 additions & 10 deletions src/output_devices.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Output device component interfaces for devices such as `LED`, `PWMLED`, etc
use palette::rgb::Rgb;
use rppal::gpio::{Gpio, IoPin, Level, Mode};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
Expand Down Expand Up @@ -256,6 +257,225 @@ impl DigitalOutputDevice {
}
}

pub struct RGBLED {
red: Arc<Mutex<OutputDevice>>,
green: Arc<Mutex<OutputDevice>>,
blue: Arc<Mutex<OutputDevice>>,
blinking: Arc<AtomicBool>,
handle: Option<JoinHandle<()>>,
blink_count: Option<i32>,
}

impl RGBLED {
pub fn new(pin_red: u8, pin_green: u8, pin_blue: u8, active_high: bool) -> RGBLED {
let red = Arc::new(Mutex::new(OutputDevice::new(pin_red)));
let green = Arc::new(Mutex::new(OutputDevice::new(pin_green)));
let blue = Arc::new(Mutex::new(OutputDevice::new(pin_blue)));
red.lock().unwrap().set_active_high(active_high);
green.lock().unwrap().set_active_high(active_high);
blue.lock().unwrap().set_active_high(active_high);
Self {
red,
green,
blue,
blinking: Arc::new(AtomicBool::new(false)),
handle: None,
blink_count: None,
}
}

pub fn set_color(&mut self, color: Rgb) {
Self::write_color(&self.red, &self.green, &self.blue, color);
}

fn write_color(
red: &Arc<Mutex<OutputDevice>>,
green: &Arc<Mutex<OutputDevice>>,
blue: &Arc<Mutex<OutputDevice>>,
color: Rgb,
) {
Self::write_state(&red, color.red > 0.5);
Self::write_state(&green, color.green > 0.5);
Self::write_state(&blue, color.blue > 0.5);
}

fn write_state(device: &Arc<Mutex<OutputDevice>>, value: bool) {
if device.lock().unwrap().value_to_state(value) {
device.lock().unwrap().pin.set_high()
} else {
device.lock().unwrap().pin.set_low()
}
}

fn blinker(
&mut self,
on_time: f32,
off_time: f32,
on_color: Rgb,
off_color: Rgb,
n: Option<i32>,
) {
self.stop();

let red = Arc::clone(&self.red);
let green = Arc::clone(&self.green);
let blue = Arc::clone(&self.blue);

let blinking = Arc::clone(&self.blinking);

self.handle = Some(thread::spawn(move || {
blinking.store(true, Ordering::SeqCst);
match n {
Some(end) => {
for _ in 0..end {
if !blinking.load(Ordering::SeqCst) {
red.lock().unwrap().off();
green.lock().unwrap().off();
blue.lock().unwrap().off();
break;
}
Self::write_color(&red, &green, &blue, on_color);
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
Self::write_color(&red, &green, &blue, off_color);
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
}
}
None => loop {
if !blinking.load(Ordering::SeqCst) {
red.lock().unwrap().off();
green.lock().unwrap().off();
blue.lock().unwrap().off();
break;
}
Self::write_color(&red, &green, &blue, on_color);
thread::sleep(Duration::from_millis((on_time * 1000.0) as u64));
Self::write_color(&red, &green, &blue, off_color);
thread::sleep(Duration::from_millis((off_time * 1000.0) as u64));
},
}
}));
}
/// Returns ``True`` if the device is currently active and ``False`` otherwise.
pub fn is_active(&self) -> bool {
self.red.lock().unwrap().is_active()
|| self.green.lock().unwrap().is_active()
|| self.blue.lock().unwrap().is_active()
}
/// Turns the device on.
pub fn on(&self) {
self.stop();
self.red.lock().unwrap().on();
self.green.lock().unwrap().on();
self.blue.lock().unwrap().on();
}
/// Turns the device off.
pub fn off(&self) {
self.stop();
self.red.lock().unwrap().off();
self.green.lock().unwrap().off();
self.blue.lock().unwrap().off();
}
/// Reverse the state of the device. If it's on, turn it off; if it's off, turn it on.
pub fn toggle(&mut self) {
if self.is_active() {
self.on()
} else {
self.off()
}
}

/// Returns ``True`` if the device is currently active and ``False`` otherwise.
pub fn value_red(&self) -> bool {
self.red.lock().unwrap().value()
}

/// Returns ``True`` if the device is currently active and ``False`` otherwise.
pub fn value_green(&self) -> bool {
self.green.lock().unwrap().value()
}

/// Returns ``True`` if the device is currently active and ``False`` otherwise.
pub fn value_blue(&self) -> bool {
self.blue.lock().unwrap().value()
}

fn stop(&self) {
self.blinking.clone().store(false, Ordering::SeqCst);
self.red.lock().unwrap().pin.set_low();
self.green.lock().unwrap().pin.set_low();
self.blue.lock().unwrap().pin.set_low();
}

/// When ``True``, the `value` property is ``True`` when the device's
/// `pin` is high. When ``False`` the `value` property is
/// ``True`` when the device's pin is low (i.e. the value is inverted).
/// Be warned that changing it will invert `value` (i.e. changing this property doesn't change
/// the device's pin state - it just changes how that state is interpreted).
pub fn active_high(&self) -> bool {
self.red.lock().unwrap().active_high()
|| self.green.lock().unwrap().active_high()
|| self.blue.lock().unwrap().active_high()
}

/// Set the state for active_high
pub fn set_active_high(&mut self, value: bool) {
self.red.lock().unwrap().set_active_high(value);
self.green.lock().unwrap().set_active_high(value);
self.blue.lock().unwrap().set_active_high(value);
}

/// The `Pin` that the device is connected to.
pub fn pin_red(&self) -> u8 {
self.red.lock().unwrap().pin.pin()
}

/// The `Pin` that the device is connected to.
pub fn pin_green(&self) -> u8 {
self.green.lock().unwrap().pin.pin()
}

/// The `Pin` that the device is connected to.
pub fn pin_blue(&self) -> u8 {
self.blue.lock().unwrap().pin.pin()
}

/// Shut down the device and release all associated resources.
pub fn close(self) {
drop(self)
}

/// Block until background process is done
pub fn wait(&mut self) {
self.handle
.take()
.expect("Called stop on non-running thread")
.join()
.expect("Could not join spawned thread");
}

/// Make the device turn on and off repeatedly in the background.
/// Use `set_blink_count` to set the number of times to blink the device
/// * `on_time` - Number of seconds on
/// * `off_time` - Number of seconds off
///
pub fn blink(&mut self, on_time: f32, off_time: f32, on_color: Rgb, off_color: Rgb) {
match self.blink_count {
None => self.blinker(on_time, off_time, on_color, off_color, None),
Some(n) => self.blinker(on_time, off_time, on_color, off_color, Some(n)),
}
}

/// Set the number of times to blink the device
/// * `n` - Number of times to blink
pub fn set_blink_count(&mut self, n: i32) {
self.blink_count = Some(n)
}

pub fn is_lit(&self) -> bool {
self.is_active()
}
}

/// Represents a light emitting diode (LED)
///
/// # Example
Expand Down Expand Up @@ -740,7 +960,8 @@ impl Servo {
if value >= -1.0 && value <= 1.0 {
// Map value form [-1, 1] to [min_pulse_width, max_pulse_width] linearly
let range: f64 = (self.max_pulse_width - self.min_pulse_width) as f64;
let pulse_width: u64 = self.min_pulse_width + (((value + 1.0)/2.0) * range).round() as u64;
let pulse_width: u64 =
self.min_pulse_width + (((value + 1.0) / 2.0) * range).round() as u64;
if self
.pin
.set_pwm(
Expand All @@ -751,12 +972,11 @@ impl Servo {
{
println!("Failed to set servo to a new position");
}
}
else {
} else {
println!("set_position value must be between -1 and 1");
}
}

/// Set the servo's minimum pulse width
pub fn set_min_pulse_width(&mut self, value: u64) {
if value >= self.max_pulse_width {
Expand Down Expand Up @@ -796,12 +1016,8 @@ impl Servo {
}

pub fn detach(&mut self) {
if self
.pin
.clear_pwm()
.is_err()
{
if self.pin.clear_pwm().is_err() {
println!("Failed to detach servo")
}
}
}
}