aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Caltabiano <rcalt2vt@gmail.com>2019-04-15 22:32:57 -0500
committerskullydazed <skullydazed@users.noreply.github.com>2019-04-20 08:05:10 -0700
commit0a645225b9c863a106921185a6c2e0c340f10694 (patch)
tree2bf8c295650e54fb4548a7ac4d348ccfc8caa307
parentb5cb5ec6ddb15cfe336b835055f546f72d440a66 (diff)
downloadqmk_firmware-0a645225b9c863a106921185a6c2e0c340f10694.tar.gz
qmk_firmware-0a645225b9c863a106921185a6c2e0c340f10694.zip
OLED Driver Feature
-rw-r--r--common_features.mk7
-rw-r--r--docs/feature_oled_driver.md246
-rw-r--r--docs/hardware_drivers.md6
-rw-r--r--drivers/arm/i2c_master.c40
-rw-r--r--drivers/arm/i2c_master.h20
-rwxr-xr-xdrivers/avr/i2c_master.c4
-rwxr-xr-xdrivers/avr/i2c_master.h6
-rw-r--r--drivers/oled/glcdfont.c240
-rw-r--r--drivers/oled/oled_driver.c528
-rw-r--r--drivers/oled/oled_driver.h183
-rw-r--r--keyboards/cannonkeys/satisfaction75/i2c_master.c46
-rw-r--r--keyboards/sol/common/glcdfont.c140
-rw-r--r--keyboards/sol/common/ssd1306.c329
-rw-r--r--keyboards/sol/common/ssd1306.h92
-rw-r--r--keyboards/sol/i2c.c162
-rw-r--r--keyboards/sol/i2c.h49
-rwxr-xr-xkeyboards/sol/keymaps/brianweyer/config.h2
-rwxr-xr-xkeyboards/sol/keymaps/brianweyer/keymap.c146
-rwxr-xr-xkeyboards/sol/keymaps/brianweyer/rules.mk14
-rw-r--r--keyboards/sol/keymaps/danielhklein/keymap.c145
-rw-r--r--keyboards/sol/keymaps/danielhklein/rules.mk8
-rw-r--r--keyboards/sol/keymaps/default/keymap.c145
-rw-r--r--keyboards/sol/keymaps/default/rules.mk8
-rw-r--r--keyboards/sol/keymaps/kageurufu/rules.mk7
-rw-r--r--keyboards/sol/rev1/config.h6
-rw-r--r--keyboards/sol/rev1/rev1.c7
-rw-r--r--keyboards/sol/rev1/split_util.h2
-rw-r--r--keyboards/sol/rules.mk7
-rw-r--r--quantum/quantum.c13
-rw-r--r--quantum/quantum.h4
30 files changed, 1540 insertions, 1072 deletions
diff --git a/common_features.mk b/common_features.mk
index eb623d18f..fbfbc3ebc 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -336,3 +336,10 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
336 endif 336 endif
337 COMMON_VPATH += $(QUANTUM_PATH)/split_common 337 COMMON_VPATH += $(QUANTUM_PATH)/split_common
338endif 338endif
339
340ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes)
341 OPT_DEFS += -DOLED_DRIVER_ENABLE
342 COMMON_VPATH += $(DRIVER_PATH)/oled
343 QUANTUM_LIB_SRC += i2c_master.c
344 SRC += oled_driver.c
345endif
diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md
new file mode 100644
index 000000000..f261bbef1
--- /dev/null
+++ b/docs/feature_oled_driver.md
@@ -0,0 +1,246 @@
1# OLED Driver
2
3## OLED Supported Hardware
4
5128x32 OLED modules using SSD1306 driver IC over I2C. Supported on AVR based keyboards. Possible but untested hardware includes ARM based keyboards and other sized OLED modules using SSD1306 over I2C, such as 128x64.
6
7!> Warning: This OLED Driver currently uses the new i2c_master driver from split common code. If your split keyboard uses i2c to communication between sides this driver could cause an address conflict (serial is fine). Please contact your keyboard vendor and ask them to migrate to the latest split common code to fix this.
8
9## Usage
10
11To enable the OLED feature, there are three steps. First, when compiling your keyboard, you'll need to set `OLED_DRIVER_ENABLE=yes` in `rules.mk`, e.g.:
12
13```
14BOOTMAGIC_ENABLE = no
15MOUSEKEY_ENABLE = no
16STENO_ENABLE = no
17EXTRAKEY_ENABLE = yes
18OLED_DRIVER_ENABLE = yes
19```
20
21This enables the feature and the `OLED_DRIVER_ENABLE` define. Then in your `keymap.c` file, you will need to implement the user task call, e.g:
22
23```C++
24#ifdef OLED_DRIVER_ENABLE
25void oled_task_user(void) {
26 // Host Keyboard Layer Status
27 oled_write_P(PSTR("Layer: "), false);
28 switch (biton32(layer_state)) {
29 case _QWERTY:
30 oled_write_P(PSTR("Default\n"), false);
31 break;
32 case _FN:
33 oled_write_P(PSTR("FN\n"), false);
34 break;
35 case _ADJ:
36 oled_write_P(PSTR("ADJ\n"), false);
37 break;
38 default:
39 // Or use the write_ln shortcut
40 oled_write_P(PSTR("Undefined\n"), false);
41 }
42
43 // Host Keyboard LED Status
44 uint8_t led_usb_state = host_keyboard_leds();
45 oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLCK ") : PSTR(" "), false);
46 oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPLCK ") : PSTR(" "), false);
47 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCRLCK ") : PSTR(" "), false);
48}
49#endif
50```
51
52
53## Other Examples
54
55In split keyboards, it is very common to have two OLED displays that each render different content and oriented flipped differently. You can do this by switching which content to render by using the return from `is_keyboard_master()` or `is_keyboard_left()` found in `split_util.h`, e.g:
56
57```C++
58#ifdef OLED_DRIVER_ENABLE
59uint8_t oled_init_user(uint8_t rotation) {
60 if (!is_keyboard_master())
61 return OLED_ROTATION_180; // flips the display 180 degrees if offhand
62 return rotation;
63}
64
65void oled_task_user(void) {
66 if (is_keyboard_master()) {
67 render_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
68 } else {
69 render_logo(); // Renders a statuc logo
70 oled_scroll_left(); // Turns on scrolling
71 }
72}
73#endif
74```
75
76
77 ## Basic Configuration
78
79|Define |Default |Description |
80|-----------------------|---------------|------------------------------------------------|
81|`OLED_DISPLAY_ADDRESS` |`0x3C` |The i2c address of the OLED Display |
82|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
83|`OLED_FONT_START` |`0` |The starting characer index for custom fonts |
84|`OLED_FONT_END` |`224` |The ending characer index for custom fonts |
85|`OLED_FONT_WIDTH` |`6` |The font width |
86|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
87|`OLED_DISABLE_TIMEOUT` |*Not defined* |Disables the built in OLED timeout feature. Useful when implementing custom timeout rules.|
88
89
90
91 ## 128x64 & Custom sized OLED Displays
92
93 The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind. We have added a define, `OLED_DISPLAY_128X64`, to switch all the values to be used in a 128x64 display, as well as added a custom define, `OLED_DISPLAY_CUSTOM`, that allows you to provide the necessary values to the driver.
94
95|Define |Default |Description |
96|-----------------------|---------------|-----------------------------------------------------------------|
97|`OLED_DISPLAY_128X64` |*Not defined* |Changes the display defines for use with 128x64 displays. |
98|`OLED_DISPLAY_CUSTOM` |*Not defined* |Changes the display defines for use with custom displays.<br />Requires user to implement the below defines. |
99|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. |
100|`OLED_DISPLAY_HEIGHT` |`32` |The height of the OLED display. |
101|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br />`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`|
102|`OLED_BLOCK_TYPE` |`uint8_t` |The unsigned integer type to use for dirty rendering.|
103|`OLED_BLOCK_COUNT` |`8` |The number of blocks the display is divided into for dirty rendering.<br />`(sizeof(OLED_BLOCK_TYPE) * 8)`|
104|`OLED_BLOCK_SIZE` |`64` |The size of each block for dirty rendering<br />`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`|
105|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
106|`OLED_TARGET_MAP` |`{ 48, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
107
108
109### 90 Degree Rotation - Technical Mumbo Jumbo
110
111 OLED displays driven by SSD1306 drivers only natively support in hard ware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an `atmega32u4` board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
112
113 90 Degree Rotated Rendering is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the OLED Height, Width, and Block Size. For example, in the default 128x32 implementation we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g:
114
115| | | | | | |
116|---|---|---|---|---|---|
117| 0 | 1 | | | | |
118| 2 | 3 | | | | |
119| 4 | 5 | | | | |
120| 6 | 7 | | | | |
121
122However the local buffer is stored as if it was Height x Width display instead of Width x Height, e.g:
123
124| | | | | | |
125|---|---|---|---|---|---|
126| 3 | 7 | | | | |
127| 2 | 6 | | | | |
128| 1 | 5 | | | | |
129| 0 | 4 | | | | |
130
131So those precalculated arrays just index the memory offsets in the order in which each one iterates its data.
132
133## OLED API
134
135```C++
136// Initialize the OLED display, rotating the rendered output 180 degrees if true.
137// Returns true if the OLED was initialized successfully
138bool oled_init(bool flip180);
139
140// Called at the start of oled_init, weak function overridable by the user
141// flip180 - the value passed into oled_init
142// Return true if you want the oled to be flip180
143bool oled_init_user(bool flip180);
144
145// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
146void oled_clear(void);
147
148// Renders the dirty chunks of the buffer to OLED display
149void oled_render(void);
150
151// Moves cursor to character position indicated by column and line, wraps if out of bounds
152// Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions
153void oled_set_cursor(uint8_t col, uint8_t line);
154
155// Advances the cursor to the next page, writing ' ' if true
156// Wraps to the begining when out of bounds
157void oled_advance_page(bool clearPageRemainder);
158
159// Moves the cursor forward 1 character length
160// Advance page if there is not enough room for the next character
161// Wraps to the begining when out of bounds
162void oled_advance_char(void);
163
164// Writes a single character to the buffer at current cursor position
165// Advances the cursor while writing, inverts the pixels if true
166// Main handler that writes character data to the display buffer
167void oled_write_char(const char data, bool invert);
168
169// Writes a string to the buffer at current cursor position
170// Advances the cursor while writing, inverts the pixels if true
171void oled_write(const char *data, bool invert);
172
173// Writes a string to the buffer at current cursor position
174// Advances the cursor while writing, inverts the pixels if true
175// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
176void oled_write_ln(const char *data, bool invert);
177
178// Writes a PROGMEM string to the buffer at current cursor position
179// Advances the cursor while writing, inverts the pixels if true
180// Remapped to call 'void oled_write(const char *data, bool invert);' on ARM
181void oled_write_P(const char *data, bool invert);
182
183// Writes a PROGMEM string to the buffer at current cursor position
184// Advances the cursor while writing, inverts the pixels if true
185// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
186// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM
187void oled_write_ln_P(const char *data, bool invert);
188
189// Can be used to manually turn on the screen if it is off
190// Returns true if the screen was on or turns on
191bool oled_on(void);
192
193// Can be used to manually turn off the screen if it is on
194// Returns true if the screen was off or turns off
195bool oled_off(void);
196
197// Basically it's oled_render, but with timeout management and oled_task_user calling!
198void oled_task(void);
199
200// Called at the start of oled_task, weak function overridable by the user
201void oled_task_user(void);
202
203// Scrolls the entire display right
204// Returns true if the screen was scrolling or starts scrolling
205// NOTE: display contents cannot be changed while scrolling
206bool oled_scroll_right(void);
207
208// Scrolls the entire display left
209// Returns true if the screen was scrolling or starts scrolling
210// NOTE: display contents cannot be changed while scrolling
211bool oled_scroll_left(void);
212
213// Turns off display scrolling
214// Returns true if the screen was not scrolling or stops scrolling
215bool oled_scroll_off(void);
216
217// Returns the maximum number of characters that will fit on a line
218uint8_t oled_max_chars(void);
219
220// Returns the maximum number of lines that will fit on the oled
221uint8_t oled_max_lines(void);
222```
223
224## SSD1306.h driver conversion guide
225
226|Old API |Recommended New API |
227|---------------------------|-----------------------------------|
228|`struct CharacterMatrix` |*removed - delete all references* |
229|`iota_gfx_init` |`oled_init` |
230|`iota_gfx_on` |`oled_on` |
231|`iota_gfx_off` |`oled_off` |
232|`iota_gfx_flush` |`oled_render` |
233|`iota_gfx_write_char` |`oled_write_char` |
234|`iota_gfx_write` |`oled_write` |
235|`iota_gfx_write_P` |`oled_write_P` |
236|`iota_gfx_clear_screen` |`oled_clear` |
237|`matrix_clear` |*removed - delete all references* |
238|`matrix_write_char_inner` |`oled_write_char` |
239|`matrix_write_char` |`oled_write_char` |
240|`matrix_write` |`oled_write` |
241|`matrix_write_ln` |`oled_write_ln` |
242|`matrix_write_P` |`oled_write_P` |
243|`matrix_write_ln_P` |`oled_write_ln_P` |
244|`matrix_render` |`oled_render` |
245|`iota_gfx_task` |`oled_task` |
246|`iota_gfx_task_user` |`oled_task_user` |
diff --git a/docs/hardware_drivers.md b/docs/hardware_drivers.md
index 4c1266f22..023e92982 100644
--- a/docs/hardware_drivers.md
+++ b/docs/hardware_drivers.md
@@ -14,9 +14,9 @@ QMK is used on a lot of different hardware. While support for the most common MC
14 14
15Support for addressing pins on the ProMicro by their Arduino name rather than their AVR name. This needs to be better documented, if you are trying to do this and reading the code doesn't help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) and we can help you through the process. 15Support for addressing pins on the ProMicro by their Arduino name rather than their AVR name. This needs to be better documented, if you are trying to do this and reading the code doesn't help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) and we can help you through the process.
16 16
17## SSD1306 (AVR Only) 17## SSD1306 OLED Driver
18 18
19Support for SSD1306 based OLED displays. This needs to be better documented, if you are trying to do this and reading the code doesn't help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) and we can help you through the process. 19Support for SSD1306 based OLED displays. For more information see the [OLED Driver Feature](feature_oled_driver.md) page.
20 20
21## uGFX 21## uGFX
22 22
@@ -32,4 +32,4 @@ Support for up to 2 drivers. Each driver impliments 2 charlieplex matrices to in
32 32
33## IS31FL3733 33## IS31FL3733
34 34
35Support for up to a single driver with room for expansion. Each driver can control 192 individual LEDs or 64 RGB LEDs. For more information on how to setup the driver see the [RGB Matrix](feature_rgb_matrix.md) page. \ No newline at end of file 35Support for up to a single driver with room for expansion. Each driver can control 192 individual LEDs or 64 RGB LEDs. For more information on how to setup the driver see the [RGB Matrix](feature_rgb_matrix.md) page.
diff --git a/drivers/arm/i2c_master.c b/drivers/arm/i2c_master.c
index 0e5edcc38..7369398cc 100644
--- a/drivers/arm/i2c_master.c
+++ b/drivers/arm/i2c_master.c
@@ -42,6 +42,18 @@ static const I2CConfig i2cconfig = {
42 0 42 0
43}; 43};
44 44
45static i2c_status_t chibios_to_qmk(const msg_t* status) {
46 switch (*status) {
47 case I2C_NO_ERROR:
48 return I2C_STATUS_SUCCESS;
49 case I2C_TIMEOUT:
50 return I2C_STATUS_TIMEOUT;
51 // I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
52 default:
53 return I2C_STATUS_ERROR;
54 }
55}
56
45__attribute__ ((weak)) 57__attribute__ ((weak))
46void i2c_init(void) 58void i2c_init(void)
47{ 59{
@@ -57,29 +69,30 @@ void i2c_init(void)
57 //i2cInit(); //This is invoked by halInit() so no need to redo it. 69 //i2cInit(); //This is invoked by halInit() so no need to redo it.
58} 70}
59 71
60// This is usually not needed 72i2c_status_t i2c_start(uint8_t address)
61uint8_t i2c_start(uint8_t address)
62{ 73{
63 i2c_address = address; 74 i2c_address = address;
64 i2cStart(&I2C_DRIVER, &i2cconfig); 75 i2cStart(&I2C_DRIVER, &i2cconfig);
65 return 0; 76 return I2C_STATUS_SUCCESS;
66} 77}
67 78
68uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) 79i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout)
69{ 80{
70 i2c_address = address; 81 i2c_address = address;
71 i2cStart(&I2C_DRIVER, &i2cconfig); 82 i2cStart(&I2C_DRIVER, &i2cconfig);
72 return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout)); 83 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout));
84 return chibios_to_qmk(&status);
73} 85}
74 86
75uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) 87i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
76{ 88{
77 i2c_address = address; 89 i2c_address = address;
78 i2cStart(&I2C_DRIVER, &i2cconfig); 90 i2cStart(&I2C_DRIVER, &i2cconfig);
79 return i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout)); 91 msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout));
92 return chibios_to_qmk(&status);
80} 93}
81 94
82uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) 95i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout)
83{ 96{
84 i2c_address = devaddr; 97 i2c_address = devaddr;
85 i2cStart(&I2C_DRIVER, &i2cconfig); 98 i2cStart(&I2C_DRIVER, &i2cconfig);
@@ -91,18 +104,19 @@ uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t l
91 } 104 }
92 complete_packet[0] = regaddr; 105 complete_packet[0] = regaddr;
93 106
94 return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout)); 107 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout));
108 return chibios_to_qmk(&status);
95} 109}
96 110
97uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout) 111i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
98{ 112{
99 i2c_address = devaddr; 113 i2c_address = devaddr;
100 i2cStart(&I2C_DRIVER, &i2cconfig); 114 i2cStart(&I2C_DRIVER, &i2cconfig);
101 return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout)); 115 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout));
116 return chibios_to_qmk(&status);
102} 117}
103 118
104uint8_t i2c_stop(void) 119void i2c_stop(void)
105{ 120{
106 i2cStop(&I2C_DRIVER); 121 i2cStop(&I2C_DRIVER);
107 return 0;
108} 122}
diff --git a/drivers/arm/i2c_master.h b/drivers/arm/i2c_master.h
index 4ab2301f8..a15f1702d 100644
--- a/drivers/arm/i2c_master.h
+++ b/drivers/arm/i2c_master.h
@@ -40,11 +40,17 @@
40 #define I2C_DRIVER I2CD1 40 #define I2C_DRIVER I2CD1
41#endif 41#endif
42 42
43typedef int16_t i2c_status_t;
44
45#define I2C_STATUS_SUCCESS (0)
46#define I2C_STATUS_ERROR (-1)
47#define I2C_STATUS_TIMEOUT (-2)
48
43void i2c_init(void); 49void i2c_init(void);
44uint8_t i2c_start(uint8_t address); 50i2c_status_t i2c_start(uint8_t address);
45uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 51i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
46uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 52i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
47uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length); 53i2c_status_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
48uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 54i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
49uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 55i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
50uint8_t i2c_stop(void); 56void i2c_stop(void);
diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c
index ba6d0d158..a7364bae0 100755
--- a/drivers/avr/i2c_master.c
+++ b/drivers/avr/i2c_master.c
@@ -121,7 +121,7 @@ int16_t i2c_read_nack(uint16_t timeout) {
121 return TWDR; 121 return TWDR;
122} 122}
123 123
124i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) { 124i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
125 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout); 125 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
126 126
127 for (uint16_t i = 0; i < length && status >= 0; i++) { 127 for (uint16_t i = 0; i < length && status >= 0; i++) {
@@ -155,7 +155,7 @@ i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16
155 return (status < 0) ? status : I2C_STATUS_SUCCESS; 155 return (status < 0) ? status : I2C_STATUS_SUCCESS;
156} 156}
157 157
158i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 158i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
159 i2c_status_t status = i2c_start(devaddr | 0x00, timeout); 159 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
160 if (status >= 0) { 160 if (status >= 0) {
161 status = i2c_write(regaddr, timeout); 161 status = i2c_write(regaddr, timeout);
diff --git a/drivers/avr/i2c_master.h b/drivers/avr/i2c_master.h
index 81a7fb5e3..b4613115d 100755
--- a/drivers/avr/i2c_master.h
+++ b/drivers/avr/i2c_master.h
@@ -22,10 +22,10 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
22i2c_status_t i2c_write(uint8_t data, uint16_t timeout); 22i2c_status_t i2c_write(uint8_t data, uint16_t timeout);
23int16_t i2c_read_ack(uint16_t timeout); 23int16_t i2c_read_ack(uint16_t timeout);
24int16_t i2c_read_nack(uint16_t timeout); 24int16_t i2c_read_nack(uint16_t timeout);
25i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 25i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
26i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 26i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
27i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 27i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
28i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 28i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
29void i2c_stop(void); 29void i2c_stop(void);
30 30
31#endif // I2C_MASTER_H \ No newline at end of file 31#endif // I2C_MASTER_H
diff --git a/drivers/oled/glcdfont.c b/drivers/oled/glcdfont.c
new file mode 100644
index 000000000..150be9e94
--- /dev/null
+++ b/drivers/oled/glcdfont.c
@@ -0,0 +1,240 @@
1#pragma once
2
3#ifdef __AVR__
4 #include <avr/io.h>
5 #include <avr/pgmspace.h>
6#elif defined(ESP8266)
7 #include <pgmspace.h>
8#else
9 #define PROGMEM
10#endif
11
12// Helidox 8x6 font with QMK Firmware Logo
13// Online editor: http://teripom.x0.com/
14
15static const unsigned char font[] PROGMEM = {
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00,
18 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00,
19 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00,
20 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00,
21 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00,
22 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00,
23 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00,
24 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 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 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC,
166 0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00,
167 0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E,
168 0x7E, 0x7E, 0x7F, 0x7F, 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, 0xE0, 0xEC, 0xDF,
174 0xFC, 0xE0, 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 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F,
198 0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00,
199 0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F,
200 0x3F, 0x3F, 0x7F, 0x7F, 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 0x40, 0x7C, 0x3F, 0x3F, 0x23, 0x01,
206 0x23, 0x3F, 0x37, 0x6C, 0x40, 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};
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
new file mode 100644
index 000000000..aa025d7a4
--- /dev/null
+++ b/drivers/oled/oled_driver.c
@@ -0,0 +1,528 @@
1/*
2Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "i2c_master.h"
18#include "oled_driver.h"
19#include OLED_FONT_H
20#include "timer.h"
21#include "print.h"
22
23#include <string.h>
24
25#if defined(__AVR__)
26 #include <avr/io.h>
27 #include <avr/pgmspace.h>
28#elif defined(ESP8266)
29 #include <pgmspace.h>
30#else // defined(ESP8266)
31 #define PROGMEM
32 #define memcpy_P(des, src, len) memcpy(des, src, len)
33#endif // defined(__AVR__)
34
35// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
36// Fundamental Commands
37#define CONTRAST 0x81
38#define DISPLAY_ALL_ON 0xA5
39#define DISPLAY_ALL_ON_RESUME 0xA4
40#define NORMAL_DISPLAY 0xA6
41#define DISPLAY_ON 0xAF
42#define DISPLAY_OFF 0xAE
43
44// Scrolling Commands
45#define ACTIVATE_SCROLL 0x2F
46#define DEACTIVATE_SCROLL 0x2E
47#define SCROLL_RIGHT 0x26
48#define SCROLL_LEFT 0x27
49#define SCROLL_RIGHT_UP 0x29
50#define SCROLL_LEFT_UP 0x2A
51
52// Addressing Setting Commands
53#define MEMORY_MODE 0x20
54#define COLUMN_ADDR 0x21
55#define PAGE_ADDR 0x22
56
57// Hardware Configuration Commands
58#define DISPLAY_START_LINE 0x40
59#define SEGMENT_REMAP 0xA0
60#define SEGMENT_REMAP_INV 0xA1
61#define MULTIPLEX_RATIO 0xA8
62#define COM_SCAN_INC 0xC0
63#define COM_SCAN_DEC 0xC8
64#define DISPLAY_OFFSET 0xD3
65#define COM_PINS 0xDA
66
67// Timing & Driving Commands
68#define DISPLAY_CLOCK 0xD5
69#define PRE_CHARGE_PERIOD 0xD9
70#define VCOM_DETECT 0xDB
71
72// Charge Pump Commands
73#define CHARGE_PUMP 0x8D
74
75// Misc defines
76#define OLED_TIMEOUT 60000
77#define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
78#define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
79
80// i2c defines
81#define I2C_CMD 0x00
82#define I2C_DATA 0x40
83#if defined(__AVR__)
84 // already defined on ARM
85 #define I2C_TIMEOUT 100
86 #define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
87#else // defined(__AVR__)
88 #define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
89#endif // defined(__AVR__)
90#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), I2C_TIMEOUT)
91#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, I2C_TIMEOUT)
92
93#define HAS_FLAGS(bits, flags) ((bits & flags) == flags)
94
95// Display buffer's is the same as the OLED memory layout
96// this is so we don't end up with rounding errors with
97// parts of the display unusable or don't get cleared correctly
98// and also allows for drawing & inverting
99uint8_t oled_buffer[OLED_MATRIX_SIZE];
100uint8_t* oled_cursor;
101OLED_BLOCK_TYPE oled_dirty = 0;
102bool oled_initialized = false;
103bool oled_active = false;
104bool oled_scrolling = false;
105uint8_t oled_rotation = 0;
106uint8_t oled_rotation_width = 0;
107#if !defined(OLED_DISABLE_TIMEOUT)
108 uint16_t oled_last_activity;
109#endif
110
111// Internal variables to reduce math instructions
112
113#if defined(__AVR__)
114// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently
115// probably should move this into i2c_master...
116static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
117 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
118
119 for (uint16_t i = 0; i < length && status >= 0; i++) {
120 status = i2c_write(pgm_read_byte((const char*)data++), timeout);
121 if (status) break;
122 }
123
124 i2c_stop();
125
126 return status;
127}
128#endif
129
130// Flips the rendering bits for a character at the current cursor position
131static void InvertCharacter(uint8_t *cursor)
132{
133 const uint8_t *end = cursor + OLED_FONT_WIDTH;
134 while (cursor < end) {
135 *cursor = ~(*cursor);
136 cursor++;
137 }
138}
139
140bool oled_init(uint8_t rotation) {
141 oled_rotation = oled_init_user(rotation);
142 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
143 oled_rotation_width = OLED_DISPLAY_WIDTH;
144 } else {
145 oled_rotation_width = OLED_DISPLAY_HEIGHT;
146 }
147 i2c_init();
148
149 static const uint8_t PROGMEM display_setup1[] = {
150 I2C_CMD,
151 DISPLAY_OFF,
152 DISPLAY_CLOCK, 0x80,
153 MULTIPLEX_RATIO, OLED_DISPLAY_HEIGHT - 1,
154 DISPLAY_OFFSET, 0x00,
155 DISPLAY_START_LINE | 0x00,
156 CHARGE_PUMP, 0x14,
157 MEMORY_MODE, 0x00, }; // Horizontal addressing mode
158 if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {
159 print("oled_init cmd set 1 failed\n");
160 return false;
161 }
162
163 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) {
164 static const uint8_t PROGMEM display_normal[] = {
165 I2C_CMD,
166 SEGMENT_REMAP_INV,
167 COM_SCAN_DEC };
168 if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
169 print("oled_init cmd normal rotation failed\n");
170 return false;
171 }
172 } else {
173 static const uint8_t PROGMEM display_flipped[] = {
174 I2C_CMD,
175 SEGMENT_REMAP,
176 COM_SCAN_INC };
177 if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) {
178 print("display_flipped failed\n");
179 return false;
180 }
181 }
182
183 static const uint8_t PROGMEM display_setup2[] = {
184 I2C_CMD,
185 COM_PINS, 0x02,
186 CONTRAST, 0x8F,
187 PRE_CHARGE_PERIOD, 0xF1,
188 VCOM_DETECT, 0x40,
189 DISPLAY_ALL_ON_RESUME,
190 NORMAL_DISPLAY,
191 DEACTIVATE_SCROLL,
192 DISPLAY_ON };
193 if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) {
194 print("display_setup2 failed\n");
195 return false;
196 }
197
198 oled_clear();
199 oled_initialized = true;
200 oled_active = true;
201 oled_scrolling = false;
202 return true;
203}
204
205__attribute__((weak))
206uint8_t oled_init_user(uint8_t rotation) {
207 return rotation;
208}
209
210void oled_clear(void) {
211 memset(oled_buffer, 0, sizeof(oled_buffer));
212 oled_cursor = &oled_buffer[0];
213 oled_dirty = -1; // -1 will be max value as long as display_dirty is unsigned type
214}
215
216static void calc_bounds(uint8_t update_start, uint8_t* cmd_array)
217{
218 cmd_array[1] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
219 cmd_array[4] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
220 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1];
221 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1;
222}
223
224static void calc_bounds_90(uint8_t update_start, uint8_t* cmd_array)
225{
226 cmd_array[1] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8;
227 cmd_array[4] = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT;
228 cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8 - 1 + cmd_array[1];;
229 cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) % OLED_DISPLAY_HEIGHT / 8;
230}
231
232uint8_t crot(uint8_t a, int8_t n)
233{
234 const uint8_t mask = 0x7;
235 n &= mask;
236 return a << n | a >> (-n & mask);
237}
238
239static void rotate_90(const uint8_t* src, uint8_t* dest)
240{
241 for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) {
242 uint8_t selector = (1 << i);
243 for (uint8_t j = 0; j < 8; ++j) {
244 dest[i] |= crot(src[j] & selector, shift - (int8_t)j);
245 }
246 }
247}
248
249void oled_render(void) {
250 // Do we have work to do?
251 if (!oled_dirty || oled_scrolling) {
252 return;
253 }
254
255 // Find first dirty block
256 uint8_t update_start = 0;
257 while (!(oled_dirty & (1 << update_start))) { ++update_start; }
258
259 // Set column & page position
260 static uint8_t display_start[] = {
261 I2C_CMD,
262 COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1,
263 PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1 };
264 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
265 calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
266 } else {
267 calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
268 }
269
270 // Send column & page position
271 if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
272 print("oled_render offset command failed\n");
273 return;
274 }
275
276 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
277 // Send render data chunk as is
278 if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
279 print("oled_render data failed\n");
280 return;
281 }
282 } else {
283 // Rotate the render chunks
284 const static uint8_t source_map[] = OLED_SOURCE_MAP;
285 const static uint8_t target_map[] = OLED_TARGET_MAP;
286
287 static uint8_t temp_buffer[OLED_BLOCK_SIZE];
288 memset(temp_buffer, 0, sizeof(temp_buffer));
289 for(uint8_t i = 0; i < sizeof(source_map); ++i) {
290 rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
291 }
292
293 // Send render data chunk after rotating
294 if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
295 print("oled_render data failed\n");
296 return;
297 }
298 }
299
300 // Turn on display if it is off
301 oled_on();
302
303 // Clear dirty flag
304 oled_dirty &= ~(1 << update_start);
305}
306
307void oled_set_cursor(uint8_t col, uint8_t line) {
308 uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH;
309
310 // Out of bounds?
311 if (index >= OLED_MATRIX_SIZE) {
312 index = 0;
313 }
314
315 oled_cursor = &oled_buffer[index];
316}
317
318void oled_advance_page(bool clearPageRemainder) {
319 uint16_t index = oled_cursor - &oled_buffer[0];
320 uint8_t remaining = oled_rotation_width - (index % oled_rotation_width);
321
322 if (clearPageRemainder) {
323 // Remaining Char count
324 remaining = remaining / OLED_FONT_WIDTH;
325
326 // Write empty character until next line
327 while (remaining--)
328 oled_write_char(' ', false);
329 } else {
330 // Next page index out of bounds?
331 if (index + remaining >= OLED_MATRIX_SIZE) {
332 index = 0;
333 remaining = 0;
334 }
335
336 oled_cursor = &oled_buffer[index + remaining];
337 }
338}
339
340void oled_advance_char(void) {
341 uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH;
342 uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width);
343
344 // Do we have enough space on the current line for the next character
345 if (remainingSpace < OLED_FONT_WIDTH) {
346 nextIndex += remainingSpace;
347 }
348
349 // Did we go out of bounds
350 if (nextIndex >= OLED_MATRIX_SIZE) {
351 nextIndex = 0;
352 }
353
354 // Update cursor position
355 oled_cursor = &oled_buffer[nextIndex];
356}
357
358// Main handler that writes character data to the display buffer
359void oled_write_char(const char data, bool invert) {
360 // Advance to the next line if newline
361 if (data == '\n') {
362 // Old source wrote ' ' until end of line...
363 oled_advance_page(true);
364 return;
365 }
366
367 // copy the current render buffer to check for dirty after
368 static uint8_t oled_temp_buffer[OLED_FONT_WIDTH];
369 memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH);
370
371 // set the reder buffer data
372 uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
373 if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) {
374 memset(oled_cursor, 0x00, OLED_FONT_WIDTH);
375 } else {
376 const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH];
377 memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH);
378 }
379
380 // Invert if needed
381 if (invert) {
382 InvertCharacter(oled_cursor);
383 }
384
385 // Dirty check
386 if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) {
387 oled_dirty |= (1 << ((oled_cursor - &oled_buffer[0]) / OLED_BLOCK_SIZE));
388 }
389
390 // Finally move to the next char
391 oled_advance_char();
392}
393
394void oled_write(const char *data, bool invert) {
395 const char *end = data + strlen(data);
396 while (data < end) {
397 oled_write_char(*data, invert);
398 data++;
399 }
400}
401
402void oled_write_ln(const char *data, bool invert) {
403 oled_write(data, invert);
404 oled_advance_page(true);
405}
406
407#if defined(__AVR__)
408void oled_write_P(const char *data, bool invert) {
409 uint8_t c = pgm_read_byte(data);
410 while (c != 0) {
411 oled_write_char(c, invert);
412 c = pgm_read_byte(++data);
413 }
414}
415
416void oled_write_ln_P(const char *data, bool invert) {
417 oled_write_P(data, invert);
418 oled_advance_page(true);
419}
420#endif // defined(__AVR__)
421
422bool oled_on(void) {
423#if !defined(OLED_DISABLE_TIMEOUT)
424 oled_last_activity = timer_read();
425#endif
426
427 static const uint8_t PROGMEM display_on[] = { I2C_CMD, DISPLAY_ON };
428 if (!oled_active) {
429 if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) {
430 print("oled_on cmd failed\n");
431 return oled_active;
432 }
433 oled_active = true;
434 }
435 return oled_active;
436}
437
438bool oled_off(void) {
439 static const uint8_t PROGMEM display_off[] = { I2C_CMD, DISPLAY_OFF };
440 if (oled_active) {
441 if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) {
442 print("oled_off cmd failed\n");
443 return oled_active;
444 }
445 oled_active = false;
446 }
447 return !oled_active;
448}
449
450bool oled_scroll_right(void) {
451 // Dont enable scrolling if we need to update the display
452 // This prevents scrolling of bad data from starting the scroll too early after init
453 if (!oled_dirty && !oled_scrolling) {
454 static const uint8_t PROGMEM display_scroll_right[] = {
455 I2C_CMD, SCROLL_RIGHT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL };
456 if (I2C_TRANSMIT_P(display_scroll_right) != I2C_STATUS_SUCCESS) {
457 print("oled_scroll_right cmd failed\n");
458 return oled_scrolling;
459 }
460 oled_scrolling = true;
461 }
462 return oled_scrolling;
463}
464
465bool oled_scroll_left(void) {
466 // Dont enable scrolling if we need to update the display
467 // This prevents scrolling of bad data from starting the scroll too early after init
468 if (!oled_dirty && !oled_scrolling) {
469 static const uint8_t PROGMEM display_scroll_left[] = {
470 I2C_CMD, SCROLL_LEFT, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xFF, ACTIVATE_SCROLL };
471 if (I2C_TRANSMIT_P(display_scroll_left) != I2C_STATUS_SUCCESS) {
472 print("oled_scroll_left cmd failed\n");
473 return oled_scrolling;
474 }
475 oled_scrolling = true;
476 }
477 return oled_scrolling;
478}
479
480bool oled_scroll_off(void) {
481 if (oled_scrolling) {
482 static const uint8_t PROGMEM display_scroll_off[] = { I2C_CMD, DEACTIVATE_SCROLL };
483 if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) {
484 print("oled_scroll_off cmd failed\n");
485 return oled_scrolling;
486 }
487 oled_scrolling = false;
488 }
489 return !oled_scrolling;
490}
491
492uint8_t oled_max_chars(void) {
493 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
494 return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH;
495 }
496 return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH;
497}
498
499uint8_t oled_max_lines(void) {
500 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
501 return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT;
502 }
503 return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT;
504}
505
506void oled_task(void) {
507 if (!oled_initialized) {
508 return;
509 }
510
511 oled_set_cursor(0, 0);
512
513 oled_task_user();
514
515 // Smart render system, no need to check for dirty
516 oled_render();
517
518 // Display timeout check
519#if !defined(OLED_DISABLE_TIMEOUT)
520 if (oled_active && timer_elapsed(oled_last_activity) > OLED_TIMEOUT) {
521 oled_off();
522 }
523#endif
524}
525
526__attribute__((weak))
527void oled_task_user(void) {
528}
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
new file mode 100644
index 000000000..1ca31df11
--- /dev/null
+++ b/drivers/oled/oled_driver.h
@@ -0,0 +1,183 @@
1/*
2Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#pragma once
18
19#include <stdint.h>
20#include <stdbool.h>
21
22
23#if defined(OLED_DISPLAY_CUSTOM)
24 // Expected user to implement the necessary defines
25#elif defined(OLED_DISPLAY_128X64)
26 // Double height 128x64
27 #define OLED_DISPLAY_WIDTH 128
28 #define OLED_DISPLAY_HEIGHT 64
29 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed)
30 #define OLED_BLOCK_TYPE uint16_t
31 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed)
32 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 64 (compile time mathed)
33
34 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
35 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
36 #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
37 #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 }
38 // If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
39 // #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }
40 // #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 }
41#else // defined(OLED_DISPLAY_128X64)
42 // Default 128x32
43 #define OLED_DISPLAY_WIDTH 128
44 #define OLED_DISPLAY_HEIGHT 32
45 #define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
46 #define OLED_BLOCK_TYPE uint8_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
47 #define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 8 (compile time mathed)
48 #define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 128 (compile time mathed)
49
50 // For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
51 // The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
52 #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
53 #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
54#endif // defined(OLED_DISPLAY_CUSTOM)
55
56// Address to use for tthe i2d oled communication
57#if !defined(OLED_DISPLAY_ADDRESS)
58 #define OLED_DISPLAY_ADDRESS 0x3C
59#endif
60
61// Custom font file to use
62#if !defined(OLED_FONT_H)
63 #define OLED_FONT_H "glcdfont.c"
64#endif
65// unsigned char value of the first character in the font file
66#if !defined(OLED_FONT_START)
67 #define OLED_FONT_START 0
68#endif
69// unsigned char value of the last character in the font file
70#if !defined(OLED_FONT_END)
71 #define OLED_FONT_END 224
72#endif
73// Font render width
74#if !defined(OLED_FONT_WIDTH)
75 #define OLED_FONT_WIDTH 6
76#endif
77// Font render height
78#if !defined(OLED_FONT_HEIGHT)
79 #define OLED_FONT_HEIGHT 8
80#endif
81
82#define OLED_ROTATION_0 0x00
83#define OLED_ROTATION_90 0x01
84#define OLED_ROTATION_180 0x02
85#define OLED_ROTATION_270 0x03
86
87// Initialize the oled display, rotating the rendered output based on the define passed in.
88// Returns true if the OLED was initialized successfully
89bool oled_init(uint8_t rotation);
90
91// Called at the start of oled_init, weak function overridable by the user
92// rotation - the value passed into oled_init
93// Return new uint8_t if you want to override default rotation
94uint8_t oled_init_user(uint8_t rotation);
95
96// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
97void oled_clear(void);
98
99// Renders the dirty chunks of the buffer to oled display
100void oled_render(void);
101
102// Moves cursor to character position indicated by column and line, wraps if out of bounds
103// Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions
104void oled_set_cursor(uint8_t col, uint8_t line);
105
106// Advances the cursor to the next page, writing ' ' if true
107// Wraps to the begining when out of bounds
108void oled_advance_page(bool clearPageRemainder);
109
110// Moves the cursor forward 1 character length
111// Advance page if there is not enough room for the next character
112// Wraps to the begining when out of bounds
113void oled_advance_char(void);
114
115// Writes a single character to the buffer at current cursor position
116// Advances the cursor while writing, inverts the pixels if true
117// Main handler that writes character data to the display buffer
118void oled_write_char(const char data, bool invert);
119
120// Writes a string to the buffer at current cursor position
121// Advances the cursor while writing, inverts the pixels if true
122void oled_write(const char *data, bool invert);
123
124// Writes a string to the buffer at current cursor position
125// Advances the cursor while writing, inverts the pixels if true
126// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
127void oled_write_ln(const char *data, bool invert);
128
129#if defined(__AVR__)
130// Writes a PROGMEM string to the buffer at current cursor position
131// Advances the cursor while writing, inverts the pixels if true
132// Remapped to call 'void oled_write(const char *data, bool invert);' on ARM
133void oled_write_P(const char *data, bool invert);
134
135// Writes a PROGMEM string to the buffer at current cursor position
136// Advances the cursor while writing, inverts the pixels if true
137// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
138// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM
139void oled_write_ln_P(const char *data, bool invert);
140#else
141 // Writes a string to the buffer at current cursor position
142 // Advances the cursor while writing, inverts the pixels if true
143 #define oled_write_P(data, invert) oled_write(data, invert)
144
145 // Writes a string to the buffer at current cursor position
146 // Advances the cursor while writing, inverts the pixels if true
147 // Advances the cursor to the next page, wiring ' ' to the remainder of the current page
148 #define oled_write_ln_P(data, invert) oled_write(data, invert)
149#endif // defined(__AVR__)
150
151// Can be used to manually turn on the screen if it is off
152// Returns true if the screen was on or turns on
153bool oled_on(void);
154
155// Can be used to manually turn off the screen if it is on
156// Returns true if the screen was off or turns off
157bool oled_off(void);
158
159// Basically it's oled_render, but with timeout management and oled_task_user calling!
160void oled_task(void);
161
162// Called at the start of oled_task, weak function overridable by the user
163void oled_task_user(void);
164
165// Scrolls the entire display right
166// Returns true if the screen was scrolling or starts scrolling
167// NOTE: display contents cannot be changed while scrolling
168bool oled_scroll_right(void);
169
170// Scrolls the entire display left
171// Returns true if the screen was scrolling or starts scrolling
172// NOTE: display contents cannot be changed while scrolling
173bool oled_scroll_left(void);
174
175// Turns off display scrolling
176// Returns true if the screen was not scrolling or stops scrolling
177bool oled_scroll_off(void);
178
179// Returns the maximum number of characters that will fit on a line
180uint8_t oled_max_chars(void);
181
182// Returns the maximum number of lines that will fit on the oled
183uint8_t oled_max_lines(void);
diff --git a/keyboards/cannonkeys/satisfaction75/i2c_master.c b/keyboards/cannonkeys/satisfaction75/i2c_master.c
index d81eb92d4..ce0e0a7ba 100644
--- a/keyboards/cannonkeys/satisfaction75/i2c_master.c
+++ b/keyboards/cannonkeys/satisfaction75/i2c_master.c
@@ -29,8 +29,6 @@
29#include "quantum.h" 29#include "quantum.h"
30#include <string.h> 30#include <string.h>
31#include <hal.h> 31#include <hal.h>
32#include "chtypes.h"
33#include "ch.h"
34 32
35static uint8_t i2c_address; 33static uint8_t i2c_address;
36 34
@@ -44,6 +42,18 @@ static const I2CConfig i2cconfig = {
44 0 42 0
45}; 43};
46 44
45static i2c_status_t chibios_to_qmk(const msg_t* status) {
46 switch (*status) {
47 case I2C_NO_ERROR:
48 return I2C_STATUS_SUCCESS;
49 case I2C_TIMEOUT:
50 return I2C_STATUS_TIMEOUT;
51 // I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
52 default:
53 return I2C_STATUS_ERROR;
54 }
55}
56
47__attribute__ ((weak)) 57__attribute__ ((weak))
48void i2c_init(void) 58void i2c_init(void)
49{ 59{
@@ -59,34 +69,32 @@ void i2c_init(void)
59 //i2cInit(); //This is invoked by halInit() so no need to redo it. 69 //i2cInit(); //This is invoked by halInit() so no need to redo it.
60} 70}
61 71
62// This is usually not needed 72i2c_status_t i2c_start(uint8_t address)
63uint8_t i2c_start(uint8_t address)
64{ 73{
65 i2c_address = address; 74 i2c_address = address;
66 i2cStart(&I2C_DRIVER, &i2cconfig); 75 i2cStart(&I2C_DRIVER, &i2cconfig);
67 return 0; 76 return I2C_STATUS_SUCCESS;
68} 77}
69 78
70uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) 79i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout)
71{ 80{
72 msg_t status = MSG_OK;
73
74 i2c_address = address; 81 i2c_address = address;
75 i2cStart(&I2C_DRIVER, &i2cconfig); 82 i2cStart(&I2C_DRIVER, &i2cconfig);
76 i2cAcquireBus(&I2C_DRIVER); 83 i2cAcquireBus(&I2C_DRIVER);
77 status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout)); 84 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout));
78 i2cReleaseBus(&I2C_DRIVER); 85 i2cReleaseBus(&I2C_DRIVER);
79 return status; 86 return chibios_to_qmk(&status);
80} 87}
81 88
82uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) 89i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
83{ 90{
84 i2c_address = address; 91 i2c_address = address;
85 i2cStart(&I2C_DRIVER, &i2cconfig); 92 i2cStart(&I2C_DRIVER, &i2cconfig);
86 return i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout)); 93 msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout));
94 return chibios_to_qmk(&status);
87} 95}
88 96
89uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) 97i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout)
90{ 98{
91 i2c_address = devaddr; 99 i2c_address = devaddr;
92 i2cStart(&I2C_DRIVER, &i2cconfig); 100 i2cStart(&I2C_DRIVER, &i2cconfig);
@@ -98,19 +106,19 @@ uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t l
98 } 106 }
99 complete_packet[0] = regaddr; 107 complete_packet[0] = regaddr;
100 108
101 return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout)); 109 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout));
110 return chibios_to_qmk(&status);
102} 111}
103 112
104uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout) 113i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
105{ 114{
106 i2c_address = devaddr; 115 i2c_address = devaddr;
107 i2cStart(&I2C_DRIVER, &i2cconfig); 116 i2cStart(&I2C_DRIVER, &i2cconfig);
108 return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout)); 117 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout));
118 return chibios_to_qmk(&status);
109} 119}
110 120
111// This is usually not needed. It releases the driver to allow pins to become GPIO again. 121void i2c_stop(void)
112uint8_t i2c_stop(void)
113{ 122{
114 i2cStop(&I2C_DRIVER); 123 i2cStop(&I2C_DRIVER);
115 return 0;
116} 124}
diff --git a/keyboards/sol/common/glcdfont.c b/keyboards/sol/common/glcdfont.c
index 89665ba07..f772e3181 100644
--- a/keyboards/sol/common/glcdfont.c
+++ b/keyboards/sol/common/glcdfont.c
@@ -1,8 +1,4 @@
1// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. 1#pragma once
2// See gfxfont.h for newer custom bitmap font info.
3
4#ifndef FONT5X7_H
5#define FONT5X7_H
6 2
7#ifdef __AVR__ 3#ifdef __AVR__
8 #include <avr/io.h> 4 #include <avr/io.h>
@@ -13,7 +9,8 @@
13 #define PROGMEM 9 #define PROGMEM
14#endif 10#endif
15 11
16// Standard ASCII 5x7 font 12// Helidox 8x6 font with RGBKB SOL Logo
13// Online editor: http://teripom.x0.com/
17 14
18static const unsigned char font[] PROGMEM = { 15static const unsigned char font[] PROGMEM = {
19 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -144,27 +141,27 @@ static const unsigned char font[] PROGMEM = {
144 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 141 0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
145 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 142 0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
146 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 143 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
147 0x03, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 144 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
148 0xFE, 0xF8, 0xF0, 0xC0, 0x20, 0xF8, 145 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
149 0xFE, 0xFF, 0xFE, 0x79, 0x27, 0x1F,
150 0x7F, 0xFF, 0xFF, 0xFE, 0xF8, 0xF0,
151 0xC0, 0x20, 0xF8, 0xFE, 0xFF, 0xFF,
152 0x7F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFE,
153 0xF8, 0xF0, 0xC0, 0x00, 0x00, 0x00,
154 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
155 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0xFF, 0x7F, 0x7F, 0x7F,
157 0xBF, 0xBF, 0xC0, 0xC0, 0xC0, 0xE0,
158 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0,
159 0xF8, 0x78, 0x78, 0x7C, 0x3C, 0x3C,
160 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 146 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
163 0xBF, 0xBF, 0xDF, 0xDF, 0xEF, 0xEF, 147 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
164 0x00, 0x03, 0x07, 0x1F, 0x7F, 0xFF, 148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 0xC0, 149 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
166 0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x7F, 0x1F, 0x07, 0x03, 0x00, 0x00, 151 0x00, 0x80, 0x00, 0x00, 0x0C, 0x90,
152 0xB0, 0xE0, 0x72, 0x31, 0x9B, 0xDE,
153 0xCE, 0xEC, 0xEE, 0xE9, 0xE9, 0xEC,
154 0xCF, 0xDA, 0x99, 0x3E, 0x62, 0xE4,
155 0xC4, 0x70, 0x10, 0x10, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
157 0xC0, 0xC0, 0x80, 0x80, 0x02, 0x85,
158 0x85, 0x87, 0x85, 0x89, 0x89, 0x92,
159 0xEA, 0xC6, 0xC4, 0x48, 0x50, 0x60,
160 0x40, 0x40, 0x40, 0x40, 0xC0, 0xE0,
161 0x50, 0x28, 0x10, 0x10, 0x60, 0xC0,
162 0x40, 0x40, 0x40, 0x40, 0x80, 0x80,
163 0x80, 0x80, 0x80, 0xE0, 0xF8, 0xFC,
164 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00,
168 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC, 165 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC,
169 0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00, 166 0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00,
170 0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E, 167 0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E,
@@ -173,30 +170,30 @@ static const unsigned char font[] PROGMEM = {
173 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00, 170 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00,
174 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE, 171 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE,
175 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00, 172 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 173 0x00, 0x00, 0x00, 0xE0, 0xEC, 0xDF,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 174 0xFC, 0xE0, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0xC1, 0xF3, 176 0x00, 0x00, 0x00, 0x7F, 0x80, 0x80,
180 0xCF, 0xBF, 0x7F, 0xFF, 0xFF, 0xFC, 177 0x80, 0x70, 0x0F, 0x00, 0x00, 0x80,
181 0xFB, 0xE7, 0x81, 0x00, 0x00, 0x00, 178 0x7F, 0x00, 0x00, 0x7F, 0x80, 0x80,
182 0x00, 0x80, 0xE3, 0xCF, 0x3F, 0xFF, 179 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F,
183 0xFF, 0xFF, 0xFC, 0xFB, 0xE7, 0x81, 180 0x00, 0x00, 0x80, 0x80, 0x80, 0x80,
184 0x00, 0x00, 0x00, 0x00, 0x81, 0xE7, 181 0x80, 0x80, 0x80, 0xFF, 0x00, 0x00,
185 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x00, 182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 183 0x00, 0x40, 0x21, 0x33, 0x3B, 0x7B,
187 0xFF, 0xF8, 0xF8, 0xFC, 0x7C, 0x7E, 184 0xFF, 0x00, 0x7C, 0xFF, 0xFF, 0xFF,
188 0x7E, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF,
189 0xFF, 0xFF, 0xF7, 0xF7, 0xF7, 0xFB,
190 0xFB, 0x7D, 0x7D, 0x7D, 0xBE, 0xBE,
191 0xBE, 0xDF, 0xDF, 0xE0, 0xE0, 0x00,
192 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
193 0x00, 0xFC, 0xFC, 0x7C, 0x7E, 0x7E,
194 0x3E, 0x3E, 0x1F, 0x1F, 0x1F, 0x0F,
195 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 185 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 186 0xFF, 0xFF, 0xFF, 0xFF, 0x7C, 0x01,
197 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 187 0xFF, 0xDE, 0x8C, 0x04, 0x0C, 0x08,
198 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x81, 188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 189 0x00, 0x01, 0x01, 0x01, 0x7F, 0x80,
190 0x80, 0xBE, 0xBE, 0x80, 0x80, 0x80,
191 0xC1, 0xFF, 0x80, 0x04, 0x32, 0x5E,
192 0x1C, 0x3D, 0x26, 0x10, 0xC1, 0xFF,
193 0x3E, 0x00, 0x00, 0x08, 0x36, 0xC1,
194 0x08, 0x08, 0x14, 0x77, 0x94, 0x94,
195 0x94, 0xF7, 0x94, 0xF7, 0x9C, 0x9C,
196 0xFF, 0xFF, 0x1E, 0x00, 0x00, 0x00,
200 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F, 197 0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F,
201 0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00, 198 0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00,
202 0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F, 199 0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F,
@@ -205,30 +202,31 @@ static const unsigned char font[] PROGMEM = {
205 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00, 202 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00,
206 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F, 203 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F,
207 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00, 204 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00,
205 0x40, 0x7C, 0x3F, 0x3F, 0x23, 0x01,
206 0x23, 0x3F, 0x37, 0x6C, 0x40, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x06, 0x02, 0x06,
216 0x4D, 0x4F, 0x8C, 0xF9, 0x73, 0x37,
217 0x27, 0x2F, 0x2F, 0xAF, 0xEF, 0x6F,
218 0x77, 0x17, 0x33, 0x79, 0xCC, 0x1F,
219 0x31, 0x20, 0x21, 0x02, 0x02, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x40, 0xE0,
222 0xA0, 0xA0, 0xD0, 0x90, 0x48, 0x48,
223 0x25, 0x2B, 0x11, 0x09, 0x05, 0x03,
224 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
225 0x01, 0x03, 0x02, 0x04, 0x03, 0x01,
226 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
227 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F,
228 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x60, 0x70, 0x7C, 0x7F, 0x7F, 0x7F,
212 0x7F, 0x1F, 0x06, 0x01, 0x03, 0x0F,
213 0x3F, 0x7F, 0x7F, 0x7E, 0x7C, 0x7C,
214 0x7E, 0x7F, 0x7F, 0x7F, 0x1F, 0x06,
215 0x01, 0x07, 0x0F, 0x3F, 0x7F, 0x7F,
216 0x7E, 0x7C, 0x7C, 0x7E, 0x7F, 0x7F,
217 0x3F, 0x0F, 0x03, 0x00, 0x00, 0x00,
218 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
219 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
221 0x7F, 0x7F, 0x7D, 0x7D, 0x3D, 0x3E,
222 0x1E, 0x1F, 0x1F, 0x1F, 0x0F, 0x0F,
223 0x07, 0x07, 0x07, 0x03, 0x03, 0x00,
224 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
225 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C,
226 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00,
227 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
228 0x00, 0x40, 0x70, 0x78, 0x7E, 0x7F,
229 0x7F, 0x7F, 0x3F, 0x0F, 0x03, 0x01,
230 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0x7F,
231 0x7E, 0x78, 0x70, 0x40, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -239,6 +237,4 @@ static const unsigned char font[] PROGMEM = {
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
243}; 240};
244#endif // FONT5X7_H
diff --git a/keyboards/sol/common/ssd1306.c b/keyboards/sol/common/ssd1306.c
deleted file mode 100644
index b3e55a67c..000000000
--- a/keyboards/sol/common/ssd1306.c
+++ /dev/null
@@ -1,329 +0,0 @@
1#ifdef SSD1306OLED
2
3#include "ssd1306.h"
4#include "i2c.h"
5#include <string.h>
6#include "print.h"
7#ifndef LOCAL_GLCDFONT
8#include "common/glcdfont.c"
9#else
10#include <helixfont.h>
11#endif
12#ifdef ADAFRUIT_BLE_ENABLE
13#include "adafruit_ble.h"
14#endif
15#ifdef PROTOCOL_LUFA
16#include "lufa.h"
17#endif
18#include "sendchar.h"
19#include "timer.h"
20
21// Set this to 1 to help diagnose early startup problems
22// when testing power-on with ble. Turn it off otherwise,
23// as the latency of printing most of the debug info messes
24// with the matrix scan, causing keys to drop.
25#define DEBUG_TO_SCREEN 0
26
27//static uint16_t last_battery_update;
28//static uint32_t vbat;
29//#define BatteryUpdateInterval 10000 /* milliseconds */
30#define ScreenOffInterval 300000 /* milliseconds */
31#if DEBUG_TO_SCREEN
32static uint8_t displaying;
33#endif
34static uint16_t last_flush;
35
36// Write command sequence.
37// Returns true on success.
38static inline bool _send_cmd1(uint8_t cmd) {
39 bool res = false;
40
41 if (i2c_start_write(SSD1306_ADDRESS)) {
42 xprintf("failed to start write to %d\n", SSD1306_ADDRESS);
43 goto done;
44 }
45
46 if (i2c_master_write(0x0 /* command byte follows */)) {
47 print("failed to write control byte\n");
48
49 goto done;
50 }
51
52 if (i2c_master_write(cmd)) {
53 xprintf("failed to write command %d\n", cmd);
54 goto done;
55 }
56 res = true;
57done:
58 i2c_master_stop();
59 return res;
60}
61
62// Write 2-byte command sequence.
63// Returns true on success
64static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) {
65 if (!_send_cmd1(cmd)) {
66 return false;
67 }
68 return _send_cmd1(opr);
69}
70
71// Write 3-byte command sequence.
72// Returns true on success
73static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) {
74 if (!_send_cmd1(cmd)) {
75 return false;
76 }
77 if (!_send_cmd1(opr1)) {
78 return false;
79 }
80 return _send_cmd1(opr2);
81}
82
83#define send_cmd1(c) if (!_send_cmd1(c)) {goto done;}
84#define send_cmd2(c,o) if (!_send_cmd2(c,o)) {goto done;}
85#define send_cmd3(c,o1,o2) if (!_send_cmd3(c,o1,o2)) {goto done;}
86
87static void clear_display(void) {
88 matrix_clear(&display);
89
90 // Clear all of the display bits (there can be random noise
91 // in the RAM on startup)
92 send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1);
93 send_cmd3(ColumnAddr, 0, DisplayWidth - 1);
94
95 if (i2c_start_write(SSD1306_ADDRESS)) {
96 goto done;
97 }
98 if (i2c_master_write(0x40)) {
99 // Data mode
100 goto done;
101 }
102 for (uint8_t row = 0; row < MatrixRows; ++row) {
103 for (uint8_t col = 0; col < DisplayWidth; ++col) {
104 i2c_master_write(0);
105 }
106 }
107
108 display.dirty = false;
109
110done:
111 i2c_master_stop();
112}
113
114#if DEBUG_TO_SCREEN
115#undef sendchar
116static int8_t capture_sendchar(uint8_t c) {
117 sendchar(c);
118 iota_gfx_write_char(c);
119
120 if (!displaying) {
121 iota_gfx_flush();
122 }
123 return 0;
124}
125#endif
126
127bool iota_gfx_init(bool rotate) {
128 bool success = false;
129
130 i2c_master_init();
131 send_cmd1(DisplayOff);
132 send_cmd2(SetDisplayClockDiv, 0x80);
133 send_cmd2(SetMultiPlex, DisplayHeight - 1);
134
135 send_cmd2(SetDisplayOffset, 0);
136
137
138 send_cmd1(SetStartLine | 0x0);
139 send_cmd2(SetChargePump, 0x14 /* Enable */);
140 send_cmd2(SetMemoryMode, 0 /* horizontal addressing */);
141
142 if(rotate){
143 // the following Flip the display orientation 180 degrees
144 send_cmd1(SegRemap);
145 send_cmd1(ComScanInc);
146 }else{
147 // Flips the display orientation 0 degrees
148 send_cmd1(SegRemap | 0x1);
149 send_cmd1(ComScanDec);
150 }
151
152 send_cmd2(SetComPins, 0x2);
153 send_cmd2(SetContrast, 0x8f);
154 send_cmd2(SetPreCharge, 0xf1);
155 send_cmd2(SetVComDetect, 0x40);
156 send_cmd1(DisplayAllOnResume);
157 send_cmd1(NormalDisplay);
158 send_cmd1(DeActivateScroll);
159 send_cmd1(DisplayOn);
160
161 send_cmd2(SetContrast, 0); // Dim
162
163 clear_display();
164
165 success = true;
166
167 iota_gfx_flush();
168
169#if DEBUG_TO_SCREEN
170 print_set_sendchar(capture_sendchar);
171#endif
172
173done:
174 return success;
175}
176
177bool iota_gfx_off(void) {
178 bool success = false;
179
180 send_cmd1(DisplayOff);
181 success = true;
182
183done:
184 return success;
185}
186
187bool iota_gfx_on(void) {
188 bool success = false;
189
190 send_cmd1(DisplayOn);
191 success = true;
192
193done:
194 return success;
195}
196
197void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) {
198 *matrix->cursor = c;
199 ++matrix->cursor;
200
201 if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) {
202 // We went off the end; scroll the display upwards by one line
203 memmove(&matrix->display[0], &matrix->display[1],
204 MatrixCols * (MatrixRows - 1));
205 matrix->cursor = &matrix->display[MatrixRows - 1][0];
206 memset(matrix->cursor, ' ', MatrixCols);
207 }
208}
209
210void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
211 matrix->dirty = true;
212
213 if (c == '\n') {
214 // Clear to end of line from the cursor and then move to the
215 // start of the next line
216 uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols;
217
218 while (cursor_col++ < MatrixCols) {
219 matrix_write_char_inner(matrix, ' ');
220 }
221 return;
222 }
223
224 matrix_write_char_inner(matrix, c);
225}
226
227void iota_gfx_write_char(uint8_t c) {
228 matrix_write_char(&display, c);
229}
230
231void matrix_write(struct CharacterMatrix *matrix, const char *data) {
232 const char *end = data + strlen(data);
233 while (data < end) {
234 matrix_write_char(matrix, *data);
235 ++data;
236 }
237}
238
239void iota_gfx_write(const char *data) {
240 matrix_write(&display, data);
241}
242
243void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
244 while (true) {
245 uint8_t c = pgm_read_byte(data);
246 if (c == 0) {
247 return;
248 }
249 matrix_write_char(matrix, c);
250 ++data;
251 }
252}
253
254void iota_gfx_write_P(const char *data) {
255 matrix_write_P(&display, data);
256}
257
258void matrix_clear(struct CharacterMatrix *matrix) {
259 memset(matrix->display, ' ', sizeof(matrix->display));
260 matrix->cursor = &matrix->display[0][0];
261 matrix->dirty = true;
262}
263
264void iota_gfx_clear_screen(void) {
265 matrix_clear(&display);
266}
267
268void matrix_render(struct CharacterMatrix *matrix) {
269 last_flush = timer_read();
270 iota_gfx_on();
271#if DEBUG_TO_SCREEN
272 ++displaying;
273#endif
274
275 // Move to the home position
276 send_cmd3(PageAddr, 0, MatrixRows - 1);
277 send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1);
278
279 if (i2c_start_write(SSD1306_ADDRESS)) {
280 goto done;
281 }
282 if (i2c_master_write(0x40)) {
283 // Data mode
284 goto done;
285 }
286
287 for (uint8_t row = 0; row < MatrixRows; ++row) {
288 for (uint8_t col = 0; col < MatrixCols; ++col) {
289 const uint8_t *glyph = font + (matrix->display[row][col] * FontWidth);
290
291 for (uint8_t glyphCol = 0; glyphCol < FontWidth; ++glyphCol) {
292 uint8_t colBits = pgm_read_byte(glyph + glyphCol);
293 i2c_master_write(colBits);
294 }
295
296 // 1 column of space between chars (it's not included in the glyph)
297 //i2c_master_write(0);
298 }
299 }
300
301 matrix->dirty = false;
302
303done:
304 i2c_master_stop();
305#if DEBUG_TO_SCREEN
306 --displaying;
307#endif
308}
309
310void iota_gfx_flush(void) {
311 matrix_render(&display);
312}
313
314__attribute__ ((weak))
315void iota_gfx_task_user(void) {
316}
317
318void iota_gfx_task(void) {
319 iota_gfx_task_user();
320
321 if (display.dirty) {
322 iota_gfx_flush();
323 }
324
325 if (timer_elapsed(last_flush) > ScreenOffInterval) {
326 iota_gfx_off();
327 }
328}
329#endif
diff --git a/keyboards/sol/common/ssd1306.h b/keyboards/sol/common/ssd1306.h
deleted file mode 100644
index 77ce7c211..000000000
--- a/keyboards/sol/common/ssd1306.h
+++ /dev/null
@@ -1,92 +0,0 @@
1#ifndef SSD1306_H
2#define SSD1306_H
3
4#include <stdbool.h>
5#include <stdio.h>
6#include "pincontrol.h"
7
8enum ssd1306_cmds {
9 DisplayOff = 0xAE,
10 DisplayOn = 0xAF,
11
12 SetContrast = 0x81,
13 DisplayAllOnResume = 0xA4,
14
15 DisplayAllOn = 0xA5,
16 NormalDisplay = 0xA6,
17 InvertDisplay = 0xA7,
18 SetDisplayOffset = 0xD3,
19 SetComPins = 0xda,
20 SetVComDetect = 0xdb,
21 SetDisplayClockDiv = 0xD5,
22 SetPreCharge = 0xd9,
23 SetMultiPlex = 0xa8,
24 SetLowColumn = 0x00,
25 SetHighColumn = 0x10,
26 SetStartLine = 0x40,
27
28 SetMemoryMode = 0x20,
29 ColumnAddr = 0x21,
30 PageAddr = 0x22,
31
32 ComScanInc = 0xc0,
33 ComScanDec = 0xc8,
34 SegRemap = 0xa0,
35 SetChargePump = 0x8d,
36 ExternalVcc = 0x01,
37 SwitchCapVcc = 0x02,
38
39 ActivateScroll = 0x2f,
40 DeActivateScroll = 0x2e,
41 SetVerticalScrollArea = 0xa3,
42 RightHorizontalScroll = 0x26,
43 LeftHorizontalScroll = 0x27,
44 VerticalAndRightHorizontalScroll = 0x29,
45 VerticalAndLeftHorizontalScroll = 0x2a,
46};
47
48// Controls the SSD1306 128x32 OLED display via i2c
49
50#ifndef SSD1306_ADDRESS
51#define SSD1306_ADDRESS 0x3C
52#endif
53
54#define DisplayHeight 32
55#define DisplayWidth 128
56
57#define FontHeight 8
58#define FontWidth 6
59
60#define MatrixRows (DisplayHeight / FontHeight)
61#define MatrixCols (DisplayWidth / FontWidth)
62
63struct CharacterMatrix {
64 uint8_t display[MatrixRows][MatrixCols];
65 uint8_t *cursor;
66 bool dirty;
67};
68
69struct CharacterMatrix display;
70
71bool iota_gfx_init(bool rotate);
72void iota_gfx_task(void);
73bool iota_gfx_off(void);
74bool iota_gfx_on(void);
75void iota_gfx_flush(void);
76void iota_gfx_write_char(uint8_t c);
77void iota_gfx_write(const char *data);
78void iota_gfx_write_P(const char *data);
79void iota_gfx_clear_screen(void);
80
81void iota_gfx_task_user(void);
82
83void matrix_clear(struct CharacterMatrix *matrix);
84void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c);
85void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c);
86void matrix_write(struct CharacterMatrix *matrix, const char *data);
87void matrix_write_P(struct CharacterMatrix *matrix, const char *data);
88void matrix_render(struct CharacterMatrix *matrix);
89
90
91
92#endif
diff --git a/keyboards/sol/i2c.c b/keyboards/sol/i2c.c
deleted file mode 100644
index 4bee5c639..000000000
--- a/keyboards/sol/i2c.c
+++ /dev/null
@@ -1,162 +0,0 @@
1#include <util/twi.h>
2#include <avr/io.h>
3#include <stdlib.h>
4#include <avr/interrupt.h>
5#include <util/twi.h>
6#include <stdbool.h>
7#include "i2c.h"
8
9#ifdef USE_I2C
10
11// Limits the amount of we wait for any one i2c transaction.
12// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
13// 9 bits, a single transaction will take around 90μs to complete.
14//
15// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit
16// poll loop takes at least 8 clock cycles to execute
17#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
18
19#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
20
21volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23static volatile uint8_t slave_buffer_pos;
24static volatile bool slave_has_register_set = false;
25
26// Wait for an i2c operation to finish
27inline static
28void i2c_delay(void) {
29 uint16_t lim = 0;
30 while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
31 lim++;
32
33 // easier way, but will wait slightly longer
34 // _delay_us(100);
35}
36
37// Setup twi to run at 100kHz or 400kHz (see ./i2c.h SCL_CLOCK)
38void i2c_master_init(void) {
39 // no prescaler
40 TWSR = 0;
41 // Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
42 // Check datasheets for more info.
43 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
44}
45
46// Start a transaction with the given i2c slave address. The direction of the
47// transfer is set with I2C_READ and I2C_WRITE.
48// returns: 0 => success
49// 1 => error
50uint8_t i2c_master_start(uint8_t address) {
51 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
52
53 i2c_delay();
54
55 // check that we started successfully
56 if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
57 return 1;
58
59 TWDR = address;
60 TWCR = (1<<TWINT) | (1<<TWEN);
61
62 i2c_delay();
63
64 if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
65 return 1; // slave did not acknowledge
66 else
67 return 0; // success
68}
69
70
71// Finish the i2c transaction.
72void i2c_master_stop(void) {
73 TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
74
75 uint16_t lim = 0;
76 while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
77 lim++;
78}
79
80// Write one byte to the i2c slave.
81// returns 0 => slave ACK
82// 1 => slave NACK
83uint8_t i2c_master_write(uint8_t data) {
84 TWDR = data;
85 TWCR = (1<<TWINT) | (1<<TWEN);
86
87 i2c_delay();
88
89 // check if the slave acknowledged us
90 return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
91}
92
93// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
94// if ack=0 the acknowledge bit is not set.
95// returns: byte read from i2c device
96uint8_t i2c_master_read(int ack) {
97 TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
98
99 i2c_delay();
100 return TWDR;
101}
102
103void i2c_reset_state(void) {
104 TWCR = 0;
105}
106
107void i2c_slave_init(uint8_t address) {
108 TWAR = address << 0; // slave i2c address
109 // TWEN - twi enable
110 // TWEA - enable address acknowledgement
111 // TWINT - twi interrupt flag
112 // TWIE - enable the twi interrupt
113 TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
114}
115
116ISR(TWI_vect);
117
118ISR(TWI_vect) {
119 uint8_t ack = 1;
120 switch(TW_STATUS) {
121 case TW_SR_SLA_ACK:
122 // this device has been addressed as a slave receiver
123 slave_has_register_set = false;
124 break;
125
126 case TW_SR_DATA_ACK:
127 // this device has received data as a slave receiver
128 // The first byte that we receive in this transaction sets the location
129 // of the read/write location of the slaves memory that it exposes over
130 // i2c. After that, bytes will be written at slave_buffer_pos, incrementing
131 // slave_buffer_pos after each write.
132 if(!slave_has_register_set) {
133 slave_buffer_pos = TWDR;
134 // don't acknowledge the master if this memory loctaion is out of bounds
135 if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
136 ack = 0;
137 slave_buffer_pos = 0;
138 }
139 slave_has_register_set = true;
140 } else {
141 i2c_slave_buffer[slave_buffer_pos] = TWDR;
142 BUFFER_POS_INC();
143 }
144 break;
145
146 case TW_ST_SLA_ACK:
147 case TW_ST_DATA_ACK:
148 // master has addressed this device as a slave transmitter and is
149 // requesting data.
150 TWDR = i2c_slave_buffer[slave_buffer_pos];
151 BUFFER_POS_INC();
152 break;
153
154 case TW_BUS_ERROR: // something went wrong, reset twi state
155 TWCR = 0;
156 default:
157 break;
158 }
159 // Reset everything, so we are ready for the next TWI interrupt
160 TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
161}
162#endif
diff --git a/keyboards/sol/i2c.h b/keyboards/sol/i2c.h
deleted file mode 100644
index 47cf6bd1b..000000000
--- a/keyboards/sol/i2c.h
+++ /dev/null
@@ -1,49 +0,0 @@
1#ifndef I2C_H
2#define I2C_H
3
4#include <stdint.h>
5
6#ifndef F_CPU
7#define F_CPU 16000000UL
8#endif
9
10#define I2C_READ 1
11#define I2C_WRITE 0
12
13#define I2C_ACK 1
14#define I2C_NACK 0
15
16#define SLAVE_BUFFER_SIZE 0x10
17
18// i2c SCL clock frequency 400kHz
19#define SCL_CLOCK 400000L
20
21extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
23void i2c_master_init(void);
24uint8_t i2c_master_start(uint8_t address);
25void i2c_master_stop(void);
26uint8_t i2c_master_write(uint8_t data);
27uint8_t i2c_master_read(int);
28void i2c_reset_state(void);
29void i2c_slave_init(uint8_t address);
30
31
32static inline unsigned char i2c_start_read(unsigned char addr) {
33 return i2c_master_start((addr << 1) | I2C_READ);
34}
35
36static inline unsigned char i2c_start_write(unsigned char addr) {
37 return i2c_master_start((addr << 1) | I2C_WRITE);
38}
39
40// from SSD1306 scrips
41extern unsigned char i2c_rep_start(unsigned char addr);
42extern void i2c_start_wait(unsigned char addr);
43extern unsigned char i2c_readAck(void);
44extern unsigned char i2c_readNak(void);
45extern unsigned char i2c_read(unsigned char ack);
46
47#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
48
49#endif
diff --git a/keyboards/sol/keymaps/brianweyer/config.h b/keyboards/sol/keymaps/brianweyer/config.h
index 87b7dd2ac..452cdda82 100755
--- a/keyboards/sol/keymaps/brianweyer/config.h
+++ b/keyboards/sol/keymaps/brianweyer/config.h
@@ -20,8 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
20 20
21#pragma once 21#pragma once
22 22
23#define SSD1306OLED
24
25 23
26// place overrides here 24// place overrides here
27 25
diff --git a/keyboards/sol/keymaps/brianweyer/keymap.c b/keyboards/sol/keymaps/brianweyer/keymap.c
index 2259e246d..9fd6ad615 100755
--- a/keyboards/sol/keymaps/brianweyer/keymap.c
+++ b/keyboards/sol/keymaps/brianweyer/keymap.c
@@ -3,9 +3,6 @@
3#include "lufa.h" 3#include "lufa.h"
4#include "split_util.h" 4#include "split_util.h"
5#endif 5#endif
6#ifdef SSD1306OLED
7 #include "common/ssd1306.h"
8#endif
9 6
10extern keymap_config_t keymap_config; 7extern keymap_config_t keymap_config;
11 8
@@ -175,38 +172,28 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
175} 172}
176 173
177void matrix_init_user(void) { 174void matrix_init_user(void) {
178 #ifdef RGBLIGHT_ENABLE 175#ifdef RGBLIGHT_ENABLE
179 RGB_current_mode = rgblight_config.mode; 176 RGB_current_mode = rgblight_config.mode;
180 #endif 177#endif
181 //SSD1306 OLED init, make sure to add #define SSD1306OLED in config.h
182 #ifdef SSD1306OLED
183 iota_gfx_init(!has_usb()); // turns on the display
184 #endif
185} 178}
186 179
187void matrix_scan_user(void) {
188 #ifdef SSD1306OLED
189 // led_test_init();
190 iota_gfx_task(); // this is what updates the display continuously
191 #endif
192}
193 180
181// OLED Driver Logic
182#ifdef OLED_DRIVER_ENABLE
194 183
195//SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h 184uint8_t oled_init_user(uint8_t rotation) {
196#ifdef SSD1306OLED 185 if (!has_usb())
186 return OLED_ROTATION_180; // flip 180 for offhand
187 return rotation;
188}
197 189
198// hook point for 'led_test' keymap 190static void render_logo(void) {
199// 'default' keymap's led_test_init() is empty function, do nothing 191 static const char PROGMEM sol_logo[] = {
200// 'led_test' keymap's led_test_init() force rgblight_mode_noeeprom(35); 192 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
201__attribute__ ((weak)) 193 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
202void led_test_init(void) {} 194 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
203 195
204void matrix_update(struct CharacterMatrix *dest, 196 oled_write_P(sol_logo, false);
205 const struct CharacterMatrix *source) {
206 if (memcmp(dest->display, source->display, sizeof(dest->display))) {
207 memcpy(dest->display, source->display, sizeof(dest->display));
208 dest->dirty = true;
209 }
210} 197}
211 198
212//assign the right code to your layers for OLED display 199//assign the right code to your layers for OLED display
@@ -215,77 +202,52 @@ void matrix_update(struct CharacterMatrix *dest,
215#define L_ADJ (1<<_ADJ) 202#define L_ADJ (1<<_ADJ)
216#define L_ADJ_TRI (L_ADJ|L_FN) 203#define L_ADJ_TRI (L_ADJ|L_FN)
217 204
218static void render_logo(struct CharacterMatrix *matrix) { 205static void render_status(void) {
219
220 static char logo[]={
221 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
222 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
223 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,
224 0};
225 matrix_write(matrix, logo);
226}
227
228
229
230void render_status(struct CharacterMatrix *matrix) {
231
232 // Render to mode icon 206 // Render to mode icon
233 static char logo[][2][3]={{{0x95,0x96,0},{0xb5,0xb6,0}},{{0x97,0x98,0},{0xb7,0xb8,0}}}; 207 static const char PROGMEM mode_logo[4][4] = {
234 if(keymap_config.swap_lalt_lgui==false){ 208 {0x95,0x96,0x0a,0},
235 matrix_write(matrix, logo[0][0]); 209 {0xb5,0xb6,0x0a,0},
236 matrix_write_P(matrix, PSTR("\n")); 210 {0x97,0x98,0x0a,0},
237 matrix_write(matrix, logo[0][1]); 211 {0xb7,0xb8,0x0a,0} };
238 }else{ 212
239 matrix_write(matrix, logo[1][0]); 213 if (keymap_config.swap_lalt_lgui != false) {
240 matrix_write_P(matrix, PSTR("\n")); 214 oled_write_P(mode_logo[0], false);
241 matrix_write(matrix, logo[1][1]); 215 oled_write_P(mode_logo[1], false);
216 } else {
217 oled_write_P(mode_logo[2], false);
218 oled_write_P(mode_logo[3], false);
242 } 219 }
243 220
244 // 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 221 // 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
245 char buf[40]; 222
246 snprintf(buf,sizeof(buf), "Undef-%ld", layer_state); 223 oled_write_P(PSTR("Layer: "), false);
247 matrix_write_P(matrix, PSTR("\nLayer: ")); 224 switch (layer_state) {
248 switch (layer_state) { 225 case L_BASE:
249 case L_BASE: 226 oled_write_P(PSTR("Laser \n"), false);
250 matrix_write_P(matrix, PSTR("Laser")); 227 break;
251 break; 228 case L_FN:
252 case L_FN: 229 oled_write_P(PSTR("Function \n"), false);
253 matrix_write_P(matrix, PSTR("Function")); 230 break;
254 break; 231 case L_ADJ:
255 case L_ADJ: 232 case L_ADJ_TRI:
256 case L_ADJ_TRI: 233 oled_write_P(PSTR("Adjustment\n"), false);
257 matrix_write_P(matrix, PSTR("Adjustment")); 234 break;
258 break; 235 default:
259 default: 236 oled_write_P(PSTR("Undefined \n"), false);
260 matrix_write(matrix, buf); 237 }
261 }
262 238
263 // Host Keyboard LED Status 239 // Host Keyboard LED Status
264 char led[40]; 240 uint8_t led_usb_state = host_keyboard_leds();
265 snprintf(led, sizeof(led), "\n%s %s %s", 241 oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLOCK ") : PSTR(" "), false);
266 (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ", 242 oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPS ") : PSTR(" "), false);
267 (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ", 243 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCLK ") : PSTR(" "), false);
268 (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " ");
269 matrix_write(matrix, led);
270} 244}
271 245
272 246void oled_task_user(void) {
273void iota_gfx_task_user(void) { 247 if (is_master)
274 struct CharacterMatrix matrix; 248 render_status();
275 249 else
276#if DEBUG_TO_SCREEN 250 render_logo();
277 if (debug_enable) {
278 return;
279 }
280#endif
281
282 matrix_clear(&matrix);
283 if(is_master){
284 render_status(&matrix);
285 }else{
286 render_logo(&matrix);
287 }
288 matrix_update(&display, &matrix);
289} 251}
290 252
291#endif 253#endif
diff --git a/keyboards/sol/keymaps/brianweyer/rules.mk b/keyboards/sol/keymaps/brianweyer/rules.mk
index d53ebe34d..15b0c8fd2 100755
--- a/keyboards/sol/keymaps/brianweyer/rules.mk
+++ b/keyboards/sol/keymaps/brianweyer/rules.mk
@@ -4,12 +4,13 @@
4# 4#
5BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) 5BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000)
6MOUSEKEY_ENABLE = no # Mouse keys(+4700) 6MOUSEKEY_ENABLE = no # Mouse keys(+4700)
7
7EXTRAKEY_ENABLE = yes # Audio control and System control(+450) 8EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
8CONSOLE_ENABLE = no # Console for debug(+400) 9CONSOLE_ENABLE = no # Console for debug(+400)
9COMMAND_ENABLE = no # Commands for debug and configuration 10COMMAND_ENABLE = no # Commands for debug and configuration
10NKRO_ENABLE = no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work 11NKRO_ENABLE = no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
11RGBLIGHT_ENABLE = yes # Enable global lighting effects. Do not enable with RGB Matrix 12RGBLIGHT_ENABLE = yes # Enable global lighting effects. Do not enable with RGB Matrix
12LED_ANIMATIONS = yes # LED animations 13RGBLIGHT_ANIMATIONS = yes # LED animations
13LED_MIRRORED = no # Mirror LEDs across halves (enable DIP 1 on slave, and DIP 2 and 3 on master) 14LED_MIRRORED = no # Mirror LEDs across halves (enable DIP 1 on slave, and DIP 2 and 3 on master)
14RGB_MATRIX_ENABLE = no # Enable per-key coordinate based RGB effects. Do not enable with RGBlight (+8500) 15RGB_MATRIX_ENABLE = no # Enable per-key coordinate based RGB effects. Do not enable with RGBlight (+8500)
15RGB_MATRIX_KEYPRESSES = no # Enable reactive per-key effects. Can be very laggy (+1500) 16RGB_MATRIX_KEYPRESSES = no # Enable reactive per-key effects. Can be very laggy (+1500)
@@ -17,15 +18,12 @@ RGBLIGHT_FULL_POWER = no # Allow maximum RGB brightness. Otherwise, limited t
17UNICODE_ENABLE = no # Unicode 18UNICODE_ENABLE = no # Unicode
18SWAP_HANDS_ENABLE = no # Enable one-hand typing 19SWAP_HANDS_ENABLE = no # Enable one-hand typing
19ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90) 20ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90)
20OLED_ENABLE = yes # OLED_ENABLE (+5000) 21
22OLED_DRIVER_ENABLE = yes # Enable the OLED Driver (+5000)
21IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone) 23IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone)
22 24
23# Do not edit past here 25# Do not edit past here
24 26
25ifeq ($(strip $(OLED_ENABLE)), yes)
26 OPT_DEFS += -DOLED_ENABLE
27endif
28
29ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes) 27ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes)
30 OPT_DEFS += -DENCODER_ENABLE_CUSTOM 28 OPT_DEFS += -DENCODER_ENABLE_CUSTOM
31 SRC += common/knob_v2.c 29 SRC += common/knob_v2.c
diff --git a/keyboards/sol/keymaps/danielhklein/keymap.c b/keyboards/sol/keymaps/danielhklein/keymap.c
index 883b41826..cfc295323 100644
--- a/keyboards/sol/keymaps/danielhklein/keymap.c
+++ b/keyboards/sol/keymaps/danielhklein/keymap.c
@@ -3,9 +3,6 @@
3#include "lufa.h" 3#include "lufa.h"
4#include "split_util.h" 4#include "split_util.h"
5#endif 5#endif
6#ifdef SSD1306OLED
7 #include "common/ssd1306.h"
8#endif
9 6
10extern keymap_config_t keymap_config; 7extern keymap_config_t keymap_config;
11 8
@@ -240,115 +237,81 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
240} 237}
241 238
242void matrix_init_user(void) { 239void matrix_init_user(void) {
243 #ifdef RGBLIGHT_ENABLE 240#ifdef RGBLIGHT_ENABLE
244 RGB_current_mode = rgblight_config.mode; 241 RGB_current_mode = rgblight_config.mode;
245 #endif 242#endif
246 //SSD1306 OLED init, make sure to add #define SSD1306OLED in config.h
247 #ifdef SSD1306OLED
248 iota_gfx_init(!has_usb()); // turns on the display
249 #endif
250} 243}
251 244
252 245
253//SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h 246// OLED Driver Logic
254#ifdef SSD1306OLED 247#ifdef OLED_DRIVER_ENABLE
255 248
256// hook point for 'led_test' keymap 249uint8_t oled_init_user(uint8_t rotation) {
257// 'default' keymap's led_test_init() is empty function, do nothing 250 if (!has_usb())
258// 'led_test' keymap's led_test_init() force rgblight_mode_noeeprom(35); 251 return OLED_ROTATION_180; // flip 180 for offhand
259__attribute__ ((weak)) 252 return rotation;
260void led_test_init(void) {}
261
262void matrix_scan_user(void) {
263 led_test_init();
264 iota_gfx_task(); // this is what updates the display continuously
265} 253}
266 254
267void matrix_update(struct CharacterMatrix *dest, 255static void render_logo(void) {
268 const struct CharacterMatrix *source) { 256 static const char PROGMEM sol_logo[] = {
269 if (memcmp(dest->display, source->display, sizeof(dest->display))) { 257 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
270 memcpy(dest->display, source->display, sizeof(dest->display)); 258 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
271 dest->dirty = true; 259 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
272 } 260
261 oled_write_P(sol_logo, false);
273} 262}
274 263
275//assign the right code to your layers for OLED display 264//assign the right code to your layers for OLED display
276#define L_BASE 0 265#define L_BASE 0
277#define L_FN (1<<_FN) 266#define L_FN (1<<_FN)
278#define L_ADJ (1<<_ADJ) 267#define L_ADJ (1<<_ADJ)
268#define L_ADJ_TRI (L_ADJ|L_FN)
279 269
280static void render_logo(struct CharacterMatrix *matrix) { 270static void render_status(void) {
281
282 static char logo[]={
283 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
284 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
285 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,
286 0};
287 matrix_write(matrix, logo);
288 //matrix_write_P(&matrix, PSTR(" Split keyboard kit"));
289}
290
291
292
293void render_status(struct CharacterMatrix *matrix) {
294
295 // Render to mode icon 271 // Render to mode icon
296 static char logo[][2][3]={{{0x95,0x96,0},{0xb5,0xb6,0}},{{0x97,0x98,0},{0xb7,0xb8,0}}}; 272 static const char PROGMEM mode_logo[4][4] = {
297 if(keymap_config.swap_lalt_lgui==false){ 273 {0x95,0x96,0x0a,0},
298 matrix_write(matrix, logo[0][0]); 274 {0xb5,0xb6,0x0a,0},
299 matrix_write_P(matrix, PSTR("\n")); 275 {0x97,0x98,0x0a,0},
300 matrix_write(matrix, logo[0][1]); 276 {0xb7,0xb8,0x0a,0} };
301 }else{ 277
302 matrix_write(matrix, logo[1][0]); 278 if (keymap_config.swap_lalt_lgui != false) {
303 matrix_write_P(matrix, PSTR("\n")); 279 oled_write_P(mode_logo[0], false);
304 matrix_write(matrix, logo[1][1]); 280 oled_write_P(mode_logo[1], false);
281 } else {
282 oled_write_P(mode_logo[2], false);
283 oled_write_P(mode_logo[3], false);
305 } 284 }
306 285
307 // 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 286 // 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
308 char buf[40]; 287 oled_write_P(PSTR("Layer: "), false);
309 snprintf(buf,sizeof(buf), "Undef-%ld", layer_state); 288 switch (layer_state) {
310 matrix_write_P(matrix, PSTR("\nLayer: ")); 289 case L_BASE:
311 switch (layer_state) { 290 oled_write_P(PSTR("Default\n"), false);
312 case L_BASE: 291 break;
313 matrix_write_P(matrix, PSTR("Default")); 292 case L_FN:
314 break; 293 oled_write_P(PSTR("FN \n"), false);
315 case L_FN: 294 break;
316 matrix_write_P(matrix, PSTR("FN")); 295 case L_ADJ:
317 break; 296 case L_ADJ_TRI:
318 case L_ADJ: 297 oled_write_P(PSTR("ADJ \n"), false);
319 case L_ADJ_TRI: 298 break;
320 matrix_write_P(matrix, PSTR("ADJ")); 299 default:
321 break; 300 oled_write_P(PSTR("UNDEF \n"), false);
322 default: 301 }
323 matrix_write(matrix, buf);
324 }
325 302
326 // Host Keyboard LED Status 303 // Host Keyboard LED Status
327 char led[40]; 304 uint8_t led_usb_state = host_keyboard_leds();
328 snprintf(led, sizeof(led), "\n%s %s %s", 305 oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLOCK ") : PSTR(" "), false);
329 (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ", 306 oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPS ") : PSTR(" "), false);
330 (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ", 307 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCLK ") : PSTR(" "), false);
331 (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " ");
332 matrix_write(matrix, led);
333} 308}
334 309
335 310void oled_task_user(void) {
336void iota_gfx_task_user(void) { 311 if (is_master)
337 struct CharacterMatrix matrix; 312 render_status();
338 313 else
339#if DEBUG_TO_SCREEN 314 render_logo();
340 if (debug_enable) {
341 return;
342 }
343#endif
344
345 matrix_clear(&matrix);
346 if(is_master){
347 render_status(&matrix);
348 }else{
349 render_logo(&matrix);
350 }
351 matrix_update(&display, &matrix);
352} 315}
353 316
354#endif 317#endif
diff --git a/keyboards/sol/keymaps/danielhklein/rules.mk b/keyboards/sol/keymaps/danielhklein/rules.mk
index 199dad6fc..526b72fe7 100644
--- a/keyboards/sol/keymaps/danielhklein/rules.mk
+++ b/keyboards/sol/keymaps/danielhklein/rules.mk
@@ -19,24 +19,18 @@ UNICODE_ENABLE = no # Unicode
19SWAP_HANDS_ENABLE = no # Enable one-hand typing 19SWAP_HANDS_ENABLE = no # Enable one-hand typing
20ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90) 20ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90)
21 21
22OLED_ENABLE = no # OLED_ENABLE (+5000) 22OLED_DRIVER_ENABLE = no # Enable the OLED Driver (+5000)
23IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone) 23IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone)
24 24
25# Do not edit past here 25# Do not edit past here
26 26
27ifeq ($(strip $(OLED_ENABLE)), yes)
28 OPT_DEFS += -DOLED_ENABLE
29endif
30
31ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes) 27ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes)
32 OPT_DEFS += -DENCODER_ENABLE_CUSTOM 28 OPT_DEFS += -DENCODER_ENABLE_CUSTOM
33 SRC += common/knob_v2.c 29 SRC += common/knob_v2.c
34
35endif 30endif
36 31
37ifeq ($(strip $(IOS_DEVICE_ENABLE)), yes) 32ifeq ($(strip $(IOS_DEVICE_ENABLE)), yes)
38 OPT_DEFS += -DIOS_DEVICE_ENABLE 33 OPT_DEFS += -DIOS_DEVICE_ENABLE
39
40else ifeq ($(strip $(RGBLIGHT_FULL_POWER)), yes) 34else ifeq ($(strip $(RGBLIGHT_FULL_POWER)), yes)
41 OPT_DEFS += -DRGBLIGHT_FULL_POWER 35 OPT_DEFS += -DRGBLIGHT_FULL_POWER
42endif 36endif
diff --git a/keyboards/sol/keymaps/default/keymap.c b/keyboards/sol/keymaps/default/keymap.c
index 799507f66..1742fc597 100644
--- a/keyboards/sol/keymaps/default/keymap.c
+++ b/keyboards/sol/keymaps/default/keymap.c
@@ -4,9 +4,6 @@
4#include "lufa.h" 4#include "lufa.h"
5#include "split_util.h" 5#include "split_util.h"
6#endif 6#endif
7#ifdef SSD1306OLED
8 #include "common/ssd1306.h"
9#endif
10 7
11extern keymap_config_t keymap_config; 8extern keymap_config_t keymap_config;
12 9
@@ -248,115 +245,81 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
248} 245}
249 246
250void matrix_init_user(void) { 247void matrix_init_user(void) {
251 #ifdef RGBLIGHT_ENABLE 248#ifdef RGBLIGHT_ENABLE
252 RGB_current_mode = rgblight_config.mode; 249 RGB_current_mode = rgblight_config.mode;
253 #endif 250#endif
254 //SSD1306 OLED init, make sure to add #define SSD1306OLED in config.h
255 #ifdef SSD1306OLED
256 iota_gfx_init(!has_usb()); // turns on the display
257 #endif
258} 251}
259 252
260 253
261//SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h 254// OLED Driver Logic
262#ifdef SSD1306OLED 255#ifdef OLED_DRIVER_ENABLE
263 256
264// hook point for 'led_test' keymap 257uint8_t oled_init_user(uint8_t rotation) {
265// 'default' keymap's led_test_init() is empty function, do nothing 258 if (!has_usb())
266// 'led_test' keymap's led_test_init() force rgblight_mode_noeeprom(35); 259 return OLED_ROTATION_180; // flip 180 for offhand
267__attribute__ ((weak)) 260 return rotation;
268void led_test_init(void) {}
269
270void matrix_scan_user(void) {
271 led_test_init();
272 iota_gfx_task(); // this is what updates the display continuously
273} 261}
274 262
275void matrix_update(struct CharacterMatrix *dest, 263static void render_logo(void) {
276 const struct CharacterMatrix *source) { 264 static const char PROGMEM sol_logo[] = {
277 if (memcmp(dest->display, source->display, sizeof(dest->display))) { 265 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
278 memcpy(dest->display, source->display, sizeof(dest->display)); 266 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
279 dest->dirty = true; 267 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
280 } 268
269 oled_write_P(sol_logo, false);
281} 270}
282 271
283//assign the right code to your layers for OLED display 272//assign the right code to your layers for OLED display
284#define L_BASE 0 273#define L_BASE 0
285#define L_FN (1<<_FN) 274#define L_FN (1<<_FN)
286#define L_ADJ (1<<_ADJ) 275#define L_ADJ (1<<_ADJ)
276#define L_ADJ_TRI (L_ADJ|L_FN)
287 277
288static void render_logo(struct CharacterMatrix *matrix) { 278static void render_status(void) {
289
290 static char logo[]={
291 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
292 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
293 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,
294 0};
295 matrix_write(matrix, logo);
296 //matrix_write_P(&matrix, PSTR(" Split keyboard kit"));
297}
298
299
300
301void render_status(struct CharacterMatrix *matrix) {
302
303 // Render to mode icon 279 // Render to mode icon
304 static char logo[][2][3]={{{0x95,0x96,0},{0xb5,0xb6,0}},{{0x97,0x98,0},{0xb7,0xb8,0}}}; 280 static const char PROGMEM mode_logo[4][4] = {
305 if(keymap_config.swap_lalt_lgui==false){ 281 {0x95,0x96,0x0a,0},
306 matrix_write(matrix, logo[0][0]); 282 {0xb5,0xb6,0x0a,0},
307 matrix_write_P(matrix, PSTR("\n")); 283 {0x97,0x98,0x0a,0},
308 matrix_write(matrix, logo[0][1]); 284 {0xb7,0xb8,0x0a,0} };
309 }else{ 285
310 matrix_write(matrix, logo[1][0]); 286 if (keymap_config.swap_lalt_lgui != false) {
311 matrix_write_P(matrix, PSTR("\n")); 287 oled_write_P(mode_logo[0], false);
312 matrix_write(matrix, logo[1][1]); 288 oled_write_P(mode_logo[1], false);
289 } else {
290 oled_write_P(mode_logo[2], false);
291 oled_write_P(mode_logo[3], false);
313 } 292 }
314 293
315 // 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 294 // 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
316 char buf[40]; 295 oled_write_P(PSTR("Layer: "), false);
317 snprintf(buf,sizeof(buf), "Undef-%ld", layer_state); 296 switch (layer_state) {
318 matrix_write_P(matrix, PSTR("\nLayer: ")); 297 case L_BASE:
319 switch (layer_state) { 298 oled_write_P(PSTR("Default\n"), false);
320 case L_BASE: 299 break;
321 matrix_write_P(matrix, PSTR("Default")); 300 case L_FN:
322 break; 301 oled_write_P(PSTR("FN \n"), false);
323 case L_FN: 302 break;
324 matrix_write_P(matrix, PSTR("FN")); 303 case L_ADJ:
325 break; 304 case L_ADJ_TRI:
326 case L_ADJ: 305 oled_write_P(PSTR("ADJ \n"), false);
327 case L_ADJ_TRI: 306 break;
328 matrix_write_P(matrix, PSTR("ADJ")); 307 default:
329 break; 308 oled_write_P(PSTR("UNDEF \n"), false);
330 default: 309 }
331 matrix_write(matrix, buf);
332 }
333 310
334 // Host Keyboard LED Status 311 // Host Keyboard LED Status
335 char led[40]; 312 uint8_t led_usb_state = host_keyboard_leds();
336 snprintf(led, sizeof(led), "\n%s %s %s", 313 oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLOCK ") : PSTR(" "), false);
337 (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : " ", 314 oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPS ") : PSTR(" "), false);
338 (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : " ", 315 oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCLK ") : PSTR(" "), false);
339 (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : " ");
340 matrix_write(matrix, led);
341} 316}
342 317
343 318void oled_task_user(void) {
344void iota_gfx_task_user(void) { 319 if (is_master)
345 struct CharacterMatrix matrix; 320 render_status();
346 321 else
347#if DEBUG_TO_SCREEN 322 render_logo();
348 if (debug_enable) {
349 return;
350 }
351#endif
352
353 matrix_clear(&matrix);
354 if(is_master){
355 render_status(&matrix);
356 }else{
357 render_logo(&matrix);
358 }
359 matrix_update(&display, &matrix);
360} 323}
361 324
362#endif 325#endif
diff --git a/keyboards/sol/keymaps/default/rules.mk b/keyboards/sol/keymaps/default/rules.mk
index a098cfd78..40167b375 100644
--- a/keyboards/sol/keymaps/default/rules.mk
+++ b/keyboards/sol/keymaps/default/rules.mk
@@ -24,19 +24,13 @@ IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPa
24 24
25# Do not edit past here 25# Do not edit past here
26 26
27ifeq ($(strip $(OLED_ENABLE)), yes)
28 OPT_DEFS += -DOLED_ENABLE
29endif
30
31ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes) 27ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes)
32 OPT_DEFS += -DENCODER_ENABLE_CUSTOM 28 OPT_DEFS += -DENCODER_ENABLE_CUSTOM
33 SRC += common/knob_v2.c 29 SRC += common/knob_v2.c
34
35endif 30endif
36 31
37ifeq ($(strip $(IOS_DEVICE_ENABLE)), yes) 32ifeq ($(strip $(IOS_DEVICE_ENABLE)), yes)
38 OPT_DEFS += -DIOS_DEVICE_ENABLE 33 OPT_DEFS += -DIOS_DEVICE_ENABLE
39
40else ifeq ($(strip $(RGBLIGHT_FULL_POWER)), yes) 34else ifeq ($(strip $(RGBLIGHT_FULL_POWER)), yes)
41 OPT_DEFS += -DRGBLIGHT_FULL_POWER 35 OPT_DEFS += -DRGBLIGHT_FULL_POWER
42endif 36endif
@@ -47,4 +41,4 @@ endif
47 41
48ifeq ($(strip $(LED_MIRRORED)), yes) 42ifeq ($(strip $(LED_MIRRORED)), yes)
49 OPT_DEFS += -DLED_MIRRORED 43 OPT_DEFS += -DLED_MIRRORED
50endif \ No newline at end of file 44endif
diff --git a/keyboards/sol/keymaps/kageurufu/rules.mk b/keyboards/sol/keymaps/kageurufu/rules.mk
index bb502be00..82816f960 100644
--- a/keyboards/sol/keymaps/kageurufu/rules.mk
+++ b/keyboards/sol/keymaps/kageurufu/rules.mk
@@ -18,15 +18,12 @@ RGBLIGHT_FULL_POWER = no # Allow maximum RGB brightness. Otherwise, limited t
18UNICODE_ENABLE = no # Unicode 18UNICODE_ENABLE = no # Unicode
19SWAP_HANDS_ENABLE = no # Enable one-hand typing 19SWAP_HANDS_ENABLE = no # Enable one-hand typing
20ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90) 20ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90)
21OLED_ENABLE = no # OLED_ENABLE (+5000) 21
22OLED_DRIVER_ENABLE = no # Enable the OLED Driver (+5000)
22IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone) 23IOS_DEVICE_ENABLE = no # Limit max brightness to connect to IOS device (iPad,iPhone)
23 24
24# Do not edit past here 25# Do not edit past here
25 26
26ifeq ($(strip $(OLED_ENABLE)), yes)
27 OPT_DEFS += -DOLED_ENABLE
28endif
29
30ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes) 27ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes)
31 OPT_DEFS += -DENCODER_ENABLE_CUSTOM 28 OPT_DEFS += -DENCODER_ENABLE_CUSTOM
32 SRC += common/knob_v2.c 29 SRC += common/knob_v2.c
diff --git a/keyboards/sol/rev1/config.h b/keyboards/sol/rev1/config.h
index 1ef373f96..1d8391f64 100644
--- a/keyboards/sol/rev1/config.h
+++ b/keyboards/sol/rev1/config.h
@@ -40,12 +40,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
40// #define MASTER_RIGHT 40// #define MASTER_RIGHT
41// #define EE_HANDS 41// #define EE_HANDS
42 42
43// Helix keyboard OLED support
44// see ./rules.mk: OLED_ENABLE=yes or no
45#ifdef OLED_ENABLE
46 #define SSD1306OLED
47#endif
48
49/* Select rows configuration */ 43/* Select rows configuration */
50// Rows are 4 or 5 44// Rows are 4 or 5
51// #define HELIX_ROWS 5 see ./rules.mk 45// #define HELIX_ROWS 5 see ./rules.mk
diff --git a/keyboards/sol/rev1/rev1.c b/keyboards/sol/rev1/rev1.c
index 9d869a4af..049b5c218 100644
--- a/keyboards/sol/rev1/rev1.c
+++ b/keyboards/sol/rev1/rev1.c
@@ -1,12 +1,5 @@
1#include "sol.h" 1#include "sol.h"
2 2
3#ifdef SSD1306OLED
4void led_set_kb(uint8_t usb_led) {
5 // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
6 //led_set_user(usb_led);
7}
8#endif
9
10#ifdef RGB_MATRIX_ENABLE 3#ifdef RGB_MATRIX_ENABLE
11 const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = { 4 const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
12 // Left Hand Mapped Left to Right 5 // Left Hand Mapped Left to Right
diff --git a/keyboards/sol/rev1/split_util.h b/keyboards/sol/rev1/split_util.h
index 59b362415..442163896 100644
--- a/keyboards/sol/rev1/split_util.h
+++ b/keyboards/sol/rev1/split_util.h
@@ -12,6 +12,4 @@ void matrix_slave_scan(void);
12void split_keyboard_setup(void); 12void split_keyboard_setup(void);
13bool has_usb(void); 13bool has_usb(void);
14 14
15void matrix_master_OLED_init (void);
16
17#endif 15#endif
diff --git a/keyboards/sol/rules.mk b/keyboards/sol/rules.mk
index aa18721b6..bafdd9c52 100644
--- a/keyboards/sol/rules.mk
+++ b/keyboards/sol/rules.mk
@@ -1,6 +1,4 @@
1SRC += i2c.c \ 1SRC += serial.c
2 serial.c \
3 common/ssd1306.c
4 2
5# MCU name 3# MCU name
6#MCU = at90usb1287 4#MCU = at90usb1287
@@ -47,6 +45,9 @@ BOOTLOADER = qmk-dfu
47# Interrupt driven control endpoint task(+60) 45# Interrupt driven control endpoint task(+60)
48OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT 46OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
49 47
48# Custom local font file
49OPT_DEFS += -DOLED_FONT_H=\"common/glcdfont.c\"
50
50# Build Options 51# Build Options
51# change to "no" to disable the options, or define them in the Makefile in 52# change to "no" to disable the options, or define them in the Makefile in
52# the appropriate keymap folder that will get included automatically 53# the appropriate keymap folder that will get included automatically
diff --git a/quantum/quantum.c b/quantum/quantum.c
index a64878c72..9aa498dad 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -275,6 +275,12 @@ bool process_record_quantum(keyrecord_t *record) {
275 preprocess_tap_dance(keycode, record); 275 preprocess_tap_dance(keycode, record);
276 #endif 276 #endif
277 277
278 #if defined(OLED_DRIVER_ENABLE) && !defined(OLED_DISABLE_TIMEOUT)
279 // Wake up oled if user is using those fabulous keys!
280 if (record->event.pressed)
281 oled_on();
282 #endif
283
278 if (!( 284 if (!(
279 #if defined(KEY_LOCK_ENABLE) 285 #if defined(KEY_LOCK_ENABLE)
280 // Must run first to be able to mask key_up events. 286 // Must run first to be able to mask key_up events.
@@ -1087,6 +1093,9 @@ void matrix_init_quantum() {
1087 #ifdef OUTPUT_AUTO_ENABLE 1093 #ifdef OUTPUT_AUTO_ENABLE
1088 set_output(OUTPUT_AUTO); 1094 set_output(OUTPUT_AUTO);
1089 #endif 1095 #endif
1096 #ifdef OLED_DRIVER_ENABLE
1097 oled_init(OLED_ROTATION_0);
1098 #endif
1090 matrix_init_kb(); 1099 matrix_init_kb();
1091} 1100}
1092 1101
@@ -1123,6 +1132,10 @@ void matrix_scan_quantum() {
1123 haptic_task(); 1132 haptic_task();
1124 #endif 1133 #endif
1125 1134
1135 #ifdef OLED_DRIVER_ENABLE
1136 oled_task();
1137 #endif
1138
1126 matrix_scan_kb(); 1139 matrix_scan_kb();
1127} 1140}
1128#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN) 1141#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
diff --git a/quantum/quantum.h b/quantum/quantum.h
index e2f467125..987516ded 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -139,6 +139,10 @@ extern uint32_t default_layer_state;
139 #include "haptic.h" 139 #include "haptic.h"
140#endif 140#endif
141 141
142#ifdef OLED_DRIVER_ENABLE
143 #include "oled_driver.h"
144#endif
145
142//Function substitutions to ease GPIO manipulation 146//Function substitutions to ease GPIO manipulation
143#ifdef __AVR__ 147#ifdef __AVR__
144 #define PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + (p >> PORT_SHIFTER) + offset) 148 #define PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + (p >> PORT_SHIFTER) + offset)