trellis/
core.rs

1extern crate i2cdev;
2
3use std;
4use std::time::Duration;
5use super::devices::I2CMasterDevice;
6
7const NUM_LEDS: usize = 16;
8
9type LedVec = [bool; NUM_LEDS];
10
11static LED_ADDRESSES : [u8; NUM_LEDS] = [
12      0x3A, 0x37, 0x35, 0x34,
13      0x28, 0x29, 0x23, 0x24,
14      0x16, 0x1B, 0x11, 0x10,
15      0x0E, 0x0D, 0x0C, 0x02
16];
17
18static BUTTON_ADDRESSES : [u8; NUM_LEDS] = [
19      0x07, 0x04, 0x02, 0x22,
20      0x05, 0x06, 0x00, 0x01,
21      0x03, 0x10, 0x30, 0x21,
22      0x13, 0x12, 0x11, 0x31
23];
24
25/// A column in the trellis grid.
26/// See the project readme for a scheme of the trellis orientation.
27#[derive(PartialEq, Debug, Copy, Clone)]
28pub enum Col {
29    A, B, C, D
30}
31
32/// A row in the trellis grid.
33/// See the project readme for a scheme of the trellis orientation.
34#[derive(PartialEq, Debug, Copy, Clone)]
35pub enum Row {
36    R0, R1, R2, R3
37}
38
39/// A particular button and LED combination in the grid.
40/// Inconsistently used in the trellis implementation
41/// at the moment.
42#[derive(PartialEq, Debug, Copy, Clone)]
43pub struct LedButton {
44    pub col: Col,
45    pub row: Row
46}
47
48/// Describes a button event that occurred. At the moment only button press
49/// is implemented.
50///
51/// Since the buttons on the trellis can be pressed simultaneouly a list
52/// of buttons is supplied. The order in this list is undefined.
53#[derive(Debug)]
54pub struct ButtonEvent {
55    pub buttons_pressed: Vec<LedButton>
56}
57
58
59impl ButtonEvent {
60    /// Returns a empty event (nothing happend).
61    pub fn empty() -> ButtonEvent {
62        return ButtonEvent{buttons_pressed: vec![]}
63    }
64}
65
66/// The callback type for the button_evt_loop (see the Trellis struct for details).
67pub type EventLoopHandler = Box<FnMut(&mut Trellis, ButtonEvent) -> bool>;
68
69// Helper methods
70
71fn row_to_num(row: Row) -> u8 {
72    match row {
73        Row::R0 => 0,
74        Row::R1 => 1,
75        Row::R2 => 2,
76        Row::R3 => 3
77    }
78}
79
80fn num_to_row(num: usize) -> Row {
81    match num {
82        0 => Row::R0,
83        1 => Row::R1,
84        2 => Row::R2,
85        3 => Row::R3,
86        _ => panic!("illegal row")
87    }
88}
89
90fn col_to_num(col: Col) -> u8 {
91    match col {
92        Col::A => 0,
93        Col::B => 1,
94        Col::C => 2,
95        Col::D => 3,
96    }
97}
98
99fn num_to_col(num: usize) -> Col {
100    match num {
101        0 => Col::A,
102        1 => Col::B,
103        2 => Col::C,
104        3 => Col::D,
105        _ => panic!("illegal column")
106    }
107}
108
109fn num_to_led_button(num: usize) -> LedButton {
110    let col_num = num % 4;
111    let row_num = num / 4;
112    return LedButton{col: num_to_col(col_num), row: num_to_row(row_num)};
113}
114
115fn led_index(col:Col, row:Row) -> usize {
116    return (row_to_num(row)*4 + col_to_num(col)) as usize;
117}
118
119fn to_button_state(dev_data: Vec<u8>) -> LedVec {
120    let mut result = [false; NUM_LEDS];
121    for i in 0..NUM_LEDS {
122        let addr = BUTTON_ADDRESSES[i];
123        result[i] = (dev_data[(addr >> 4) as usize] & (1 << (addr & 0x0F))) > 0;
124    }
125    return result;
126}
127
128fn button_event(old: LedVec, new: LedVec) -> ButtonEvent {
129    let mut pressed = Vec::new();
130    for i in 0..NUM_LEDS {
131        if new[i] && !old[i] {
132            pressed.push(num_to_led_button(i));
133        }
134    }
135    return ButtonEvent{buttons_pressed:pressed};
136}
137
138// Trellis impl
139
140/// The Trellis device abstraction.
141pub struct Trellis {
142    display_buffer: LedVec,
143    button_state: LedVec,
144    device : Box<I2CMasterDevice>
145}
146
147impl Trellis {
148
149    /// Construct a new Trellis device with a particular
150    /// I2C-Device. See the devices module for a list
151    /// of concrete devices that can be used.
152    /// Note: object has to be initialised with a call to
153    /// init before you can control the LEDs and
154    /// buttons.
155    pub fn new(dev: Box<I2CMasterDevice>) -> Trellis {
156        return Trellis { display_buffer: [false; NUM_LEDS],
157                         button_state: [false; NUM_LEDS],
158                         device: dev};
159    }
160
161    /// Initialise the trellis connection. Has to be called
162    /// exactly once for a trellis.
163    pub fn init(&mut self) {
164        let empty_array:[u8;0] = [];
165        self.device.write_block(0x21, &empty_array).unwrap();
166        // set blink off
167        self.device.write_block(0x80 | 0x01 | 0 << 1, &empty_array).unwrap();
168        //set brightness to max
169        self.device.write_block(0xE0 | 15, &empty_array).unwrap();
170        //turn interrupt on
171        self.device.write_block(0xA1, &empty_array).unwrap();
172    }
173
174    /// Turn a LED on the specified position to on.
175    pub fn set_led(&mut self, col:Col, row: Row) {
176        self.display_buffer[led_index(col, row)] = true;
177    }
178
179    /// Turn a LED on the specified position to off.
180    pub fn clear_led(&mut self, col:Col, row:Row) {
181        self.display_buffer[led_index(col, row)] = false;
182    }
183
184    /// Returns the LED state (on or off) from the internal display buffer.
185    /// The state may not reflect the actual state on the hardware if
186    /// the display buffer was not written.
187    pub fn is_led_set(&mut self, col:Col, row: Row) -> bool {
188        return self.display_buffer[led_index(col, row)];
189    }
190
191    /// Writes the internal display buffer to the hardware.
192    /// You must call this function manually after updating
193    /// the LED states of the trellis.
194    pub fn write_display(&mut self) {
195        let mut data:[u16; 8] = [0; 8];
196        for l in 0..NUM_LEDS {
197            let led_addr = LED_ADDRESSES[l];
198            if self.display_buffer[l] {
199                data[(led_addr >> 4) as usize] |= 1 << (led_addr & 0x0F);
200            } else {
201                data[(led_addr >> 4) as usize] &= !(1 << (led_addr & 0x0F));
202            }
203        }
204
205        let mut w:[u8; 16] = [0; 16];
206        for i in 0..8 {
207            w[i*2] = (data[i] & 0xFF) as u8;
208            w[i*2+1] = (data[i] >> 8) as u8;
209        }
210
211        self.device.write_block(0x0, &w).unwrap();
212    }
213
214    /// Start the button read event loop. This function does not terminate and can
215    /// only be stopped by the supplied event handler returning false.
216    /// The polling interval for reading the button is currently fixed to 30ms.
217    pub fn button_evt_loop(&mut self, mut hnd: EventLoopHandler) {
218        loop {
219            let new_button_state = to_button_state(self.device.read_block(0x40, 6).unwrap());
220            let event = button_event(self.button_state, new_button_state);
221
222            self.button_state = new_button_state;
223
224            let handler_result = hnd(self, event);
225            if handler_result {
226                break;
227            }
228            std::thread::sleep(Duration::from_millis(30));
229        }
230    }
231}