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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
extern crate i2cdev;

use std;
use std::time::Duration;
use super::devices::I2CMasterDevice;

const NUM_LEDS: usize = 16;

type LedVec = [bool; NUM_LEDS];

static LED_ADDRESSES : [u8; NUM_LEDS] = [
      0x3A, 0x37, 0x35, 0x34,
      0x28, 0x29, 0x23, 0x24,
      0x16, 0x1B, 0x11, 0x10,
      0x0E, 0x0D, 0x0C, 0x02
];

static BUTTON_ADDRESSES : [u8; NUM_LEDS] = [
      0x07, 0x04, 0x02, 0x22,
      0x05, 0x06, 0x00, 0x01,
      0x03, 0x10, 0x30, 0x21,
      0x13, 0x12, 0x11, 0x31
];

/// A column in the trellis grid.
/// See the project readme for a scheme of the trellis orientation.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Col {
    A, B, C, D
}

/// A row in the trellis grid.
/// See the project readme for a scheme of the trellis orientation.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Row {
    R0, R1, R2, R3
}

/// A particular button and LED combination in the grid.
/// Inconsistently used in the trellis implementation
/// at the moment.
#[derive(PartialEq, Debug, Copy, Clone)]
pub struct LedButton {
    pub col: Col,
    pub row: Row
}

/// Describes a button event that occurred. At the moment only button press
/// is implemented.
///
/// Since the buttons on the trellis can be pressed simultaneouly a list
/// of buttons is supplied. The order in this list is undefined.
#[derive(Debug)]
pub struct ButtonEvent {
    pub buttons_pressed: Vec<LedButton>
}


impl ButtonEvent {
    /// Returns a empty event (nothing happend).
    pub fn empty() -> ButtonEvent {
        return ButtonEvent{buttons_pressed: vec![]}
    }
}

/// The callback type for the button_evt_loop (see the Trellis struct for details).
pub type EventLoopHandler = Box<FnMut(&mut Trellis, ButtonEvent) -> bool>;

// Helper methods

fn row_to_num(row: Row) -> u8 {
    match row {
        Row::R0 => 0,
        Row::R1 => 1,
        Row::R2 => 2,
        Row::R3 => 3
    }
}

fn num_to_row(num: usize) -> Row {
    match num {
        0 => Row::R0,
        1 => Row::R1,
        2 => Row::R2,
        3 => Row::R3,
        _ => panic!("illegal row")
    }
}

fn col_to_num(col: Col) -> u8 {
    match col {
        Col::A => 0,
        Col::B => 1,
        Col::C => 2,
        Col::D => 3,
    }
}

fn num_to_col(num: usize) -> Col {
    match num {
        0 => Col::A,
        1 => Col::B,
        2 => Col::C,
        3 => Col::D,
        _ => panic!("illegal column")
    }
}

fn num_to_led_button(num: usize) -> LedButton {
    let col_num = num % 4;
    let row_num = num / 4;
    return LedButton{col: num_to_col(col_num), row: num_to_row(row_num)};
}

fn led_index(col:Col, row:Row) -> usize {
    return (row_to_num(row)*4 + col_to_num(col)) as usize;
}

fn to_button_state(dev_data: Vec<u8>) -> LedVec {
    let mut result = [false; NUM_LEDS];
    for i in 0..NUM_LEDS {
        let addr = BUTTON_ADDRESSES[i];
        result[i] = (dev_data[(addr >> 4) as usize] & (1 << (addr & 0x0F))) > 0;
    }
    return result;
}

fn button_event(old: LedVec, new: LedVec) -> ButtonEvent {
    let mut pressed = Vec::new();
    for i in 0..NUM_LEDS {
        if new[i] && !old[i] {
            pressed.push(num_to_led_button(i));
        }
    }
    return ButtonEvent{buttons_pressed:pressed};
}

// Trellis impl

/// The Trellis device abstraction.
pub struct Trellis {
    display_buffer: LedVec,
    button_state: LedVec,
    device : Box<I2CMasterDevice>
}

impl Trellis {

    /// Construct a new Trellis device with a particular
    /// I2C-Device. See the devices module for a list
    /// of concrete devices that can be used.
    /// Note: object has to be initialised with a call to
    /// init before you can control the LEDs and
    /// buttons.
    pub fn new(dev: Box<I2CMasterDevice>) -> Trellis {
        return Trellis { display_buffer: [false; NUM_LEDS],
                         button_state: [false; NUM_LEDS],
                         device: dev};
    }

    /// Initialise the trellis connection. Has to be called
    /// exactly once for a trellis.
    pub fn init(&mut self) {
        let empty_array:[u8;0] = [];
        self.device.write_block(0x21, &empty_array).unwrap();
        // set blink off
        self.device.write_block(0x80 | 0x01 | 0 << 1, &empty_array).unwrap();
        //set brightness to max
        self.device.write_block(0xE0 | 15, &empty_array).unwrap();
        //turn interrupt on
        self.device.write_block(0xA1, &empty_array).unwrap();
    }

    /// Turn a LED on the specified position to on.
    pub fn set_led(&mut self, col:Col, row: Row) {
        self.display_buffer[led_index(col, row)] = true;
    }

    /// Turn a LED on the specified position to off.
    pub fn clear_led(&mut self, col:Col, row:Row) {
        self.display_buffer[led_index(col, row)] = false;
    }

    /// Returns the LED state (on or off) from the internal display buffer.
    /// The state may not reflect the actual state on the hardware if
    /// the display buffer was not written.
    pub fn is_led_set(&mut self, col:Col, row: Row) -> bool {
        return self.display_buffer[led_index(col, row)];
    }

    /// Writes the internal display buffer to the hardware.
    /// You must call this function manually after updating
    /// the LED states of the trellis.
    pub fn write_display(&mut self) {
        let mut data:[u16; 8] = [0; 8];
        for l in 0..NUM_LEDS {
            let led_addr = LED_ADDRESSES[l];
            if self.display_buffer[l] {
                data[(led_addr >> 4) as usize] |= 1 << (led_addr & 0x0F);
            } else {
                data[(led_addr >> 4) as usize] &= !(1 << (led_addr & 0x0F));
            }
        }

        let mut w:[u8; 16] = [0; 16];
        for i in 0..8 {
            w[i*2] = (data[i] & 0xFF) as u8;
            w[i*2+1] = (data[i] >> 8) as u8;
        }

        self.device.write_block(0x0, &w).unwrap();
    }

    /// Start the button read event loop. This function does not terminate and can
    /// only be stopped by the supplied event handler returning false.
    /// The polling interval for reading the button is currently fixed to 30ms.
    pub fn button_evt_loop(&mut self, mut hnd: EventLoopHandler) {
        loop {
            let new_button_state = to_button_state(self.device.read_block(0x40, 6).unwrap());
            let event = button_event(self.button_state, new_button_state);

            self.button_state = new_button_state;

            let handler_result = hnd(self, event);
            if handler_result {
                break;
            }
            std::thread::sleep(Duration::from_millis(30));
        }
    }
}