Commit | Line | Data |
---|---|---|
3dc1c2aa | 1 | /* |
1c2b594a L |
2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). |
3 | Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | |
4 | Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
3dc1c2aa | 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
1c2b594a L |
6 | */ |
7 | #include "Smoothiepanel.h" | |
8 | #include "smoothiepanel/LCDBang.h" | |
9 | ||
ab4abea9 | 10 | #include "smoothiepanel/Colors.h" |
61134a65 JM |
11 | #include "Config.h" |
12 | #include "checksumm.h" | |
ab4abea9 | 13 | |
3dc1c2aa JM |
14 | // commands |
15 | #define LCD_CLEARDISPLAY 0x01 | |
16 | #define LCD_RETURNHOME 0x02 | |
17 | #define LCD_ENTRYMODESET 0x04 | |
18 | #define LCD_DISPLAYCONTROL 0x08 | |
19 | #define LCD_CURSORSHIFT 0x10 | |
20 | #define LCD_FUNCTIONSET 0x20 | |
21 | #define LCD_SETCGRAMADDR 0x40 | |
22 | #define LCD_SETDDRAMADDR 0x80 | |
23 | ||
24 | // flags for display entry mode | |
25 | #define LCD_ENTRYRIGHT 0x00 | |
26 | #define LCD_ENTRYLEFT 0x02 | |
27 | #define LCD_ENTRYSHIFTINCREMENT 0x01 | |
28 | #define LCD_ENTRYSHIFTDECREMENT 0x00 | |
29 | ||
30 | // flags for display on/off control | |
31 | #define LCD_DISPLAYON 0x04 | |
32 | #define LCD_DISPLAYOFF 0x00 | |
33 | #define LCD_CURSORON 0x02 | |
34 | #define LCD_CURSOROFF 0x00 | |
35 | #define LCD_BLINKON 0x01 | |
36 | #define LCD_BLINKOFF 0x00 | |
37 | ||
38 | // flags for display/cursor shift | |
39 | #define LCD_DISPLAYMOVE 0x08 | |
40 | #define LCD_CURSORMOVE 0x00 | |
41 | #define LCD_MOVERIGHT 0x04 | |
42 | #define LCD_MOVELEFT 0x00 | |
43 | ||
44 | // flags for function set | |
45 | #define LCD_8BITMODE 0x10 | |
46 | #define LCD_4BITMODE 0x00 | |
47 | #define LCD_2LINE 0x08 | |
48 | #define LCD_1LINE 0x00 | |
49 | #define LCD_5x10DOTS 0x04 | |
50 | #define LCD_5x8DOTS 0x00 | |
51 | ||
52 | // flags for backlight control | |
53 | #define LCD_BACKLIGHT 0x08 | |
54 | #define LCD_NOBACKLIGHT 0x00 | |
55 | ||
56 | ||
1c2b594a L |
57 | #define LCD_WRITE 0x00 |
58 | #define LCD_READ 0x01 | |
59 | #define LCD_ACK 0x01 | |
60 | ||
61 | Smoothiepanel::Smoothiepanel() { | |
62 | // Default values | |
63 | this->backlightval = 0x00; | |
64 | this->displaycontrol = 0x00; | |
65 | this->displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; // in case they forget to call begin() at least we have somethin | |
66 | this->displaymode = 0x00; | |
67 | this->_numlines = 4; | |
68 | ||
08ce8807 L |
69 | this->wii_connected = false; |
70 | ||
1c2b594a L |
71 | // I2C com |
72 | int i2c_pins = THEKERNEL->config->value(panel_checksum, i2c_pins_checksum)->by_default(3)->as_number(); | |
73 | if(i2c_pins == 0){ | |
74 | this->i2c = new mbed::I2C(P0_0, P0_1); | |
75 | }else if(i2c_pins == 1){ | |
76 | this->i2c = new mbed::I2C(P0_10, P0_11); | |
77 | }else if(i2c_pins == 2){ | |
78 | this->i2c = new mbed::I2C(P0_19, P0_20); | |
79 | }else{ // 3, default | |
80 | this->i2c = new mbed::I2C(P0_27, P0_28); | |
81 | } | |
08ce8807 | 82 | this->wii = new Wiichuck(this->i2c); |
1c2b594a L |
83 | |
84 | this->i2c_address = (char)THEKERNEL->config->value(panel_checksum, i2c_address_checksum)->by_default(0)->as_number(); | |
85 | this->i2c_address = (this->i2c_address & 0x07) << 1; | |
86 | this->i2c_frequency = THEKERNEL->config->value(panel_checksum, i2c_frequency_checksum)->by_default(20000)->as_number(); | |
87 | i2c->frequency(this->i2c_frequency); | |
88 | this->lcd_contrast = THEKERNEL->config->value(panel_checksum, lcd_contrast_checksum)->by_default(0)->as_number(); | |
ab4abea9 L |
89 | this->backlight_red = THEKERNEL->config->value(panel_checksum, lcd_led_checksum)->by_default(255)->as_number(); |
90 | this->backlight_red = THEKERNEL->config->value(panel_checksum, lcd_led_red_checksum)->by_default(this->backlight_red)->as_number(); | |
91 | this->backlight_green = THEKERNEL->config->value(panel_checksum, lcd_led_green_checksum)->by_default(255)->as_number(); | |
92 | this->backlight_blue = THEKERNEL->config->value(panel_checksum, lcd_led_blue_checksum)->by_default(255)->as_number(); | |
93 | this->playledval = THEKERNEL->config->value(panel_checksum, play_led_brightness_checksum)->by_default(255)->as_number(); | |
94 | this->backledval = THEKERNEL->config->value(panel_checksum, back_led_brightness_checksum)->by_default(255)->as_number(); | |
1c2b594a L |
95 | |
96 | // this->interrupt_pin.from_string(THEKERNEL->config->value(panel_checksum, i2c_interrupt_pin_checksum)->by_default("nc")->as_string())->as_input(); | |
4933a6ed L |
97 | this->encoder_a_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input(); |
98 | this->encoder_b_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input(); | |
ab4abea9 | 99 | this->encoder_hue = THEKERNEL->config->value(panel_checksum, encoder_led_hue_checksum)->by_default(220)->as_number(); |
1c2b594a L |
100 | } |
101 | ||
102 | Smoothiepanel::~Smoothiepanel() { | |
08ce8807 | 103 | delete this->wii; |
1c2b594a L |
104 | delete this->i2c; |
105 | } | |
106 | ||
ab4abea9 | 107 | void pca9634_init(I2C i2c, int address){ |
1c2b594a L |
108 | const int leds = PCA9634_ADDRESS | (address & 0x0E); |
109 | char cmd[2]; | |
110 | ||
111 | // initialize led controller | |
112 | cmd[0] = 0x00; | |
113 | cmd[1] = 0x00; | |
114 | i2c.write(leds, cmd, 2); | |
115 | cmd[0] = 0x01; | |
116 | cmd[1] = 0x02; | |
117 | i2c.write(leds, cmd, 2); | |
118 | cmd[0] = 0x0C; | |
119 | cmd[1] = 0xAA; | |
120 | i2c.write(leds, cmd, 2); | |
121 | cmd[0] = 0x0D; | |
122 | i2c.write(leds, cmd, 2); | |
1c2b594a L |
123 | } |
124 | ||
073389cb L |
125 | void pca9634_setLed(I2C *i2c, int address, char led, char val){ |
126 | const int leds = PCA9634_ADDRESS | (address & 0x0E); | |
127 | char cmd[2]; | |
128 | ||
129 | cmd[0] = led; // lcd blue | |
130 | cmd[1] = val; | |
131 | i2c->write(leds, cmd, 2); | |
132 | } | |
133 | ||
52500e58 L |
134 | void pca9505_write(I2C *i2c, int address, char reg, char val){ |
135 | const int expander = PCA9505_ADDRESS | (address & 0x0E); | |
136 | char cmd[2]; | |
137 | ||
138 | cmd[0] = reg; | |
139 | cmd[1] = val; | |
140 | i2c->write(expander, cmd, 2); | |
141 | } | |
142 | ||
143 | char pca9505_read(I2C *i2c, int address, char reg){ | |
144 | const int expander = PCA9505_ADDRESS | (address & 0x0E); | |
145 | char cmd[1]; | |
146 | ||
147 | cmd[0] = 0x04; | |
148 | i2c->write(expander, cmd, 1, false); | |
149 | i2c->read(expander, cmd, 1); | |
150 | return cmd[0]; | |
151 | } | |
152 | ||
1c2b594a L |
153 | void Smoothiepanel::init(){ |
154 | // init lcd and buzzer | |
155 | lcdbang_init(*this->i2c); | |
4933a6ed | 156 | // lcdbang_print(*this->i2c, " Smoothiepanel Beta - design by Logxen -"); |
1c2b594a L |
157 | lcdbang_contrast(*this->i2c, this->lcd_contrast); |
158 | ||
ab4abea9 L |
159 | pca9634_init(*this->i2c, this->i2c_address); |
160 | setEncoderByHue(this->encoder_hue); | |
161 | setBacklightColor(this->backlight_red, this->backlight_green, this->backlight_blue); | |
162 | setPlayLED(this->playledval); | |
163 | setBackLED(this->backledval); | |
52500e58 L |
164 | |
165 | pca9505_write(this->i2c, this->i2c_address, 0x18, 0xAA); // enable leds for button/led wing on port0 | |
166 | pca9505_write(this->i2c, this->i2c_address, 0x08, 0x01); // enable leds for button/led wing on port0 | |
4933a6ed L |
167 | // wait_us(3000); |
168 | // this->clear(); | |
1c2b594a L |
169 | } |
170 | ||
073389cb L |
171 | void Smoothiepanel::setLed(int led, bool on){ |
172 | // LED turns on when bit is cleared | |
52500e58 | 173 | char saved = pca9505_read(this->i2c, this->i2c_address, 0x08); |
073389cb L |
174 | if(on) { |
175 | switch(led) { | |
52500e58 L |
176 | case LED_FAN_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved | 0x40); break; // on |
177 | case LED_HOTEND_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved | 0x10); break; // on | |
178 | case LED_BED_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved | 0x04); break; // on | |
073389cb L |
179 | } |
180 | }else{ | |
181 | switch(led) { | |
52500e58 L |
182 | case LED_FAN_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved & ~0x40); break; // off |
183 | case LED_HOTEND_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved & ~0x10); break; // off | |
184 | case LED_BED_ON: pca9505_write(this->i2c, this->i2c_address, 0x08, saved & ~0x04); break; // off | |
073389cb L |
185 | } |
186 | } | |
187 | } | |
188 | ||
189 | void Smoothiepanel::setLedBrightness(int led, int val){ | |
190 | switch(led){ | |
191 | // case LED_FAN_ON: this->backlight_green = val; break; // on | |
52500e58 L |
192 | // case LED_HOTEND_ON: this->backlight_red = val; break; // on |
193 | // case LED_BED_ON: this->backlight_blue = val; break; // on | |
073389cb L |
194 | } |
195 | } | |
196 | ||
3dc1c2aa | 197 | // cycle the buzzer pin at a certain frequency (hz) for a certain duration (ms) |
1c2b594a L |
198 | void Smoothiepanel::buzz(long duration, uint16_t freq) { |
199 | const int expander = PCA9505_ADDRESS | this->i2c_address; | |
200 | char cmd[2]; | |
4933a6ed L |
201 | char saved; |
202 | ||
203 | // save register state | |
204 | cmd[0] = 0x04; | |
205 | this->i2c->write(expander, cmd, 1, false); | |
206 | this->i2c->read(expander, cmd, 1); | |
207 | saved = cmd[0]; | |
1c2b594a L |
208 | |
209 | // buzz | |
210 | cmd[0] = 0x0C; | |
4933a6ed | 211 | cmd[1] = saved & 0xFE; |
1c2b594a L |
212 | this->i2c->write(expander, cmd, 2); |
213 | wait_ms(duration); // TODO: Make this not hold up the whole system | |
4933a6ed | 214 | cmd[1] = saved; |
1c2b594a L |
215 | this->i2c->write(expander, cmd, 2); |
216 | } | |
217 | ||
218 | uint8_t Smoothiepanel::readButtons(void) { | |
219 | const int expander = PCA9505_ADDRESS | this->i2c_address; | |
220 | uint8_t button_bits = 0x00; | |
221 | char cmd[1]; | |
222 | ||
223 | cmd[0] = 0x03; | |
224 | this->i2c->write(expander, cmd, 1, false); | |
225 | this->i2c->read(expander, cmd, 1); | |
4933a6ed | 226 | //cmd[0] = ~cmd[0]; |
08ce8807 | 227 | if((cmd[0] & 0x10) > 0) button_bits |= BUTTON_SELECT; // encoder click |
4933a6ed | 228 | if((cmd[0] & 0x02) > 0) button_bits |= BUTTON_LEFT; // back button |
52500e58 | 229 | if((cmd[0] & 0x01) > 0) button_bits |= BUTTON_PAUSE; // play button |
08ce8807 L |
230 | if((cmd[0] & 0x20) > 0){ // wii accessory connected |
231 | if(!this->wii_connected){ | |
232 | this->wii->init_device(); | |
233 | if(this->wii->device_type >= 0){ | |
234 | this->wii_connected = true; | |
235 | wait_ms(100); | |
236 | } | |
237 | } | |
238 | if(this->wii_connected){ | |
239 | this->wii->poll_device(); | |
240 | if(this->wii->data_ready){ | |
241 | if(this->wii->device_type == DEVICE_NUNCHUCK){ | |
242 | if(this->wii->SY > 192) button_bits |= BUTTON_UP; | |
243 | else if(this->wii->SY < 64) button_bits |= BUTTON_DOWN; | |
244 | if(this->wii->SX > 192) button_bits |= BUTTON_RIGHT; | |
245 | else if(this->wii->SX < 64) button_bits |= BUTTON_LEFT; | |
246 | if(!this->wii->BC) button_bits |= BUTTON_SELECT; | |
247 | if(!this->wii->BZ) button_bits |= BUTTON_LEFT; | |
248 | }else if(this->wii->device_type == DEVICE_CLASSIC){ | |
249 | if(this->wii->LY > 192) button_bits |= BUTTON_UP; | |
250 | else if(this->wii->LY < 64) button_bits |= BUTTON_DOWN; | |
251 | if(this->wii->LX > 192) button_bits |= BUTTON_RIGHT; | |
252 | else if(this->wii->LX < 64) button_bits |= BUTTON_LEFT; | |
253 | if(!this->wii->BDU) button_bits |= BUTTON_UP; | |
254 | else if(!this->wii->BDD) button_bits |= BUTTON_DOWN; | |
255 | if(!this->wii->BDL) button_bits |= BUTTON_LEFT; | |
256 | else if(!this->wii->BDR) button_bits |= BUTTON_RIGHT; | |
257 | if(!this->wii->BA) button_bits |= BUTTON_SELECT; | |
258 | if(!this->wii->BB) button_bits |= BUTTON_LEFT; | |
259 | } | |
260 | }else this->wii_connected = false; | |
261 | } | |
262 | }else this->wii_connected = false; | |
1c2b594a | 263 | |
ab4abea9 L |
264 | // update the encoder color |
265 | if(this->encoder_changed){ | |
266 | if(this->encoder_hue > 360) this->encoder_hue -= 360; | |
267 | else if(this->encoder_hue < 0) this->encoder_hue += 360; | |
268 | this->encoder_changed = false; | |
269 | ||
270 | setEncoderByHue(this->encoder_hue); | |
271 | } | |
272 | ||
1c2b594a L |
273 | return button_bits; |
274 | } | |
275 | ||
276 | int Smoothiepanel::readEncoderDelta() { | |
4933a6ed L |
277 | static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; |
278 | static uint8_t old_AB = 0; | |
ab4abea9 | 279 | int8_t state; |
4933a6ed | 280 | old_AB <<= 2; //remember previous state |
3dc1c2aa | 281 | old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) ); //add current state |
ab4abea9 L |
282 | state = enc_states[(old_AB&0x0f)]; |
283 | if(state != 0){ | |
284 | this->encoder_hue += state; | |
285 | this->encoder_changed = true; | |
286 | } | |
287 | return state; | |
1c2b594a L |
288 | } |
289 | ||
290 | void Smoothiepanel::clear() | |
291 | { | |
292 | command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero | |
4933a6ed L |
293 | //#ifndef USE_FASTMODE |
294 | // wait_ms(50); // this command takes a long time! | |
295 | //#endif | |
1c2b594a L |
296 | } |
297 | ||
298 | void Smoothiepanel::home() | |
299 | { | |
300 | command(LCD_RETURNHOME); // set cursor position to zero | |
4933a6ed L |
301 | //#ifndef USE_FASTMODE |
302 | // wait_us(2000); // this command takes a long time! | |
303 | //#endif | |
1c2b594a L |
304 | } |
305 | ||
306 | void Smoothiepanel::setCursor(uint8_t col, uint8_t row) | |
307 | { | |
308 | int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; | |
309 | if ( row > _numlines ) row = _numlines - 1; // we count rows starting w/0 | |
310 | command(LCD_SETDDRAMADDR | (col + row_offsets[row])); | |
311 | } | |
312 | ||
313 | // Turn the display on/off (quickly) | |
314 | void Smoothiepanel::noDisplay() { | |
315 | displaycontrol &= ~LCD_DISPLAYON; | |
316 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
317 | } | |
318 | ||
319 | void Smoothiepanel::display() { | |
320 | displaycontrol |= LCD_DISPLAYON; | |
321 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
322 | } | |
323 | ||
324 | // Turns the underline cursor on/off | |
325 | void Smoothiepanel::noCursor() { | |
326 | displaycontrol &= ~LCD_CURSORON; | |
327 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
328 | } | |
329 | void Smoothiepanel::cursor() { | |
330 | displaycontrol |= LCD_CURSORON; | |
331 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
332 | } | |
333 | ||
334 | // Turn on and off the blinking cursor | |
335 | void Smoothiepanel::noBlink() { | |
336 | displaycontrol &= ~LCD_BLINKON; | |
337 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
338 | } | |
339 | void Smoothiepanel::blink() { | |
340 | displaycontrol |= LCD_BLINKON; | |
341 | command(LCD_DISPLAYCONTROL | displaycontrol); | |
342 | } | |
343 | ||
344 | // These commands scroll the display without changing the RAM | |
345 | void Smoothiepanel::scrollDisplayLeft(void) { | |
346 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); | |
347 | } | |
348 | void Smoothiepanel::scrollDisplayRight(void) { | |
349 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); | |
350 | } | |
351 | ||
352 | // This is for text that flows Left to Right | |
353 | void Smoothiepanel::leftToRight(void) { | |
354 | displaymode |= LCD_ENTRYLEFT; | |
355 | command(LCD_ENTRYMODESET | displaymode); | |
356 | } | |
357 | ||
358 | // This is for text that flows Right to Left | |
359 | void Smoothiepanel::rightToLeft(void) { | |
360 | displaymode &= ~LCD_ENTRYLEFT; | |
361 | command(LCD_ENTRYMODESET | displaymode); | |
362 | } | |
363 | ||
364 | // This will 'right justify' text from the cursor | |
365 | void Smoothiepanel::autoscroll(void) { | |
366 | displaymode |= LCD_ENTRYSHIFTINCREMENT; | |
367 | command(LCD_ENTRYMODESET | displaymode); | |
368 | } | |
369 | ||
370 | // This will 'left justify' text from the cursor | |
371 | void Smoothiepanel::noAutoscroll(void) { | |
372 | displaymode &= ~LCD_ENTRYSHIFTINCREMENT; | |
373 | command(LCD_ENTRYMODESET | displaymode); | |
374 | } | |
375 | ||
376 | void Smoothiepanel::command(uint8_t value) { | |
377 | lcdbang_write(*this->i2c, value>>4, true); | |
378 | lcdbang_write(*this->i2c, value, true); | |
379 | } | |
380 | ||
f54d25cb JM |
381 | void Smoothiepanel::write(const char* line, int len) { |
382 | for (int i = 0; i < len; ++i) { | |
383 | lcdbang_write(*this->i2c, *line++); | |
384 | } | |
1c2b594a L |
385 | } |
386 | ||
387 | // Allows to set the backlight, if the LCD backpack is used | |
388 | void Smoothiepanel::setBacklight(uint8_t status) { | |
389 | /* // LED turns on when bit is cleared | |
390 | _backlightBits = M17_BIT_LB|M17_BIT_LG|M17_BIT_LR; // all off | |
391 | if (status & LED_RED) _backlightBits &= ~M17_BIT_LR; // red on | |
392 | if (status & LED_GREEN) _backlightBits &= ~M17_BIT_LG; // green on | |
393 | if (status & LED_BLUE) _backlightBits &= ~M17_BIT_LB; // blue on | |
394 | ||
395 | burstBits16(_backlightBits); | |
396 | */ | |
397 | } | |
ab4abea9 L |
398 | |
399 | void Smoothiepanel::setBacklightColor(uint8_t r, uint8_t g, uint8_t b) { | |
400 | const int leds = PCA9634_ADDRESS | this->i2c_address; | |
401 | char cmd[2]; | |
402 | ||
403 | cmd[0] = 0x07; // lcd blue | |
404 | cmd[1] = b; | |
405 | this->i2c->write(leds, cmd, 2); | |
406 | cmd[0] = 0x08; // lcd green | |
407 | cmd[1] = g; | |
408 | this->i2c->write(leds, cmd, 2); | |
409 | cmd[0] = 0x09; // lcd red | |
410 | cmd[1] = r; | |
411 | this->i2c->write(leds, cmd, 2); | |
412 | } | |
413 | ||
414 | void Smoothiepanel::setBacklightByHue(int h) { | |
415 | float r, g, b; | |
416 | HSVtoRGB(&r, &g, &b, h, 1.0, 1.0); | |
417 | setBacklightColor(r*0xFF, g*0xFF, b*0xFF); | |
418 | } | |
419 | ||
420 | void Smoothiepanel::setEncoderLED(uint8_t r, uint8_t g, uint8_t b) { | |
421 | const int leds = PCA9634_ADDRESS | this->i2c_address; | |
422 | char cmd[2]; | |
423 | ||
424 | cmd[0] = 0x04; // encoder red | |
425 | cmd[1] = r; | |
426 | this->i2c->write(leds, cmd, 2); | |
427 | cmd[0] = 0x05; // encoder green | |
428 | cmd[1] = g; | |
429 | this->i2c->write(leds, cmd, 2); | |
430 | cmd[0] = 0x06; // encoder blue | |
431 | cmd[1] = b; | |
432 | this->i2c->write(leds, cmd, 2); | |
433 | } | |
434 | ||
435 | void Smoothiepanel::setEncoderByHue(int h) { | |
436 | float r, g, b; | |
437 | HSVtoRGB(&r, &g, &b, h, 1.0, 1.0); | |
438 | setEncoderLED(r*0xFF, g*0xFF, b*0xFF); | |
439 | } | |
440 | ||
441 | void Smoothiepanel::setPlayLED(uint8_t v) { | |
442 | const int leds = PCA9634_ADDRESS | this->i2c_address; | |
443 | char cmd[2]; | |
444 | ||
445 | cmd[0] = 0x02; // play | |
446 | cmd[1] = v; | |
447 | this->i2c->write(leds, cmd, 2); | |
448 | } | |
449 | ||
450 | void Smoothiepanel::setBackLED(uint8_t v) { | |
451 | const int leds = PCA9634_ADDRESS | this->i2c_address; | |
452 | char cmd[2]; | |
453 | ||
454 | cmd[0] = 0x03; // back | |
455 | cmd[1] = v; | |
456 | this->i2c->write(leds, cmd, 2); | |
457 | } | |
458 | ||
1c2b594a L |
459 | /* |
460 | // write either command or data, burst it to the expander over I2C. | |
461 | void Smoothiepanel::send(uint8_t value, uint8_t mode) { | |
462 | #ifdef USE_FASTMODE | |
463 | // polls for ready. not sure on I2C this is any faster | |
3dc1c2aa | 464 | |
1c2b594a L |
465 | // set Data pins as input |
466 | char data[2]; | |
467 | data[0]= MCP23017_IODIRB; | |
468 | data[1]= 0x1E; | |
469 | i2c->write(this->i2c_address, data, 2); | |
470 | uint8_t b= _backlightBits >> 8; | |
3dc1c2aa | 471 | burstBits8b((M17_BIT_RW>>8)|b); // RW hi,RS lo |
1c2b594a L |
472 | char busy; |
473 | data[0] = MCP23017_GPIOB; | |
474 | do { | |
475 | burstBits8b(((M17_BIT_RW|M17_BIT_EN)>>8)|b); // EN hi | |
476 | i2c->write(this->i2c_address, data, 1); | |
477 | i2c->read(this->i2c_address, &busy, 1); // Read D7 | |
478 | burstBits8b((M17_BIT_RW>>8)|b); // EN lo | |
479 | burstBits8b(((M17_BIT_RW|M17_BIT_EN)>>8)|b); // EN hi | |
480 | burstBits8b((M17_BIT_RW>>8)|b); // EN lo | |
481 | } while ((busy&(M17_BIT_D7>>8)) != 0); | |
482 | ||
483 | // reset data bits as output | |
484 | data[0]= MCP23017_IODIRB; | |
485 | data[1]= 0x00; | |
486 | i2c->write(this->i2c_address, data, 2); | |
3dc1c2aa | 487 | burstBits8b(b); // RW lo |
1c2b594a L |
488 | |
489 | #else | |
490 | // wait_us(320); | |
491 | #endif | |
3dc1c2aa | 492 | |
1c2b594a L |
493 | // BURST SPEED, OH MY GOD |
494 | // the (now High Speed!) I/O expander pinout | |
3dc1c2aa JM |
495 | // B7 B6 B5 B4 B3 B2 B1 B0 A7 A6 A5 A4 A3 A2 A1 A0 - MCP23017 |
496 | // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |
497 | // RS RW EN D4 D5 D6 D7 B G R B4 B3 B2 B1 B0 | |
1c2b594a L |
498 | |
499 | // n.b. RW bit stays LOW to write | |
500 | uint8_t buf = _backlightBits >> 8; | |
501 | // send high 4 bits | |
502 | if (value & 0x10) buf |= M17_BIT_D4 >> 8; | |
503 | if (value & 0x20) buf |= M17_BIT_D5 >> 8; | |
504 | if (value & 0x40) buf |= M17_BIT_D6 >> 8; | |
505 | if (value & 0x80) buf |= M17_BIT_D7 >> 8; | |
3dc1c2aa | 506 | |
1c2b594a L |
507 | if (mode) buf |= (M17_BIT_RS|M17_BIT_EN) >> 8; // RS+EN |
508 | else buf |= M17_BIT_EN >> 8; // EN | |
509 | ||
510 | burstBits8b(buf); | |
511 | ||
512 | // resend w/ EN turned off | |
513 | buf &= ~(M17_BIT_EN >> 8); | |
514 | burstBits8b(buf); | |
515 | ||
516 | // send low 4 bits | |
517 | buf = _backlightBits >> 8; | |
518 | // send high 4 bits | |
519 | if (value & 0x01) buf |= M17_BIT_D4 >> 8; | |
520 | if (value & 0x02) buf |= M17_BIT_D5 >> 8; | |
521 | if (value & 0x04) buf |= M17_BIT_D6 >> 8; | |
522 | if (value & 0x08) buf |= M17_BIT_D7 >> 8; | |
3dc1c2aa | 523 | |
1c2b594a L |
524 | if (mode) buf |= (M17_BIT_RS|M17_BIT_EN) >> 8; // RS+EN |
525 | else buf |= M17_BIT_EN >> 8; // EN | |
526 | ||
527 | burstBits8b(buf); | |
528 | ||
529 | // resend w/ EN turned off | |
530 | buf &= ~(M17_BIT_EN >> 8); | |
531 | burstBits8b(buf); | |
532 | } | |
533 | ||
534 | // We pause the system | |
535 | uint32_t Smoothiepanel::on_pause_release(uint32_t dummy){ | |
536 | if(!paused) { | |
537 | THEKERNEL->pauser->take(); | |
538 | paused= true; | |
539 | }else{ | |
540 | THEKERNEL->pauser->release(); | |
541 | paused= false; | |
542 | } | |
543 | return 0; | |
544 | } | |
545 | */ | |
546 |