#![recursion_limit="128"]
extern crate libc;
extern crate num;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate quick_error;
mod gpio;
mod system;
use std::result;
use gpio::{GPIO, Level, Mode};
pub use gpio::Error as GPIOError;
const DAT: u8 = 23;
const CLK: u8 = 24;
const NUM_PIXELS: usize = 8;
const DEFAULT_BRIGHTNESS: u8 = 7;
quick_error! {
#[derive(Debug)]
pub enum Error {
GPIO(err: GPIOError) { description(err.description()) from() }
}
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Copy, Clone)]
struct Pixel {
red: u8,
green: u8,
blue: u8,
brightness: u8,
}
impl Default for Pixel {
fn default() -> Pixel {
Pixel {
red: 0,
green: 0,
blue: 0,
brightness: DEFAULT_BRIGHTNESS,
}
}
}
pub struct Blinkt {
gpio: GPIO,
pixels: Vec<Pixel>,
clear_on_drop: bool,
pin_data: u8,
pin_clock: u8,
endframe_pulses: usize,
}
impl Blinkt {
pub fn new() -> Result<Blinkt> {
Blinkt::with_settings(DAT, CLK, NUM_PIXELS)
}
pub fn with_settings(pin_data: u8, pin_clock: u8, num_pixels: usize) -> Result<Blinkt> {
let mut gpio = try!(GPIO::new());
gpio.set_mode(pin_data, Mode::Output);
gpio.write(pin_data, Level::Low);
gpio.set_mode(pin_clock, Mode::Output);
gpio.write(pin_clock, Level::Low);
let blinkt = Blinkt {
gpio: gpio,
pixels: vec![Pixel::default(); num_pixels],
clear_on_drop: true,
pin_data: pin_data,
pin_clock: pin_clock,
endframe_pulses: ((num_pixels as f32 * 0.5) + 0.5) as usize,
};
blinkt.write_byte(0);
blinkt.write_byte(0);
blinkt.write_byte(0);
blinkt.write_byte(0);
Ok(blinkt)
}
pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
self.clear_on_drop = clear_on_drop;
}
pub fn cleanup(&mut self) {
if self.clear_on_drop {
self.clear();
self.show();
}
self.gpio.cleanup();
}
pub fn set_pixel(&mut self, pixel: usize, red: u8, green: u8, blue: u8) {
if let Some(pixel) = self.pixels.get_mut(pixel) {
pixel.red = red;
pixel.green = green;
pixel.blue = blue;
}
}
pub fn set_pixel_rgbb(&mut self, pixel: usize, red: u8, green: u8, blue: u8, brightness: f32) {
if let Some(pixel) = self.pixels.get_mut(pixel) {
pixel.red = red;
pixel.green = green;
pixel.blue = blue;
pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
}
}
pub fn set_pixel_brightness(&mut self, pixel: usize, brightness: f32) {
if let Some(pixel) = self.pixels.get_mut(pixel) {
pixel.brightness = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
}
}
pub fn set_all_pixels(&mut self, red: u8, green: u8, blue: u8) {
for pixel in &mut self.pixels {
pixel.red = red;
pixel.green = green;
pixel.blue = blue;
}
}
pub fn set_all_pixels_rgbb(&mut self, red: u8, green: u8, blue: u8, brightness: f32) {
let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
for pixel in &mut self.pixels {
pixel.red = red;
pixel.green = green;
pixel.blue = blue;
pixel.brightness = brightness;
}
}
pub fn set_all_pixels_brightness(&mut self, brightness: f32) {
let brightness: u8 = (31.0 * if brightness > 1.0 { 1.0 } else if brightness < 0.0 { 0.0 } else { brightness }) as u8;
for pixel in &mut self.pixels {
pixel.brightness = brightness;
}
}
pub fn clear(&mut self) {
self.set_all_pixels(0, 0, 0);
}
pub fn show(&self) {
for pixel in &self.pixels {
self.write_byte(0b11100000 | pixel.brightness); self.write_byte(pixel.blue);
self.write_byte(pixel.green);
self.write_byte(pixel.red);
}
self.gpio.write(self.pin_data, Level::Low);
for _ in 0..32 + self.endframe_pulses {
self.gpio.write(self.pin_clock, Level::High);
self.gpio.write(self.pin_clock, Level::Low);
}
}
fn write_byte(&self, byte: u8) {
for n in 0..8 {
if (byte & (1 << (7 - n))) > 0 {
self.gpio.write(self.pin_data, Level::High);
} else {
self.gpio.write(self.pin_data, Level::Low);
}
self.gpio.write(self.pin_clock, Level::High);
self.gpio.write(self.pin_clock, Level::Low);
}
}
}
impl Drop for Blinkt {
fn drop(&mut self) {
self.cleanup();
}
}
#[test]
fn test_new() {
let mut blinkt = match Blinkt::new() {
Err(Error::GPIO(_)) => return,
Ok(blinkt) => blinkt,
};
blinkt.set_clear_on_drop(false);
}