aboutsummaryrefslogtreecommitdiff
path: root/drivers/oled
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/oled')
-rw-r--r--drivers/oled/glcdfont.c241
-rw-r--r--drivers/oled/oled_driver.c801
-rw-r--r--drivers/oled/oled_driver.h206
3 files changed, 507 insertions, 741 deletions
diff --git a/drivers/oled/glcdfont.c b/drivers/oled/glcdfont.c
index 8b969057e..95c5d2ebf 100644
--- a/drivers/oled/glcdfont.c
+++ b/drivers/oled/glcdfont.c
@@ -1,240 +1,25 @@
1#pragma once 1#pragma once
2 2
3#ifdef __AVR__ 3#ifdef __AVR__
4 #include <avr/io.h> 4# include <avr/io.h>
5 #include <avr/pgmspace.h> 5# include <avr/pgmspace.h>
6#elif defined(ESP8266) 6#elif defined(ESP8266)
7 #include <pgmspace.h> 7# include <pgmspace.h>
8#else 8#else
9 #define PROGMEM 9# define PROGMEM
10#endif 10#endif
11 11
12// Helidox 8x6 font with QMK Firmware Logo 12// Helidox 8x6 font with QMK Firmware Logo
13// Online editor: http://teripom.x0.com/ 13// Online editor: http://teripom.x0.com/
14 14
15static const unsigned char font[] PROGMEM = { 15static const unsigned char font[] PROGMEM = {
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
17 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 17 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
18 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 18 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
19 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 19 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
20 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 20 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
21 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 21 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xF0, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0x3F, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF8, 0xFC, 0x3E,
22 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 22 0x1E, 0x06, 0x01, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B, 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE, 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x49, 0x49, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xDF, 0xBF, 0xBF, 0x00, 0xBF, 0xBF, 0xDF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x60, 0x60, 0xE0, 0xBF, 0x1F, 0x00, 0x7F, 0x7F, 0x07, 0x1E, 0x38, 0x1E, 0x07, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x0E, 0x1F, 0x3B, 0x71, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x0C, 0x0C, 0x0C, 0x00, 0x7E, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x7E, 0x7E, 0x03, 0x03, 0x7F, 0x7E, 0x00, 0x0F,
23 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 23 0x3E, 0x70, 0x3C, 0x06, 0x3C, 0x70, 0x3E, 0x0F, 0x00, 0x32, 0x7B, 0x49, 0x49, 0x3F, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x1E, 0x3F, 0x69, 0x69, 0x6F, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3C, 0x78, 0x70, 0x60, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20, 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00, 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F, 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x07, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x7E, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 24 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25 0x00, 0x18, 0x24, 0x18, 0x00, 0x00,
26 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00,
27 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00,
28 0x26, 0x29, 0x79, 0x29, 0x26, 0x00,
29 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00,
30 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00,
31 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00,
32 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00,
33 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00,
34 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00,
35 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00,
36 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00,
37 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00,
38 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
39 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00,
40 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
41 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00,
42 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00,
43 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00,
44 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00,
45 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00,
46 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00,
47 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
50 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
51 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00,
52 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00,
53 0x23, 0x13, 0x08, 0x64, 0x62, 0x00,
54 0x36, 0x49, 0x56, 0x20, 0x50, 0x00,
55 0x00, 0x08, 0x07, 0x03, 0x00, 0x00,
56 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00,
57 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00,
58 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00,
59 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
60 0x00, 0x80, 0x70, 0x30, 0x00, 0x00,
61 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
62 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
63 0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
64 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00,
65 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
66 0x72, 0x49, 0x49, 0x49, 0x46, 0x00,
67 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00,
68 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00,
69 0x27, 0x45, 0x45, 0x45, 0x39, 0x00,
70 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00,
71 0x41, 0x21, 0x11, 0x09, 0x07, 0x00,
72 0x36, 0x49, 0x49, 0x49, 0x36, 0x00,
73 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00,
74 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
75 0x00, 0x40, 0x34, 0x00, 0x00, 0x00,
76 0x00, 0x08, 0x14, 0x22, 0x41, 0x00,
77 0x14, 0x14, 0x14, 0x14, 0x14, 0x00,
78 0x00, 0x41, 0x22, 0x14, 0x08, 0x00,
79 0x02, 0x01, 0x59, 0x09, 0x06, 0x00,
80 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00,
81 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00,
82 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00,
83 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00,
84 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00,
85 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00,
86 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00,
87 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00,
88 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00,
89 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00,
90 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
91 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00,
92 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00,
93 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00,
94 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00,
95 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00,
96 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00,
97 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00,
98 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00,
99 0x26, 0x49, 0x49, 0x49, 0x32, 0x00,
100 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00,
101 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00,
102 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00,
103 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00,
104 0x63, 0x14, 0x08, 0x14, 0x63, 0x00,
105 0x03, 0x04, 0x78, 0x04, 0x03, 0x00,
106 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
107 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00,
108 0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
109 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00,
110 0x04, 0x02, 0x01, 0x02, 0x04, 0x00,
111 0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
112 0x00, 0x03, 0x07, 0x08, 0x00, 0x00,
113 0x20, 0x54, 0x54, 0x78, 0x40, 0x00,
114 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00,
115 0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
116 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00,
117 0x38, 0x54, 0x54, 0x54, 0x18, 0x00,
118 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00,
119 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00,
120 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00,
121 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00,
122 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00,
123 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00,
124 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00,
125 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00,
126 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00,
127 0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
128 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00,
129 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00,
130 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00,
131 0x48, 0x54, 0x54, 0x54, 0x24, 0x00,
132 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00,
133 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00,
134 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00,
135 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00,
136 0x44, 0x28, 0x10, 0x28, 0x44, 0x00,
137 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00,
138 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00,
139 0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
140 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
141 0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
142 0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
143 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x40, 0x40, 0x40, 0xF0, 0xF8, 0xF8,
146 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0x3F,
147 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8,
148 0xF8, 0xF0, 0x40, 0x40, 0x40, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
150 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00,
151 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00,
152 0x80, 0xC0, 0xC0, 0x00, 0xC0, 0xC0,
153 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
155 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0xC0, 0xF0, 0xF8, 0xFC, 0x3E,
166 0x1E, 0x06, 0x01, 0x00, 0x00, 0x00,
167 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00,
168 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00,
169 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B,
170 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00,
171 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE,
172 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x49, 0x49, 0x49, 0xFF, 0xFF, 0xFF,
178 0xFF, 0xE0, 0xDF, 0xBF, 0xBF, 0x00,
179 0xBF, 0xBF, 0xDF, 0xE0, 0xFF, 0xFF,
180 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F,
182 0x60, 0x60, 0xE0, 0xBF, 0x1F, 0x00,
183 0x7F, 0x7F, 0x07, 0x1E, 0x38, 0x1E,
184 0x07, 0x7F, 0x7F, 0x00, 0x7F, 0x7F,
185 0x0E, 0x1F, 0x3B, 0x71, 0x60, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F,
187 0x0C, 0x0C, 0x0C, 0x00, 0x7E, 0x7E,
188 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00,
189 0x7F, 0x7E, 0x03, 0x03, 0x7E, 0x7E,
190 0x03, 0x03, 0x7F, 0x7E, 0x00, 0x0F,
191 0x3E, 0x70, 0x3C, 0x06, 0x3C, 0x70,
192 0x3E, 0x0F, 0x00, 0x32, 0x7B, 0x49,
193 0x49, 0x3F, 0x7E, 0x00, 0x7F, 0x7E,
194 0x03, 0x03, 0x00, 0x1E, 0x3F, 0x69,
195 0x69, 0x6F, 0x26, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3C,
198 0x78, 0x70, 0x60, 0x00, 0x00, 0x00,
199 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00,
200 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00,
201 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20,
202 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00,
203 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F,
204 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x01, 0x01, 0x01, 0x07, 0x0F, 0x0F,
210 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x7E,
211 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F,
212 0x0F, 0x07, 0x01, 0x01, 0x01, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240}; 25};
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
index 3dad72add..1a1b7299b 100644
--- a/drivers/oled/oled_driver.c
+++ b/drivers/oled/oled_driver.c
@@ -23,64 +23,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
23#include <string.h> 23#include <string.h>
24 24
25#if defined(__AVR__) 25#if defined(__AVR__)
26 #include <avr/io.h> 26# include <avr/io.h>
27 #include <avr/pgmspace.h> 27# include <avr/pgmspace.h>
28#elif defined(ESP8266) 28#elif defined(ESP8266)
29 #include <pgmspace.h> 29# include <pgmspace.h>
30#else // defined(ESP8266) 30#else // defined(ESP8266)
31 #define PROGMEM 31# define PROGMEM
32 #define memcpy_P(des, src, len) memcpy(des, src, len) 32# define memcpy_P(des, src, len) memcpy(des, src, len)
33#endif // defined(__AVR__) 33#endif // defined(__AVR__)
34 34
35// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf 35// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
36// for SH1106: https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf 36// for SH1106: https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf
37 37
38// Fundamental Commands 38// Fundamental Commands
39#define CONTRAST 0x81 39#define CONTRAST 0x81
40#define DISPLAY_ALL_ON 0xA5 40#define DISPLAY_ALL_ON 0xA5
41#define DISPLAY_ALL_ON_RESUME 0xA4 41#define DISPLAY_ALL_ON_RESUME 0xA4
42#define NORMAL_DISPLAY 0xA6 42#define NORMAL_DISPLAY 0xA6
43#define DISPLAY_ON 0xAF 43#define DISPLAY_ON 0xAF
44#define DISPLAY_OFF 0xAE 44#define DISPLAY_OFF 0xAE
45#define NOP 0xE3 45#define NOP 0xE3
46 46
47// Scrolling Commands 47// Scrolling Commands
48#define ACTIVATE_SCROLL 0x2F 48#define ACTIVATE_SCROLL 0x2F
49#define DEACTIVATE_SCROLL 0x2E 49#define DEACTIVATE_SCROLL 0x2E
50#define SCROLL_RIGHT 0x26 50#define SCROLL_RIGHT 0x26
51#define SCROLL_LEFT 0x27 51#define SCROLL_LEFT 0x27
52#define SCROLL_RIGHT_UP 0x29 52#define SCROLL_RIGHT_UP 0x29
53#define SCROLL_LEFT_UP 0x2A 53#define SCROLL_LEFT_UP 0x2A
54 54
55// Addressing Setting Commands 55// Addressing Setting Commands
56#define MEMORY_MODE 0x20 56#define MEMORY_MODE 0x20
57#define COLUMN_ADDR 0x21 57#define COLUMN_ADDR 0x21
58#define PAGE_ADDR 0x22 58#define PAGE_ADDR 0x22
59#define PAM_SETCOLUMN_LSB 0x00 59#define PAM_SETCOLUMN_LSB 0x00
60#define PAM_SETCOLUMN_MSB 0x10 60#define PAM_SETCOLUMN_MSB 0x10
61#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7 61#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
62 62
63// Hardware Configuration Commands 63// Hardware Configuration Commands
64#define DISPLAY_START_LINE 0x40 64#define DISPLAY_START_LINE 0x40
65#define SEGMENT_REMAP 0xA0 65#define SEGMENT_REMAP 0xA0
66#define SEGMENT_REMAP_INV 0xA1 66#define SEGMENT_REMAP_INV 0xA1
67#define MULTIPLEX_RATIO 0xA8 67#define MULTIPLEX_RATIO 0xA8
68#define COM_SCAN_INC 0xC0 68#define COM_SCAN_INC 0xC0
69#define COM_SCAN_DEC 0xC8 69#define COM_SCAN_DEC 0xC8
70#define DISPLAY_OFFSET 0xD3 70#define DISPLAY_OFFSET 0xD3
71#define COM_PINS 0xDA 71#define COM_PINS 0xDA
72#define COM_PINS_SEQ 0x02 72#define COM_PINS_SEQ 0x02
73#define COM_PINS_ALT 0x12 73#define COM_PINS_ALT 0x12
74#define COM_PINS_SEQ_LR 0x22 74#define COM_PINS_SEQ_LR 0x22
75#define COM_PINS_ALT_LR 0x32 75#define COM_PINS_ALT_LR 0x32
76 76
77// Timing & Driving Commands 77// Timing & Driving Commands
78#define DISPLAY_CLOCK 0xD5 78#define DISPLAY_CLOCK 0xD5
79#define PRE_CHARGE_PERIOD 0xD9 79#define PRE_CHARGE_PERIOD 0xD9
80#define VCOM_DETECT 0xDB 80#define VCOM_DETECT 0xDB
81 81
82// Charge Pump Commands 82// Charge Pump Commands
83#define CHARGE_PUMP 0x8D 83#define CHARGE_PUMP 0x8D
84 84
85// Misc defines 85// Misc defines
86#define OLED_TIMEOUT 60000 86#define OLED_TIMEOUT 60000
@@ -91,12 +91,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
91#define I2C_CMD 0x00 91#define I2C_CMD 0x00
92#define I2C_DATA 0x40 92#define I2C_DATA 0x40
93#if defined(__AVR__) 93#if defined(__AVR__)
94 // already defined on ARM 94// already defined on ARM
95 #define I2C_TIMEOUT 100 95# define I2C_TIMEOUT 100
96 #define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT) 96# define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
97#else // defined(__AVR__) 97#else // defined(__AVR__)
98 #define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT) 98# define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
99#endif // defined(__AVR__) 99#endif // defined(__AVR__)
100#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT) 100#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
101#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, I2C_TIMEOUT) 101#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, I2C_TIMEOUT)
102 102
@@ -106,19 +106,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
106// this is so we don't end up with rounding errors with 106// this is so we don't end up with rounding errors with
107// parts of the display unusable or don't get cleared correctly 107// parts of the display unusable or don't get cleared correctly
108// and also allows for drawing & inverting 108// and also allows for drawing & inverting
109uint8_t oled_buffer[OLED_MATRIX_SIZE]; 109uint8_t oled_buffer[OLED_MATRIX_SIZE];
110uint8_t* oled_cursor; 110uint8_t * oled_cursor;
111OLED_BLOCK_TYPE oled_dirty = 0; 111OLED_BLOCK_TYPE oled_dirty = 0;
112bool oled_initialized = false; 112bool oled_initialized = false;
113bool oled_active = false; 113bool oled_active = false;
114bool oled_scrolling = false; 114bool oled_scrolling = false;
115uint8_t oled_rotation = 0; 115uint8_t oled_rotation = 0;
116uint8_t oled_rotation_width = 0; 116uint8_t oled_rotation_width = 0;
117#if OLED_TIMEOUT > 0 117#if OLED_TIMEOUT > 0
118 uint32_t oled_timeout; 118uint32_t oled_timeout;
119#endif 119#endif
120#if OLED_SCROLL_TIMEOUT > 0 120#if OLED_SCROLL_TIMEOUT > 0
121 uint32_t oled_scroll_timeout; 121uint32_t oled_scroll_timeout;
122#endif 122#endif
123 123
124// Internal variables to reduce math instructions 124// Internal variables to reduce math instructions
@@ -126,468 +126,445 @@ uint8_t oled_rotation_width = 0;
126#if defined(__AVR__) 126#if defined(__AVR__)
127// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently 127// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently
128// probably should move this into i2c_master... 128// probably should move this into i2c_master...
129static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) { 129static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) {
130 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout); 130 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
131 131
132 for (uint16_t i = 0; i < length && status >= 0; i++) { 132 for (uint16_t i = 0; i < length && status >= 0; i++) {
133 status = i2c_write(pgm_read_byte((const char*)data++), timeout); 133 status = i2c_write(pgm_read_byte((const char *)data++), timeout);
134 if (status) break; 134 if (status) break;
135 } 135 }
136 136
137 i2c_stop(); 137 i2c_stop();
138 138
139 return status; 139 return status;
140} 140}
141#endif 141#endif
142 142
143// Flips the rendering bits for a character at the current cursor position 143// Flips the rendering bits for a character at the current cursor position
144static void InvertCharacter(uint8_t *cursor) 144static void InvertCharacter(uint8_t *cursor) {
145{ 145 const uint8_t *end = cursor + OLED_FONT_WIDTH;
146 const uint8_t *end = cursor + OLED_FONT_WIDTH; 146 while (cursor < end) {
147 while (cursor < end) { 147 *cursor = ~(*cursor);
148 *cursor = ~(*cursor); 148 cursor++;
149 cursor++; 149 }
150 }
151} 150}
152 151
153bool oled_init(uint8_t rotation) { 152bool oled_init(uint8_t rotation) {
154 oled_rotation = oled_init_user(rotation); 153 oled_rotation = oled_init_user(rotation);
155 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 154 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
156 oled_rotation_width = OLED_DISPLAY_WIDTH; 155 oled_rotation_width = OLED_DISPLAY_WIDTH;
157 } else { 156 } else {
158 oled_rotation_width = OLED_DISPLAY_HEIGHT; 157 oled_rotation_width = OLED_DISPLAY_HEIGHT;
159 } 158 }
160 i2c_init(); 159 i2c_init();
161 160
162 static const uint8_t PROGMEM display_setup1[] = { 161 static const uint8_t PROGMEM display_setup1[] = {
163 I2C_CMD, 162 I2C_CMD,
164 DISPLAY_OFF, 163 DISPLAY_OFF,
165 DISPLAY_CLOCK, 0x80, 164 DISPLAY_CLOCK,
166 MULTIPLEX_RATIO, OLED_DISPLAY_HEIGHT - 1, 165 0x80,
167 DISPLAY_OFFSET, 0x00, 166 MULTIPLEX_RATIO,
168 DISPLAY_START_LINE | 0x00, 167 OLED_DISPLAY_HEIGHT - 1,
169 CHARGE_PUMP, 0x14, 168 DISPLAY_OFFSET,
169 0x00,
170 DISPLAY_START_LINE | 0x00,
171 CHARGE_PUMP,
172 0x14,
170#if (OLED_IC != OLED_IC_SH1106) 173#if (OLED_IC != OLED_IC_SH1106)
171 // MEMORY_MODE is unsupported on SH1106 (Page Addressing only) 174 // MEMORY_MODE is unsupported on SH1106 (Page Addressing only)
172 MEMORY_MODE, 0x00, // Horizontal addressing mode 175 MEMORY_MODE,
176 0x00, // Horizontal addressing mode
173#endif 177#endif
174 }; 178 };
175 if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) { 179 if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {
176 print("oled_init cmd set 1 failed\n"); 180 print("oled_init cmd set 1 failed\n");
177 return false; 181 return false;
178 } 182 }
179 183
180 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) { 184 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) {
181 static const uint8_t PROGMEM display_normal[] = { 185 static const uint8_t PROGMEM display_normal[] = {I2C_CMD, SEGMENT_REMAP_INV, COM_SCAN_DEC};
182 I2C_CMD, 186 if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
183 SEGMENT_REMAP_INV, 187 print("oled_init cmd normal rotation failed\n");
184 COM_SCAN_DEC }; 188 return false;
185 if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) { 189 }
186 print("oled_init cmd normal rotation failed\n"); 190 } else {
187 return false; 191 static const uint8_t PROGMEM display_flipped[] = {I2C_CMD, SEGMENT_REMAP, COM_SCAN_INC};
188 } 192 if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) {
189 } else { 193 print("display_flipped failed\n");
190 static const uint8_t PROGMEM display_flipped[] = { 194 return false;
191 I2C_CMD, 195 }
192 SEGMENT_REMAP, 196 }
193 COM_SCAN_INC }; 197
194 if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) { 198 static const uint8_t PROGMEM display_setup2[] = {I2C_CMD, COM_PINS, OLED_COM_PINS, CONTRAST, 0x8F, PRE_CHARGE_PERIOD, 0xF1, VCOM_DETECT, 0x40, DISPLAY_ALL_ON_RESUME, NORMAL_DISPLAY, DEACTIVATE_SCROLL, DISPLAY_ON};
195 print("display_flipped failed\n"); 199 if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) {
196 return false; 200 print("display_setup2 failed\n");
197 } 201 return false;
198 } 202 }
199
200 static const uint8_t PROGMEM display_setup2[] = {
201 I2C_CMD,
202 COM_PINS, OLED_COM_PINS,
203 CONTRAST, 0x8F,
204 PRE_CHARGE_PERIOD, 0xF1,
205 VCOM_DETECT, 0x40,
206 DISPLAY_ALL_ON_RESUME,
207 NORMAL_DISPLAY,
208 DEACTIVATE_SCROLL,
209 DISPLAY_ON };
210 if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) {
211 print("display_setup2 failed\n");
212 return false;
213 }
214 203
215#if OLED_TIMEOUT > 0 204#if OLED_TIMEOUT > 0
216 oled_timeout = timer_read32() + OLED_TIMEOUT; 205 oled_timeout = timer_read32() + OLED_TIMEOUT;
217#endif 206#endif
218#if OLED_SCROLL_TIMEOUT > 0 207#if OLED_SCROLL_TIMEOUT > 0
219 oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT; 208 oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
220#endif 209#endif
221 210
222 oled_clear(); 211 oled_clear();
223 oled_initialized = true; 212 oled_initialized = true;
224 oled_active = true; 213 oled_active = true;
225 oled_scrolling = false; 214 oled_scrolling = false;
226 return true; 215 return true;
227} 216}
228 217
229__attribute__((weak)) 218__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; }
230oled_rotation_t oled_init_user(oled_rotation_t rotation) {
231 return rotation;
232}
233 219
234void oled_clear(void) { 220void oled_clear(void) {
235 memset(oled_buffer, 0, sizeof(oled_buffer)); 221 memset(oled_buffer, 0, sizeof(oled_buffer));
236 oled_cursor = &oled_buffer[0]; 222 oled_cursor = &oled_buffer[0];
237 oled_dirty = -1; // -1 will be max value as long as display_dirty is unsigned type 223 oled_dirty = -1; // -1 will be max value as long as display_dirty is unsigned type
238} 224}
239 225
240static void calc_bounds(uint8_t update_start, uint8_t* cmd_array) 226static void calc_bounds(uint8_t update_start, uint8_t *cmd_array) {
241{ 227 // Calculate commands to set memory addressing bounds.
242 // Calculate commands to set memory addressing bounds. 228 uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
243 uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH; 229 uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
244 uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
245#if (OLED_IC == OLED_IC_SH1106) 230#if (OLED_IC == OLED_IC_SH1106)
246 // Commands for Page Addressing Mode. Sets starting page and column; has no end bound. 231 // Commands for Page Addressing Mode. Sets starting page and column; has no end bound.
247 // Column value must be split into high and low nybble and sent as two commands. 232 // Column value must be split into high and low nybble and sent as two commands.
248 cmd_array[0] = PAM_PAGE_ADDR | start_page; 233 cmd_array[0] = PAM_PAGE_ADDR | start_page;
249 cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f); 234 cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
250 cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f); 235 cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
251 cmd_array[3] = NOP; 236 cmd_array[3] = NOP;
252 cmd_array[4] = NOP; 237 cmd_array[4] = NOP;
253 cmd_array[5] = NOP; 238 cmd_array[5] = NOP;
254#else 239#else
255 // Commands for use in Horizontal Addressing mode. 240 // Commands for use in Horizontal Addressing mode.
256 cmd_array[1] = start_column; 241 cmd_array[1] = start_column;
257 cmd_array[4] = start_page; 242 cmd_array[4] = start_page;
258 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1]; 243 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1];
259 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1; 244 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1;
260#endif 245#endif
261} 246}
262 247
263static void calc_bounds_90(uint8_t update_start, uint8_t* cmd_array) 248static void calc_bounds_90(uint8_t update_start, uint8_t *cmd_array) {
264{ 249 cmd_array[1] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8;
265 cmd_array[1] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8; 250 cmd_array[4] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT;
266 cmd_array[4] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT; 251 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8 - 1 + cmd_array[1];
267 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8 - 1 + cmd_array[1];; 252 ;
268 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) % OLED_DISPLAY_HEIGHT / 8; 253 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) % OLED_DISPLAY_HEIGHT / 8;
269} 254}
270 255
271uint8_t crot(uint8_t a, int8_t n) 256uint8_t crot(uint8_t a, int8_t n) {
272{ 257 const uint8_t mask = 0x7;
273 const uint8_t mask = 0x7; 258 n &= mask;
274 n &= mask; 259 return a << n | a >> (-n & mask);
275 return a << n | a >> (-n & mask);
276} 260}
277 261
278static void rotate_90(const uint8_t* src, uint8_t* dest) 262static void rotate_90(const uint8_t *src, uint8_t *dest) {
279{ 263 for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) {
280 for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) { 264 uint8_t selector = (1 << i);
281 uint8_t selector = (1 << i); 265 for (uint8_t j = 0; j < 8; ++j) {
282 for (uint8_t j = 0; j < 8; ++j) { 266 dest[i] |= crot(src[j] & selector, shift - (int8_t)j);
283 dest[i] |= crot(src[j] & selector, shift - (int8_t)j); 267 }
284 } 268 }
285 }
286} 269}
287 270
288void oled_render(void) { 271void oled_render(void) {
289 // Do we have work to do? 272 // Do we have work to do?
290 if (!oled_dirty || oled_scrolling) { 273 if (!oled_dirty || oled_scrolling) {
291 return; 274 return;
292 } 275 }
293 276
294 // Find first dirty block 277 // Find first dirty block
295 uint8_t update_start = 0; 278 uint8_t update_start = 0;
296 while (!(oled_dirty & (1 << update_start))) { ++update_start; } 279 while (!(oled_dirty & (1 << update_start))) {
297 280 ++update_start;
298 // Set column & page position 281 }
299 static uint8_t display_start[] = { 282
300 I2C_CMD, 283 // Set column & page position
301 COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, 284 static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
302 PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1 }; 285 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
303 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 286 calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
304 calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start 287 } else {
305 } else { 288 calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
306 calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start 289 }
307 } 290
308 291 // Send column & page position
309 // Send column & page position 292 if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
310 if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) { 293 print("oled_render offset command failed\n");
311 print("oled_render offset command failed\n"); 294 return;
312 return; 295 }
313 } 296
314 297 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
315 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 298 // Send render data chunk as is
316 // Send render data chunk as is 299 if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
317 if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) { 300 print("oled_render data failed\n");
318 print("oled_render data failed\n"); 301 return;
319 return; 302 }
320 } 303 } else {
321 } else { 304 // Rotate the render chunks
322 // Rotate the render chunks 305 const static uint8_t source_map[] = OLED_SOURCE_MAP;
323 const static uint8_t source_map[] = OLED_SOURCE_MAP; 306 const static uint8_t target_map[] = OLED_TARGET_MAP;
324 const static uint8_t target_map[] = OLED_TARGET_MAP; 307
325 308 static uint8_t temp_buffer[OLED_BLOCK_SIZE];
326 static uint8_t temp_buffer[OLED_BLOCK_SIZE]; 309 memset(temp_buffer, 0, sizeof(temp_buffer));
327 memset(temp_buffer, 0, sizeof(temp_buffer)); 310 for (uint8_t i = 0; i < sizeof(source_map); ++i) {
328 for(uint8_t i = 0; i < sizeof(source_map); ++i) { 311 rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
329 rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]); 312 }
330 } 313
331 314 // Send render data chunk after rotating
332 // Send render data chunk after rotating 315 if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
333 if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) { 316 print("oled_render90 data failed\n");
334 print("oled_render90 data failed\n"); 317 return;
335 return; 318 }
336 } 319 }
337 } 320
338 321 // Turn on display if it is off
339 // Turn on display if it is off 322 oled_on();
340 oled_on(); 323
341 324 // Clear dirty flag
342 // Clear dirty flag 325 oled_dirty &= ~(1 << update_start);
343 oled_dirty &= ~(1 << update_start);
344} 326}
345 327
346void oled_set_cursor(uint8_t col, uint8_t line) { 328void oled_set_cursor(uint8_t col, uint8_t line) {
347 uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH; 329 uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH;
348 330
349 // Out of bounds? 331 // Out of bounds?
350 if (index >= OLED_MATRIX_SIZE) { 332 if (index >= OLED_MATRIX_SIZE) {
351 index = 0; 333 index = 0;
352 } 334 }
353 335
354 oled_cursor = &oled_buffer[index]; 336 oled_cursor = &oled_buffer[index];
355} 337}
356 338
357void oled_advance_page(bool clearPageRemainder) { 339void oled_advance_page(bool clearPageRemainder) {
358 uint16_t index = oled_cursor - &oled_buffer[0]; 340 uint16_t index = oled_cursor - &oled_buffer[0];
359 uint8_t remaining = oled_rotation_width - (index % oled_rotation_width); 341 uint8_t remaining = oled_rotation_width - (index % oled_rotation_width);
360 342
361 if (clearPageRemainder) { 343 if (clearPageRemainder) {
362 // Remaining Char count 344 // Remaining Char count
363 remaining = remaining / OLED_FONT_WIDTH; 345 remaining = remaining / OLED_FONT_WIDTH;
364 346
365 // Write empty character until next line 347 // Write empty character until next line
366 while (remaining--) 348 while (remaining--) oled_write_char(' ', false);
367 oled_write_char(' ', false); 349 } else {
368 } else { 350 // Next page index out of bounds?
369 // Next page index out of bounds? 351 if (index + remaining >= OLED_MATRIX_SIZE) {
370 if (index + remaining >= OLED_MATRIX_SIZE) { 352 index = 0;
371 index = 0; 353 remaining = 0;
372 remaining = 0; 354 }
355
356 oled_cursor = &oled_buffer[index + remaining];
373 } 357 }
374
375 oled_cursor = &oled_buffer[index + remaining];
376 }
377} 358}
378 359
379void oled_advance_char(void) { 360void oled_advance_char(void) {
380 uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH; 361 uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH;
381 uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width); 362 uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width);
382 363
383 // Do we have enough space on the current line for the next character 364 // Do we have enough space on the current line for the next character
384 if (remainingSpace < OLED_FONT_WIDTH) { 365 if (remainingSpace < OLED_FONT_WIDTH) {
385 nextIndex += remainingSpace; 366 nextIndex += remainingSpace;
386 } 367 }
387 368
388 // Did we go out of bounds 369 // Did we go out of bounds
389 if (nextIndex >= OLED_MATRIX_SIZE) { 370 if (nextIndex >= OLED_MATRIX_SIZE) {
390 nextIndex = 0; 371 nextIndex = 0;
391 } 372 }
392 373
393 // Update cursor position 374 // Update cursor position
394 oled_cursor = &oled_buffer[nextIndex]; 375 oled_cursor = &oled_buffer[nextIndex];
395} 376}
396 377
397// Main handler that writes character data to the display buffer 378// Main handler that writes character data to the display buffer
398void oled_write_char(const char data, bool invert) { 379void oled_write_char(const char data, bool invert) {
399 // Advance to the next line if newline 380 // Advance to the next line if newline
400 if (data == '\n') { 381 if (data == '\n') {
401 // Old source wrote ' ' until end of line... 382 // Old source wrote ' ' until end of line...
402 oled_advance_page(true); 383 oled_advance_page(true);
403 return; 384 return;
404 } 385 }
405 386
406 if (data == '\r') { 387 if (data == '\r') {
407 oled_advance_page(false); 388 oled_advance_page(false);
408 return; 389 return;
409 } 390 }
410 391
411 // copy the current render buffer to check for dirty after 392 // copy the current render buffer to check for dirty after
412 static uint8_t oled_temp_buffer[OLED_FONT_WIDTH]; 393 static uint8_t oled_temp_buffer[OLED_FONT_WIDTH];
413 memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH); 394 memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH);
414 395
415 // set the reder buffer data 396 // set the reder buffer data
416 uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index 397 uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
417 if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) { 398 if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) {
418 memset(oled_cursor, 0x00, OLED_FONT_WIDTH); 399 memset(oled_cursor, 0x00, OLED_FONT_WIDTH);
419 } else { 400 } else {
420 const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH]; 401 const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH];
421 memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH); 402 memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH);
422 } 403 }
423 404
424 // Invert if needed 405 // Invert if needed
425 if (invert) { 406 if (invert) {
426 InvertCharacter(oled_cursor); 407 InvertCharacter(oled_cursor);
427 } 408 }
428 409
429 // Dirty check 410 // Dirty check
430 if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) { 411 if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) {
431 uint16_t index = oled_cursor - &oled_buffer[0]; 412 uint16_t index = oled_cursor - &oled_buffer[0];
432 oled_dirty |= (1 << (index / OLED_BLOCK_SIZE)); 413 oled_dirty |= (1 << (index / OLED_BLOCK_SIZE));
433 // Edgecase check if the written data spans the 2 chunks 414 // Edgecase check if the written data spans the 2 chunks
434 oled_dirty |= (1 << ((index + OLED_FONT_WIDTH) / OLED_BLOCK_SIZE)); 415 oled_dirty |= (1 << ((index + OLED_FONT_WIDTH) / OLED_BLOCK_SIZE));
435 } 416 }
436 417
437 // Finally move to the next char 418 // Finally move to the next char
438 oled_advance_char(); 419 oled_advance_char();
439} 420}
440 421
441void oled_write(const char *data, bool invert) { 422void oled_write(const char *data, bool invert) {
442 const char *end = data + strlen(data); 423 const char *end = data + strlen(data);
443 while (data < end) { 424 while (data < end) {
444 oled_write_char(*data, invert); 425 oled_write_char(*data, invert);
445 data++; 426 data++;
446 } 427 }
447} 428}
448 429
449void oled_write_ln(const char *data, bool invert) { 430void oled_write_ln(const char *data, bool invert) {
450 oled_write(data, invert); 431 oled_write(data, invert);
451 oled_advance_page(true); 432 oled_advance_page(true);
452} 433}
453 434
454#if defined(__AVR__) 435#if defined(__AVR__)
455void oled_write_P(const char *data, bool invert) { 436void oled_write_P(const char *data, bool invert) {
456 uint8_t c = pgm_read_byte(data); 437 uint8_t c = pgm_read_byte(data);
457 while (c != 0) { 438 while (c != 0) {
458 oled_write_char(c, invert); 439 oled_write_char(c, invert);
459 c = pgm_read_byte(++data); 440 c = pgm_read_byte(++data);
460 } 441 }
461} 442}
462 443
463void oled_write_ln_P(const char *data, bool invert) { 444void oled_write_ln_P(const char *data, bool invert) {
464 oled_write_P(data, invert); 445 oled_write_P(data, invert);
465 oled_advance_page(true); 446 oled_advance_page(true);
466} 447}
467#endif // defined(__AVR__) 448#endif // defined(__AVR__)
468 449
469bool oled_on(void) { 450bool oled_on(void) {
470#if OLED_TIMEOUT > 0 451#if OLED_TIMEOUT > 0
471 oled_timeout = timer_read32() + OLED_TIMEOUT; 452 oled_timeout = timer_read32() + OLED_TIMEOUT;
472#endif 453#endif
473 454
474 static const uint8_t PROGMEM display_on[] = { I2C_CMD, DISPLAY_ON }; 455 static const uint8_t PROGMEM display_on[] = {I2C_CMD, DISPLAY_ON};
475 if (!oled_active) { 456 if (!oled_active) {
476 if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) { 457 if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) {
477 print("oled_on cmd failed\n"); 458 print("oled_on cmd failed\n");
478 return oled_active; 459 return oled_active;
460 }
461 oled_active = true;
479 } 462 }
480 oled_active = true; 463 return oled_active;
481 }
482 return oled_active;
483} 464}
484 465
485bool oled_off(void) { 466bool oled_off(void) {
486 static const uint8_t PROGMEM display_off[] = { I2C_CMD, DISPLAY_OFF }; 467 static const uint8_t PROGMEM display_off[] = {I2C_CMD, DISPLAY_OFF};
487 if (oled_active) { 468 if (oled_active) {
488 if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) { 469 if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) {
489 print("oled_off cmd failed\n"); 470 print("oled_off cmd failed\n");
490 return oled_active; 471 return oled_active;
491 } 472 }
492 oled_active = false; 473 oled_active = false;
493 } 474 }
494 return !oled_active; 475 return !oled_active;
495} 476}
496 477
497bool oled_scroll_right(void) { 478bool oled_scroll_right(void) {
498 // Dont enable scrolling if we need to update the display 479 // Dont enable scrolling if we need to update the display
499 // This prevents scrolling of bad data from starting the scroll too early after init 480 // This prevents scrolling of bad data from starting the scroll too early after init
500 if (!oled_dirty && !oled_scrolling) { 481 if (!oled_dirty && !oled_scrolling) {
501 static const uint8_t PROGMEM display_scroll_right[] = { 482 static const uint8_t PROGMEM display_scroll_right[] = {I2C_CMD, SCROLL_RIGHT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL};
502 I2C_CMD, SCROLL_RIGHT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL }; 483 if (I2C_TRANSMIT_P(display_scroll_right) != I2C_STATUS_SUCCESS) {
503 if (I2C_TRANSMIT_P(display_scroll_right) != I2C_STATUS_SUCCESS) { 484 print("oled_scroll_right cmd failed\n");
504 print("oled_scroll_right cmd failed\n"); 485 return oled_scrolling;
505 return oled_scrolling; 486 }
506 } 487 oled_scrolling = true;
507 oled_scrolling = true; 488 }
508 } 489 return oled_scrolling;
509 return oled_scrolling;
510} 490}
511 491
512bool oled_scroll_left(void) { 492bool oled_scroll_left(void) {
513 // Dont enable scrolling if we need to update the display 493 // Dont enable scrolling if we need to update the display
514 // This prevents scrolling of bad data from starting the scroll too early after init 494 // This prevents scrolling of bad data from starting the scroll too early after init
515 if (!oled_dirty && !oled_scrolling) { 495 if (!oled_dirty && !oled_scrolling) {
516 static const uint8_t PROGMEM display_scroll_left[] = { 496 static const uint8_t PROGMEM display_scroll_left[] = {I2C_CMD, SCROLL_LEFT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL};
517 I2C_CMD, SCROLL_LEFT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL }; 497 if (I2C_TRANSMIT_P(display_scroll_left) != I2C_STATUS_SUCCESS) {
518 if (I2C_TRANSMIT_P(display_scroll_left) != I2C_STATUS_SUCCESS) { 498 print("oled_scroll_left cmd failed\n");
519 print("oled_scroll_left cmd failed\n"); 499 return oled_scrolling;
520 return oled_scrolling; 500 }
521 } 501 oled_scrolling = true;
522 oled_scrolling = true; 502 }
523 } 503 return oled_scrolling;
524 return oled_scrolling;
525} 504}
526 505
527bool oled_scroll_off(void) { 506bool oled_scroll_off(void) {
528 if (oled_scrolling) { 507 if (oled_scrolling) {
529 static const uint8_t PROGMEM display_scroll_off[] = { I2C_CMD, DEACTIVATE_SCROLL }; 508 static const uint8_t PROGMEM display_scroll_off[] = {I2C_CMD, DEACTIVATE_SCROLL};
530 if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) { 509 if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) {
531 print("oled_scroll_off cmd failed\n"); 510 print("oled_scroll_off cmd failed\n");
532 return oled_scrolling; 511 return oled_scrolling;
533 } 512 }
534 oled_scrolling = false; 513 oled_scrolling = false;
535 oled_dirty = -1; 514 oled_dirty = -1;
536 } 515 }
537 return !oled_scrolling; 516 return !oled_scrolling;
538} 517}
539 518
540uint8_t oled_max_chars(void) { 519uint8_t oled_max_chars(void) {
541 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 520 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
542 return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH; 521 return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH;
543 } 522 }
544 return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH; 523 return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH;
545} 524}
546 525
547uint8_t oled_max_lines(void) { 526uint8_t oled_max_lines(void) {
548 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 527 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
549 return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT; 528 return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT;
550 } 529 }
551 return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT; 530 return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT;
552} 531}
553 532
554void oled_task(void) { 533void oled_task(void) {
555 if (!oled_initialized) { 534 if (!oled_initialized) {
556 return; 535 return;
557 } 536 }
558 537
559 oled_set_cursor(0, 0); 538 oled_set_cursor(0, 0);
560 539
561 oled_task_user(); 540 oled_task_user();
562 541
563#if OLED_SCROLL_TIMEOUT > 0 542#if OLED_SCROLL_TIMEOUT > 0
564 if (oled_dirty && oled_scrolling) { 543 if (oled_dirty && oled_scrolling) {
565 oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT; 544 oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
566 oled_scroll_off(); 545 oled_scroll_off();
567 } 546 }
568#endif 547#endif
569 548
570 // Smart render system, no need to check for dirty 549 // Smart render system, no need to check for dirty
571 oled_render(); 550 oled_render();
572 551
573 // Display timeout check 552 // Display timeout check
574#if OLED_TIMEOUT > 0 553#if OLED_TIMEOUT > 0
575 if (oled_active && timer_expired32(timer_read32(), oled_timeout)) { 554 if (oled_active && timer_expired32(timer_read32(), oled_timeout)) {
576 oled_off(); 555 oled_off();
577 } 556 }
578#endif 557#endif
579 558
580#if OLED_SCROLL_TIMEOUT > 0 559#if OLED_SCROLL_TIMEOUT > 0
581 if (!oled_scrolling && timer_expired32(timer_read32(), oled_scroll_timeout)) { 560 if (!oled_scrolling && timer_expired32(timer_read32(), oled_scroll_timeout)) {
582#ifdef OLED_SCROLL_TIMEOUT_RIGHT 561# ifdef OLED_SCROLL_TIMEOUT_RIGHT
583 oled_scroll_right(); 562 oled_scroll_right();
584#else 563# else
585 oled_scroll_left(); 564 oled_scroll_left();
586#endif 565# endif
587 } 566 }
588#endif 567#endif
589} 568}
590 569
591__attribute__((weak)) 570__attribute__((weak)) void oled_task_user(void) {}
592void oled_task_user(void) {
593}
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index 4f6254c98..ac8a1c765 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -21,129 +21,133 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
21 21
22// an enumeration of the chips this driver supports 22// an enumeration of the chips this driver supports
23#define OLED_IC_SSD1306 0 23#define OLED_IC_SSD1306 0
24#define OLED_IC_SH1106 1 24#define OLED_IC_SH1106 1
25 25
26#if defined(OLED_DISPLAY_CUSTOM) 26#if defined(OLED_DISPLAY_CUSTOM)
27 // Expected user to implement the necessary defines 27// Expected user to implement the necessary defines
28#elif defined(OLED_DISPLAY_128X64) 28#elif defined(OLED_DISPLAY_128X64)
29 // Double height 128x64 29// Double height 128x64
30#ifndef OLED_DISPLAY_WIDTH 30# ifndef OLED_DISPLAY_WIDTH
31 #define OLED_DISPLAY_WIDTH 128 31# define OLED_DISPLAY_WIDTH 128
32#endif 32# endif
33#ifndef OLED_DISPLAY_HEIGHT 33# ifndef OLED_DISPLAY_HEIGHT
34 #define OLED_DISPLAY_HEIGHT 64 34# define OLED_DISPLAY_HEIGHT 64
35#endif 35# endif
36#ifndef OLED_MATRIX_SIZE 36# ifndef OLED_MATRIX_SIZE
37 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed) 37# define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed)
38#endif 38# endif
39#ifndef OLED_BLOCK_TYPE 39# ifndef OLED_BLOCK_TYPE
40 #define OLED_BLOCK_TYPE uint16_t 40# define OLED_BLOCK_TYPE uint16_t
41#endif 41# endif
42#ifndef OLED_BLOCK_COUNT 42# ifndef OLED_BLOCK_COUNT
43 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed) 43# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed)
44#endif 44# endif
45#ifndef OLED_BLOCK_SIZE 45# ifndef OLED_BLOCK_SIZE
46 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed) 46# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
47#endif 47# endif
48#ifndef OLED_COM_PINS 48# ifndef OLED_COM_PINS
49 #define OLED_COM_PINS COM_PINS_ALT 49# define OLED_COM_PINS COM_PINS_ALT
50#endif 50# endif
51 51
52 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays 52// For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
53 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode 53// The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
54#ifndef OLED_SOURCE_MAP 54# ifndef OLED_SOURCE_MAP
55 #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 } 55# define OLED_SOURCE_MAP \
56#endif 56 { 0, 8, 16, 24, 32, 40, 48, 56 }
57#ifndef OLED_TARGET_MAP 57# endif
58 #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 } 58# ifndef OLED_TARGET_MAP
59#endif 59# define OLED_TARGET_MAP \
60 // If OLED_BLOCK_TYPE is uint32_t, these tables would look like: 60 { 56, 48, 40, 32, 24, 16, 8, 0 }
61 // #define OLED_SOURCE_MAP { 32, 40, 48, 56 } 61# endif
62 // #define OLED_TARGET_MAP { 24, 16, 8, 0 } 62// If OLED_BLOCK_TYPE is uint32_t, these tables would look like:
63 // If OLED_BLOCK_TYPE is uint16_t, these tables would look like: 63// #define OLED_SOURCE_MAP { 32, 40, 48, 56 }
64 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 } 64// #define OLED_TARGET_MAP { 24, 16, 8, 0 }
65 // #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 } 65// If OLED_BLOCK_TYPE is uint16_t, these tables would look like:
66 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like: 66// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
67 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 } 67// #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 }
68 // #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 } 68// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
69#else // defined(OLED_DISPLAY_128X64) 69// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }
70 // Default 128x32 70// #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 }
71#ifndef OLED_DISPLAY_WIDTH 71#else // defined(OLED_DISPLAY_128X64)
72 #define OLED_DISPLAY_WIDTH 128 72// Default 128x32
73#endif 73# ifndef OLED_DISPLAY_WIDTH
74#ifndef OLED_DISPLAY_HEIGHT 74# define OLED_DISPLAY_WIDTH 128
75 #define OLED_DISPLAY_HEIGHT 32 75# endif
76#endif 76# ifndef OLED_DISPLAY_HEIGHT
77#ifndef OLED_MATRIX_SIZE 77# define OLED_DISPLAY_HEIGHT 32
78 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed) 78# endif
79#endif 79# ifndef OLED_MATRIX_SIZE
80#ifndef OLED_BLOCK_TYPE 80# define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
81 #define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only 81# endif
82#endif 82# ifndef OLED_BLOCK_TYPE
83#ifndef OLED_BLOCK_COUNT 83# define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
84 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed) 84# endif
85#endif 85# ifndef OLED_BLOCK_COUNT
86#ifndef OLED_BLOCK_SIZE 86# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed)
87 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed) 87# endif
88#endif 88# ifndef OLED_BLOCK_SIZE
89#ifndef OLED_COM_PINS 89# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
90 #define OLED_COM_PINS COM_PINS_SEQ 90# endif
91#endif 91# ifndef OLED_COM_PINS
92 92# define OLED_COM_PINS COM_PINS_SEQ
93 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays 93# endif
94 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode 94
95#ifndef OLED_SOURCE_MAP 95// For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
96 #define OLED_SOURCE_MAP { 0, 8, 16, 24 } 96// The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
97#endif 97# ifndef OLED_SOURCE_MAP
98#ifndef OLED_TARGET_MAP 98# define OLED_SOURCE_MAP \
99 #define OLED_TARGET_MAP { 24, 16, 8, 0 } 99 { 0, 8, 16, 24 }
100#endif 100# endif
101 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like: 101# ifndef OLED_TARGET_MAP
102 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 } 102# define OLED_TARGET_MAP \
103 // #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 } 103 { 24, 16, 8, 0 }
104#endif // defined(OLED_DISPLAY_CUSTOM) 104# endif
105// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
106// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
107// #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
108#endif // defined(OLED_DISPLAY_CUSTOM)
105 109
106#if !defined(OLED_IC) 110#if !defined(OLED_IC)
107 #define OLED_IC OLED_IC_SSD1306 111# define OLED_IC OLED_IC_SSD1306
108#endif 112#endif
109 113
110// the column address corresponding to the first column in the display hardware 114// the column address corresponding to the first column in the display hardware
111#if !defined(OLED_COLUMN_OFFSET) 115#if !defined(OLED_COLUMN_OFFSET)
112 #define OLED_COLUMN_OFFSET 0 116# define OLED_COLUMN_OFFSET 0
113#endif 117#endif
114 118
115// Address to use for the i2c oled communication 119// Address to use for the i2c oled communication
116#if !defined(OLED_DISPLAY_ADDRESS) 120#if !defined(OLED_DISPLAY_ADDRESS)
117 #define OLED_DISPLAY_ADDRESS 0x3C 121# define OLED_DISPLAY_ADDRESS 0x3C
118#endif 122#endif
119 123
120// Custom font file to use 124// Custom font file to use
121#if !defined(OLED_FONT_H) 125#if !defined(OLED_FONT_H)
122 #define OLED_FONT_H "glcdfont.c" 126# define OLED_FONT_H "glcdfont.c"
123#endif 127#endif
124// unsigned char value of the first character in the font file 128// unsigned char value of the first character in the font file
125#if !defined(OLED_FONT_START) 129#if !defined(OLED_FONT_START)
126 #define OLED_FONT_START 0 130# define OLED_FONT_START 0
127#endif 131#endif
128// unsigned char value of the last character in the font file 132// unsigned char value of the last character in the font file
129#if !defined(OLED_FONT_END) 133#if !defined(OLED_FONT_END)
130 #define OLED_FONT_END 224 134# define OLED_FONT_END 224
131#endif 135#endif
132// Font render width 136// Font render width
133#if !defined(OLED_FONT_WIDTH) 137#if !defined(OLED_FONT_WIDTH)
134 #define OLED_FONT_WIDTH 6 138# define OLED_FONT_WIDTH 6
135#endif 139#endif
136// Font render height 140// Font render height
137#if !defined(OLED_FONT_HEIGHT) 141#if !defined(OLED_FONT_HEIGHT)
138 #define OLED_FONT_HEIGHT 8 142# define OLED_FONT_HEIGHT 8
139#endif 143#endif
140 144
141#if !defined(OLED_TIMEOUT) 145#if !defined(OLED_TIMEOUT)
142 #if defined(OLED_DISABLE_TIMEOUT) 146# if defined(OLED_DISABLE_TIMEOUT)
143 #define OLED_TIMEOUT 0 147# define OLED_TIMEOUT 0
144 #else 148# else
145 #define OLED_TIMEOUT 60000 149# define OLED_TIMEOUT 60000
146 #endif 150# endif
147#endif 151#endif
148 152
149// OLED Rotation enum values are flags 153// OLED Rotation enum values are flags
@@ -151,7 +155,7 @@ typedef enum {
151 OLED_ROTATION_0 = 0, 155 OLED_ROTATION_0 = 0,
152 OLED_ROTATION_90 = 1, 156 OLED_ROTATION_90 = 1,
153 OLED_ROTATION_180 = 2, 157 OLED_ROTATION_180 = 2,
154 OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180 158 OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
155} oled_rotation_t; 159} oled_rotation_t;
156 160
157// Initialize the oled display, rotating the rendered output based on the define passed in. 161// Initialize the oled display, rotating the rendered output based on the define passed in.
@@ -208,15 +212,15 @@ void oled_write_P(const char *data, bool invert);
208// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM 212// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM
209void oled_write_ln_P(const char *data, bool invert); 213void oled_write_ln_P(const char *data, bool invert);
210#else 214#else
211 // Writes a string to the buffer at current cursor position 215// Writes a string to the buffer at current cursor position
212 // Advances the cursor while writing, inverts the pixels if true 216// Advances the cursor while writing, inverts the pixels if true
213 #define oled_write_P(data, invert) oled_write(data, invert) 217# define oled_write_P(data, invert) oled_write(data, invert)
214 218
215 // Writes a string to the buffer at current cursor position 219// Writes a string to the buffer at current cursor position
216 // Advances the cursor while writing, inverts the pixels if true 220// Advances the cursor while writing, inverts the pixels if true
217 // Advances the cursor to the next page, wiring ' ' to the remainder of the current page 221// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
218 #define oled_write_ln_P(data, invert) oled_write(data, invert) 222# define oled_write_ln_P(data, invert) oled_write(data, invert)
219#endif // defined(__AVR__) 223#endif // defined(__AVR__)
220 224
221// Can be used to manually turn on the screen if it is off 225// Can be used to manually turn on the screen if it is off
222// Returns true if the screen was on or turns on 226// Returns true if the screen was on or turns on