8 #include "lets_split.h"
9 #include "common/glcdfont.c"
10 #ifdef ADAFRUIT_BLE_ENABLE
11 #include "adafruit_ble.h"
17 #include "pincontrol.h"
19 //assign the right code to your layers
27 #define _MOUSECURSOR 256
30 // Set this to 1 to help diagnose early startup problems
31 // when testing power-on with ble. Turn it off otherwise,
32 // as the latency of printing most of the debug info messes
33 // with the matrix scan, causing keys to drop.
34 #define DEBUG_TO_SCREEN 0
36 // Controls the SSD1306 128x32 OLED display via i2c
38 #define i2cAddress 0x3C
40 #define DisplayHeight 32
41 #define DisplayWidth 128
46 #define MatrixRows (DisplayHeight / FontHeight)
47 #define MatrixCols (DisplayWidth / FontWidth)
49 struct CharacterMatrix {
50 uint8_t display[MatrixRows][MatrixCols];
55 static struct CharacterMatrix display;
56 //static uint16_t last_battery_update;
57 //static uint32_t vbat;
58 //#define BatteryUpdateInterval 10000 /* milliseconds */
59 #define ScreenOffInterval 300000 /* milliseconds */
61 static uint8_t displaying;
63 static uint16_t last_flush;
70 DisplayAllOnResume = 0xA4,
75 SetDisplayOffset = 0xD3,
78 SetDisplayClockDiv = 0xD5,
96 ActivateScroll = 0x2f,
97 DeActivateScroll = 0x2e,
98 SetVerticalScrollArea = 0xa3,
99 RightHorizontalScroll = 0x26,
100 LeftHorizontalScroll = 0x27,
101 VerticalAndRightHorizontalScroll = 0x29,
102 VerticalAndLeftHorizontalScroll = 0x2a,
106 // Write command sequence.
107 // Returns true on success.
108 static inline bool _send_cmd1(uint8_t cmd) {
111 if (i2c_start_write(i2cAddress)) {
112 xprintf("failed to start write to %d\n", i2cAddress);
116 if (i2c_master_write(0x0 /* command byte follows */)) {
117 print("failed to write control byte\n");
122 if (i2c_master_write(cmd)) {
123 xprintf("failed to write command %d\n", cmd);
132 // Write 2-byte command sequence.
133 // Returns true on success
134 static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) {
135 if (!_send_cmd1(cmd)) {
138 return _send_cmd1(opr);
141 // Write 3-byte command sequence.
142 // Returns true on success
143 static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) {
144 if (!_send_cmd1(cmd)) {
147 if (!_send_cmd1(opr1)) {
150 return _send_cmd1(opr2);
153 #define send_cmd1(c) if (!_send_cmd1(c)) {goto done;}
154 #define send_cmd2(c,o) if (!_send_cmd2(c,o)) {goto done;}
155 #define send_cmd3(c,o1,o2) if (!_send_cmd3(c,o1,o2)) {goto done;}
157 static void matrix_clear(struct CharacterMatrix *matrix);
159 static void clear_display(void) {
160 matrix_clear(&display);
162 // Clear all of the display bits (there can be random noise
163 // in the RAM on startup)
164 send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1);
165 send_cmd3(ColumnAddr, 0, DisplayWidth - 1);
167 if (i2c_start_write(i2cAddress)) {
170 if (i2c_master_write(0x40)) {
174 for (uint8_t row = 0; row < MatrixRows; ++row) {
175 for (uint8_t col = 0; col < DisplayWidth; ++col) {
180 display.dirty = false;
188 static int8_t capture_sendchar(uint8_t c) {
190 iota_gfx_write_char(c);
199 bool iota_gfx_init(void) {
200 bool success = false;
202 send_cmd1(DisplayOff);
203 send_cmd2(SetDisplayClockDiv, 0x80);
204 send_cmd2(SetMultiPlex, DisplayHeight - 1);
206 send_cmd2(SetDisplayOffset, 0);
209 send_cmd1(SetStartLine | 0x0);
210 send_cmd2(SetChargePump, 0x14 /* Enable */);
211 send_cmd2(SetMemoryMode, 0 /* horizontal addressing */);
213 /// Flips the display orientation 0 degrees
214 send_cmd1(SegRemap | 0x1);
215 send_cmd1(ComScanDec);
217 // the following Flip the display orientation 180 degrees
219 send_cmd1(ComScanInc);
221 send_cmd2(SetComPins, 0x2);
222 send_cmd2(SetContrast, 0x8f);
223 send_cmd2(SetPreCharge, 0xf1);
224 send_cmd2(SetVComDetect, 0x40);
225 send_cmd1(DisplayAllOnResume);
226 send_cmd1(NormalDisplay);
227 send_cmd1(DeActivateScroll);
228 send_cmd1(DisplayOn);
230 send_cmd2(SetContrast, 0); // Dim
239 print_set_sendchar(capture_sendchar);
246 bool iota_gfx_off(void) {
247 bool success = false;
249 send_cmd1(DisplayOff);
256 bool iota_gfx_on(void) {
257 bool success = false;
259 send_cmd1(DisplayOn);
266 static void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) {
270 if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) {
271 // We went off the end; scroll the display upwards by one line
272 memmove(&matrix->display[0], &matrix->display[1],
273 MatrixCols * (MatrixRows - 1));
274 matrix->cursor = &matrix->display[MatrixRows - 1][0];
275 memset(matrix->cursor, ' ', MatrixCols);
279 static void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
280 matrix->dirty = true;
283 // Clear to end of line from the cursor and then move to the
284 // start of the next line
285 uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols;
287 while (cursor_col++ < MatrixCols) {
288 matrix_write_char_inner(matrix, ' ');
293 matrix_write_char_inner(matrix, c);
296 void iota_gfx_write_char(uint8_t c) {
297 matrix_write_char(&display, c);
300 static void matrix_write(struct CharacterMatrix *matrix, const char *data) {
301 const char *end = data + strlen(data);
303 matrix_write_char(matrix, *data);
308 void iota_gfx_write(const char *data) {
309 matrix_write(&display, data);
312 static void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
314 uint8_t c = pgm_read_byte(data);
318 matrix_write_char(matrix, c);
323 void iota_gfx_write_P(const char *data) {
324 matrix_write_P(&display, data);
327 static void matrix_clear(struct CharacterMatrix *matrix) {
328 memset(matrix->display, ' ', sizeof(matrix->display));
329 matrix->cursor = &matrix->display[0][0];
330 matrix->dirty = true;
333 void iota_gfx_clear_screen(void) {
334 matrix_clear(&display);
337 static void matrix_render(struct CharacterMatrix *matrix) {
338 last_flush = timer_read();
344 // Move to the home position
345 send_cmd3(PageAddr, 0, MatrixRows - 1);
346 send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1);
348 if (i2c_start_write(i2cAddress)) {
351 if (i2c_master_write(0x40)) {
356 for (uint8_t row = 0; row < MatrixRows; ++row) {
357 for (uint8_t col = 0; col < MatrixCols; ++col) {
358 const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1));
360 for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) {
361 uint8_t colBits = pgm_read_byte(glyph + glyphCol);
362 i2c_master_write(colBits);
365 // 1 column of space between chars (it's not included in the glyph)
370 matrix->dirty = false;
379 void iota_gfx_flush(void) {
380 matrix_render(&display);
383 static void matrix_update(struct CharacterMatrix *dest,
384 const struct CharacterMatrix *source) {
385 if (memcmp(dest->display, source->display, sizeof(dest->display))) {
386 memcpy(dest->display, source->display, sizeof(dest->display));
391 static void render_status_info(void) {
398 struct CharacterMatrix matrix;
400 matrix_clear(&matrix);
401 matrix_write_P(&matrix, PSTR("USB: "));
403 switch (USB_DeviceState) {
404 case DEVICE_STATE_Unattached:
405 matrix_write_P(&matrix, PSTR("Unattached"));
407 case DEVICE_STATE_Suspended:
408 matrix_write_P(&matrix, PSTR("Suspended"));
410 case DEVICE_STATE_Configured:
411 matrix_write_P(&matrix, PSTR("Connected"));
413 case DEVICE_STATE_Powered:
414 matrix_write_P(&matrix, PSTR("Powered"));
416 case DEVICE_STATE_Default:
417 matrix_write_P(&matrix, PSTR("Default"));
419 case DEVICE_STATE_Addressed:
420 matrix_write_P(&matrix, PSTR("Addressed"));
423 matrix_write_P(&matrix, PSTR("Invalid"));
427 // Define layers here, Have not worked out how to have text displayed for each layer. Copy down the number you see and add a case for it below
430 snprintf(buf,sizeof(buf), "Undef-%ld", layer_state);
431 matrix_write_P(&matrix, PSTR("\n\nLayer: "));
432 switch (layer_state) {
434 matrix_write_P(&matrix, PSTR("Default"));
437 matrix_write_P(&matrix, PSTR("Raise"));
440 matrix_write_P(&matrix, PSTR("Lower"));
443 matrix_write_P(&matrix, PSTR("ADJUST"));
446 matrix_write(&matrix, buf);
449 // Host Keyboard LED Status
451 snprintf(led, sizeof(led), "\n%s %s %s",
452 (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ",
453 (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ",
454 (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " ");
455 matrix_write(&matrix, led);
456 matrix_update(&display, &matrix);
459 void iota_gfx_task(void) {
460 render_status_info();
466 if (timer_elapsed(last_flush) > ScreenOffInterval) {