1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
extern crate hidapi;
extern crate color_processing;
extern crate timer;
extern crate chrono;

use color_processing::Color;
use timer::{Guard, Timer};
use std::sync::{Arc, Mutex};
use std::ops::Deref;

const VID: u16 = 0x04D8;

pub enum Tones {
    OpenOffice = 136,
    Quiet = 144,
    Funky = 152,
    FairyTale = 160,
    KuandoTrain = 168,
    TelephoneNordic = 176,
    TelephoneOriginal = 184,
    TelephonePickMeUp = 192,
    Buzz = 216
}

pub enum Positions {
    Red = 3,
    Green = 4,
    Blue = 5,
    Sound = 8
}

pub struct BusyLight {
    device: Arc<Mutex<hidapi::HidDevice>>,
    buffer: Arc<Mutex<[u8; 9]>>,
    keep_alive_timer: Timer,
    keep_alive_guard: Guard,
}

impl BusyLight {
    pub fn new() -> Self {
        let api = match hidapi::HidApi::new() {
            Ok(api) => api,
            Err(_) => panic!("Can't init hidapi!"),
        };

        //find device based on VID
        let devices = api.devices();
        let mut pid: u16 = 0xF848;

        for d in devices {
            if d.vendor_id == VID {
                pid = d.product_id;
                break;
            }
        }

        let device = Arc::new(Mutex::new(match api.open(VID, pid) {
            Ok(dev) => dev,
            Err(_) => panic!("Can't find the BusyLight! Is it plugged in?"),
        }));

        //This is just default settings for the light
        let defaults = Arc::new(Mutex::new([0, 0, 0, 0, 0, 0, 0, 0, 128]));

        //keepalive timer
        let timer = timer::Timer::new();
        //dummy guard as I have to pass a guard that isn't empty when constructing. Cannot let guard be empty and set later
        let guard = timer.schedule_with_delay(chrono::Duration::minutes(1000), || {});

        BusyLight{device: device, buffer: defaults, keep_alive_timer: timer, keep_alive_guard: guard}
    }

    pub fn send(&mut self) {
        // send the current buffer, as all changes should be reflected in that
        let shared_device = self.device.clone();
        let shared_buffer = self.buffer.clone();
        let dev = shared_device.lock().unwrap();
        let buf = shared_buffer.lock().unwrap();

        dev.write(buf.deref()).expect("Can't write payload to device!");
    }

    pub fn keepalive_enable(&mut self) {

        let shared_device = self.device.clone();
        let shared_buffer = self.buffer.clone();

        self.keep_alive_guard = self.keep_alive_timer.schedule_repeating(chrono::Duration::seconds(20), move || {

            // getting device and buffer for usage
            let dev = shared_device.lock().unwrap();
            let buf = shared_buffer.lock().unwrap();
            dev.write(buf.deref()).expect("KeepAlive: Can't write payload to device!");
        });
    }

    pub fn keepalive_disable(&mut self) {
        // drop() errors for some reason as we are behind mutable reference. Making new dummy timer instead
        self.keep_alive_guard = self.keep_alive_timer.schedule_with_delay(chrono::Duration::minutes(1000), || {});
    }

    ///
    /// volume accepts 0 to 7, with 7 being loudest
    ///
    pub fn ring(&mut self, tone: Tones, volume: u8) {
        //validate volume input
        if volume > 7 {
            panic!("[ring()] Volume can only be between 0-7 with both inclusive")
        }

        //stop current sound, or can it change directly?
        self.stop_ring();

        // get buffer
        let shared_buffer = self.buffer.clone();
        let mut buf = shared_buffer.lock().unwrap();

        //change buffer to new settings
        buf[Positions::Sound as usize] = (tone as u8) + volume;

        //drop mutex
        drop(buf);

        self.send();
    }

    pub fn stop_ring(&mut self) {
        // get buffer
        let shared_buffer = self.buffer.clone();
        let mut buf = shared_buffer.lock().unwrap();

        buf[Positions::Sound as usize] = 128;

        //drop mutex
        drop(buf);

        self.send();
    }

    pub fn light(&mut self, colour: &str) {
        //try to parse colour
        let col = Color::new_string(colour).unwrap();

        // get buffer
        let shared_buffer = self.buffer.clone();
        let mut buf = shared_buffer.lock().unwrap();

        buf[Positions::Red as usize] = col.red; // buf.get_mut(Positions::Red as usize).
        buf[Positions::Green as usize] = col.green;
        buf[Positions::Blue as usize] = col.blue;

        //drop mutex
        drop(buf);

        //update changes
        self.send();
    }

    pub fn stop_light(&mut self) {
        // get mut buffer
        // get buffer
        let shared_buffer = self.buffer.clone();
        let mut buf = shared_buffer.lock().unwrap();

        buf[Positions::Red as usize] = 0;
        buf[Positions::Green as usize] = 0;
        buf[Positions::Blue as usize] = 0;

        //drop mutex
        drop(buf);

        //update changes
        self.send();
    }
}