Browse Source

OLED Driver Feature

pjones-keymap
Ryan Caltabiano 2 months ago
parent
commit
0a645225b9

+ 7
- 0
common_features.mk View File

@@ -336,3 +336,10 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
336 336
     endif
337 337
     COMMON_VPATH += $(QUANTUM_PATH)/split_common
338 338
 endif
339
+
340
+ifeq ($(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
345
+endif

+ 246
- 0
docs/feature_oled_driver.md View File

@@ -0,0 +1,246 @@
1
+# OLED Driver
2
+
3
+## OLED Supported Hardware
4
+
5
+128x32 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
+
11
+To 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
+```
14
+BOOTMAGIC_ENABLE = no
15
+MOUSEKEY_ENABLE = no
16
+STENO_ENABLE = no
17
+EXTRAKEY_ENABLE = yes
18
+OLED_DRIVER_ENABLE = yes
19
+```
20
+
21
+This 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
25
+void 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
+
55
+In 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
59
+uint8_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
+
65
+void 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
+
122
+However 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
+
131
+So 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
138
+bool 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
143
+bool oled_init_user(bool flip180);
144
+
145
+// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
146
+void oled_clear(void);
147
+
148
+// Renders the dirty chunks of the buffer to OLED display
149
+void 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
153
+void 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
157
+void 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
162
+void 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
167
+void 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
171
+void 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
176
+void 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
181
+void 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
187
+void 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
191
+bool 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
195
+bool oled_off(void);
196
+
197
+// Basically it's oled_render, but with timeout management and oled_task_user calling!
198
+void oled_task(void);
199
+
200
+// Called at the start of oled_task, weak function overridable by the user
201
+void 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
206
+bool 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
211
+bool oled_scroll_left(void);
212
+
213
+// Turns off display scrolling
214
+// Returns true if the screen was not scrolling or stops scrolling
215
+bool oled_scroll_off(void);
216
+
217
+// Returns the maximum number of characters that will fit on a line
218
+uint8_t oled_max_chars(void);
219
+
220
+// Returns the maximum number of lines that will fit on the oled
221
+uint8_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`                   |

+ 3
- 3
docs/hardware_drivers.md View File

@@ -14,9 +14,9 @@ QMK is used on a lot of different hardware. While support for the most common MC
14 14
 
15 15
 Support 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
 
19
-Support 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.
19
+Support for SSD1306 based OLED displays. For more information see the [OLED Driver Feature](feature_oled_driver.md) page.
20 20
 
21 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 33
 ## IS31FL3733
34 34
 
35
-Support 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.
35
+Support 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.

+ 27
- 13
drivers/arm/i2c_master.c View File

@@ -42,6 +42,18 @@ static const I2CConfig i2cconfig = {
42 42
   0
43 43
 };
44 44
 
45
+static 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 57
 __attribute__ ((weak))
46 58
 void i2c_init(void)
47 59
 {
@@ -57,29 +69,30 @@ void i2c_init(void)
57 69
   //i2cInit(); //This is invoked by halInit() so no need to redo it.
58 70
 }
59 71
 
60
-// This is usually not needed
61
-uint8_t i2c_start(uint8_t address)
72
+i2c_status_t i2c_start(uint8_t address)
62 73
 {
63 74
   i2c_address = address;
64 75
   i2cStart(&I2C_DRIVER, &i2cconfig);
65
-  return 0;
76
+  return I2C_STATUS_SUCCESS;
66 77
 }
67 78
 
68
-uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
79
+i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout)
69 80
 {
70 81
   i2c_address = address;
71 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
 
75
-uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
87
+i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
76 88
 {
77 89
   i2c_address = address;
78 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
 
82
-uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
95
+i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout)
83 96
 {
84 97
   i2c_address = devaddr;
85 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 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
 
97
-uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
111
+i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
98 112
 {
99 113
   i2c_address = devaddr;
100 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
 
104
-uint8_t i2c_stop(void)
119
+void i2c_stop(void)
105 120
 {
106 121
   i2cStop(&I2C_DRIVER);
107
-  return 0;
108 122
 }

+ 13
- 7
drivers/arm/i2c_master.h View File

@@ -40,11 +40,17 @@
40 40
   #define I2C_DRIVER I2CD1
41 41
 #endif
42 42
 
43
+typedef 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
+
43 49
 void i2c_init(void);
44
-uint8_t i2c_start(uint8_t address);
45
-uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
46
-uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
47
-uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
48
-uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
49
-uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
50
-uint8_t i2c_stop(void);
50
+i2c_status_t i2c_start(uint8_t address);
51
+i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
52
+i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
53
+i2c_status_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
54
+i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
55
+i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
56
+void i2c_stop(void);

+ 2
- 2
drivers/avr/i2c_master.c View File

@@ -121,7 +121,7 @@ int16_t i2c_read_nack(uint16_t timeout) {
121 121
   return TWDR;
122 122
 }
123 123
 
124
-i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
124
+i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
125 125
   i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
126 126
 
127 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 155
   return (status < 0) ? status : I2C_STATUS_SUCCESS;
156 156
 }
157 157
 
158
-i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
158
+i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
159 159
   i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
160 160
   if (status >= 0) {
161 161
     status = i2c_write(regaddr, timeout);

+ 3
- 3
drivers/avr/i2c_master.h View File

@@ -22,10 +22,10 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
22 22
 i2c_status_t i2c_write(uint8_t data, uint16_t timeout);
23 23
 int16_t i2c_read_ack(uint16_t timeout);
24 24
 int16_t i2c_read_nack(uint16_t timeout);
25
-i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
25
+i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
26 26
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
27
-i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
27
+i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
28 28
 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
29 29
 void i2c_stop(void);
30 30
 
31
-#endif // I2C_MASTER_H
31
+#endif // I2C_MASTER_H

+ 240
- 0
drivers/oled/glcdfont.c View File

@@ -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
+
15
+static 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
+};

+ 528
- 0
drivers/oled/oled_driver.c View File

@@ -0,0 +1,528 @@
1
+/*
2
+Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
3
+
4
+This program is free software: you can redistribute it and/or modify
5
+it under the terms of the GNU General Public License as published by
6
+the Free Software Foundation, either version 2 of the License, or
7
+(at your option) any later version.
8
+
9
+This program is distributed in the hope that it will be useful,
10
+but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+GNU General Public License for more details.
13
+
14
+You should have received a copy of the GNU General Public License
15
+along 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
99
+uint8_t          oled_buffer[OLED_MATRIX_SIZE];
100
+uint8_t*         oled_cursor;
101
+OLED_BLOCK_TYPE  oled_dirty = 0;
102
+bool             oled_initialized = false;
103
+bool             oled_active = false;
104
+bool             oled_scrolling = false;
105
+uint8_t          oled_rotation = 0;
106
+uint8_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...
116
+static 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
131
+static 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
+
140
+bool 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))
206
+uint8_t oled_init_user(uint8_t rotation) {
207
+  return rotation;
208
+}
209
+
210
+void 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
+
216
+static 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
+
224
+static 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
+
232
+uint8_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
+
239
+static 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
+
249
+void 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
+
307
+void 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
+
318
+void 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
+
340
+void 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
359
+void 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
+
394
+void 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
+
402
+void oled_write_ln(const char *data, bool invert) {
403
+  oled_write(data, invert);
404
+  oled_advance_page(true);
405
+}
406
+
407
+#if defined(__AVR__)
408
+void 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
+
416
+void 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
+
422
+bool 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
+
438
+bool 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
+
450
+bool 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
+
465
+bool 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
+
480
+bool 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
+
492
+uint8_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
+
499
+uint8_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
+
506
+void 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))
527
+void oled_task_user(void) {
528
+}

+ 183
- 0
drivers/oled/oled_driver.h View File

@@ -0,0 +1,183 @@
1
+/*
2
+Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
3
+
4
+This program is free software: you can redistribute it and/or modify
5
+it under the terms of the GNU General Public License as published by
6
+the Free Software Foundation, either version 2 of the License, or
7
+(at your option) any later version.
8
+
9
+This program is distributed in the hope that it will be useful,
10
+but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+GNU General Public License for more details.
13
+
14
+You should have received a copy of the GNU General Public License
15
+along 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
89
+bool 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
94
+uint8_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
97
+void oled_clear(void);
98
+
99
+// Renders the dirty chunks of the buffer to oled display
100
+void 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
104
+void 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
108
+void 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
113
+void 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
118
+void 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
122
+void 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
127
+void 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
133
+void 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
139
+void 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
153
+bool 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
157
+bool oled_off(void);
158
+
159
+// Basically it's oled_render, but with timeout management and oled_task_user calling!
160
+void oled_task(void);
161
+
162
+// Called at the start of oled_task, weak function overridable by the user
163
+void 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
168
+bool 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
173
+bool oled_scroll_left(void);
174
+
175
+// Turns off display scrolling
176
+// Returns true if the screen was not scrolling or stops scrolling
177
+bool oled_scroll_off(void);
178
+
179
+// Returns the maximum number of characters that will fit on a line
180
+uint8_t oled_max_chars(void);
181
+
182
+// Returns the maximum number of lines that will fit on the oled
183
+uint8_t oled_max_lines(void);

+ 27
- 19
keyboards/cannonkeys/satisfaction75/i2c_master.c View File

@@ -29,8 +29,6 @@
29 29
 #include "quantum.h"
30 30
 #include <string.h>
31 31
 #include <hal.h>
32
-#include "chtypes.h"
33
-#include "ch.h"
34 32
 
35 33
 static uint8_t i2c_address;
36 34
 
@@ -44,6 +42,18 @@ static const I2CConfig i2cconfig = {
44 42
   0
45 43
 };
46 44
 
45
+static 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 57
 __attribute__ ((weak))
48 58
 void i2c_init(void)
49 59
 {
@@ -59,34 +69,32 @@ void i2c_init(void)
59 69
   //i2cInit(); //This is invoked by halInit() so no need to redo it.
60 70
 }
61 71
 
62
-// This is usually not needed
63
-uint8_t i2c_start(uint8_t address)
72
+i2c_status_t i2c_start(uint8_t address)
64 73
 {
65 74
   i2c_address = address;
66 75
   i2cStart(&I2C_DRIVER, &i2cconfig);
67
-  return 0;
76
+  return I2C_STATUS_SUCCESS;
68 77
 }
69 78
 
70
-uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
79
+i2c_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 81
   i2c_address = address;
75 82
   i2cStart(&I2C_DRIVER, &i2cconfig);
76 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 85
   i2cReleaseBus(&I2C_DRIVER);
79
-  return status;
86
+  return chibios_to_qmk(&status);
80 87
 }
81 88
 
82
-uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
89
+i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
83 90
 {
84 91
   i2c_address = address;
85 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
 
89
-uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
97
+i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout)
90 98
 {
91 99
   i2c_address = devaddr;
92 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 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
 
104
-uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
113
+i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
105 114
 {
106 115
   i2c_address = devaddr;
107 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.
112
-uint8_t i2c_stop(void)
121
+void i2c_stop(void)
113 122
 {
114 123
   i2cStop(&I2C_DRIVER);
115
-  return 0;
116 124
 }

+ 68
- 72
keyboards/sol/common/glcdfont.c View File

@@ -1,8 +1,4 @@
1
-// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
2
-// See gfxfont.h for newer custom bitmap font info.
3
-
4
-#ifndef FONT5X7_H
5
-#define FONT5X7_H
1
+#pragma once
6 2
 
7 3
 #ifdef __AVR__
8 4
  #include <avr/io.h>
@@ -13,7 +9,8 @@
13 9
  #define PROGMEM
14 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
 
18 15
 static const unsigned char font[] PROGMEM = {
19 16
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -144,27 +141,27 @@ static const unsigned char font[] PROGMEM = {
144 141
   0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
145 142
   0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
146 143
   0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
147
-  0x03, 0x07, 0x1F, 0x7F, 0xFF, 0xFF,
148
-  0xFE, 0xF8, 0xF0, 0xC0, 0x20, 0xF8,
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,
144
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
145
+  0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
162 146
   0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
163
-  0xBF, 0xBF, 0xDF, 0xDF, 0xEF, 0xEF,
164
-  0x00, 0x03, 0x07, 0x1F, 0x7F, 0xFF,
165
-  0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 0xC0,
166
-  0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF,
167
-  0x7F, 0x1F, 0x07, 0x03, 0x00, 0x00,
147
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
148
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149
+  0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
150
+  0x00, 0x00, 0x00, 0x00, 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 165
   0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC,
169 166
   0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00,
170 167
   0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E,
@@ -173,30 +170,30 @@ static const unsigned char font[] PROGMEM = {
173 170
   0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00,
174 171
   0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE,
175 172
   0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00,
176
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179
-  0x00, 0x00, 0x00, 0x00, 0xC1, 0xF3,
180
-  0xCF, 0xBF, 0x7F, 0xFF, 0xFF, 0xFC,
181
-  0xFB, 0xE7, 0x81, 0x00, 0x00, 0x00,
182
-  0x00, 0x80, 0xE3, 0xCF, 0x3F, 0xFF,
183
-  0xFF, 0xFF, 0xFC, 0xFB, 0xE7, 0x81,
184
-  0x00, 0x00, 0x00, 0x00, 0x81, 0xE7,
185
-  0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x00,
186
-  0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
187
-  0xFF, 0xF8, 0xF8, 0xFC, 0x7C, 0x7E,
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,
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, 0x7F, 0x80, 0x80,
177
+  0x80, 0x70, 0x0F, 0x00, 0x00, 0x80,
178
+  0x7F, 0x00, 0x00, 0x7F, 0x80, 0x80,
179
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x7F,
180
+  0x00, 0x00, 0x80, 0x80, 0x80, 0x80,
181
+  0x80, 0x80, 0x80, 0xFF, 0x00, 0x00,
182
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183
+  0x00, 0x40, 0x21, 0x33, 0x3B, 0x7B,
184
+  0xFF, 0x00, 0x7C, 0xFF, 0xFF, 0xFF,
195 185
   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
196
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
197
-  0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
198
-  0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x81,
199
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186
+  0xFF, 0xFF, 0xFF, 0xFF, 0x7C, 0x01,
187
+  0xFF, 0xDE, 0x8C, 0x04, 0x0C, 0x08,
188
+  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 197
   0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F,
201 198
   0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00,
202 199
   0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F,
@@ -205,30 +202,31 @@ static const unsigned char font[] PROGMEM = {
205 202
   0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00,
206 203
   0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F,
207 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 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 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 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 230
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 231
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 232
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -239,6 +237,4 @@ static const unsigned char font[] PROGMEM = {
239 237
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 238
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 239
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
243 240
 };
244
-#endif // FONT5X7_H

+ 0
- 329
keyboards/sol/common/ssd1306.c View File

@@ -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
32
-static uint8_t displaying;
33
-#endif
34
-static uint16_t last_flush;
35
-
36
-// Write command sequence.
37
-// Returns true on success.
38
-static 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;
57
-done:
58
-  i2c_master_stop();
59
-  return res;
60
-}
61
-
62
-// Write 2-byte command sequence.
63
-// Returns true on success
64
-static 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
73
-static 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
-
87
-static 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
-
110
-done:
111
-  i2c_master_stop();
112
-}
113
-
114
-#if DEBUG_TO_SCREEN
115
-#undef sendchar
116
-static 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
-
127
-bool 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
-
173
-done:
174
-  return success;
175
-}
176
-
177
-bool iota_gfx_off(void) {
178
-  bool success = false;
179
-
180
-  send_cmd1(DisplayOff);
181
-  success = true;
182
-
183
-done:
184
-  return success;
185
-}
186
-
187
-bool iota_gfx_on(void) {
188
-  bool success = false;
189
-
190
-  send_cmd1(DisplayOn);
191
-  success = true;
192
-
193
-done:
194
-  return success;
195
-}
196
-
197
-void 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
-
210
-void 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
-
227
-void iota_gfx_write_char(uint8_t c) {
228
-  matrix_write_char(&display, c);
229
-}
230
-
231
-void 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
-
239
-void iota_gfx_write(const char *data) {
240
-  matrix_write(&display, data);
241
-}
242
-
243
-void 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
-
254
-void iota_gfx_write_P(const char *data) {
255
-  matrix_write_P(&display, data);
256
-}
257
-
258
-void 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
-
264
-void iota_gfx_clear_screen(void) {
265
-  matrix_clear(&display);
266
-}
267
-
268
-void 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
-
303
-done:
304
-  i2c_master_stop();
305
-#if DEBUG_TO_SCREEN
306
-  --displaying;
307
-#endif
308
-}
309
-
310
-void iota_gfx_flush(void) {
311
-  matrix_render(&display);
312
-}
313
-
314
-__attribute__ ((weak))
315
-void iota_gfx_task_user(void) {
316
-}
317
-
318
-void 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

+ 0
- 92
keyboards/sol/common/ssd1306.h View File

@@ -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
-
8
-enum 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
-
63
-struct CharacterMatrix {
64
-  uint8_t display[MatrixRows][MatrixCols];
65
-  uint8_t *cursor;
66
-  bool dirty;
67
-};
68
-
69
-struct CharacterMatrix display;
70
-
71
-bool iota_gfx_init(bool rotate);
72
-void iota_gfx_task(void);
73
-bool iota_gfx_off(void);
74
-bool iota_gfx_on(void);
75
-void iota_gfx_flush(void);
76
-void iota_gfx_write_char(uint8_t c);
77
-void iota_gfx_write(const char *data);
78
-void iota_gfx_write_P(const char *data);
79
-void iota_gfx_clear_screen(void);
80
-
81
-void iota_gfx_task_user(void);
82
-
83
-void matrix_clear(struct CharacterMatrix *matrix);
84
-void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c);
85
-void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c);
86
-void matrix_write(struct CharacterMatrix *matrix, const char *data);
87
-void matrix_write_P(struct CharacterMatrix *matrix, const char *data);
88
-void matrix_render(struct CharacterMatrix *matrix);
89
-
90
-
91
-
92
-#endif

+ 0
- 162
keyboards/sol/i2c.c View File

@@ -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
-
21
-volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
-
23
-static volatile uint8_t slave_buffer_pos;
24
-static volatile bool slave_has_register_set = false;
25
-
26
-// Wait for an i2c operation to finish
27
-inline static
28
-void 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)
38
-void 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
50
-uint8_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.
72
-void 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
83
-uint8_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
96
-uint8_t i2c_master_read(int ack) {
97
-  TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
98
-
99
-  i2c_delay();
100
-  return TWDR;
101
-}
102
-
103
-void i2c_reset_state(void) {
104
-  TWCR = 0;
105
-}
106
-
107
-void 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
-
116
-ISR(TWI_vect);
117
-
118
-ISR(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

+ 0
- 49
keyboards/sol/i2c.h View File

@@ -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
-
21
-extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
22
-
23
-void i2c_master_init(void);
24
-uint8_t i2c_master_start(uint8_t address);
25
-void i2c_master_stop(void);
26
-uint8_t i2c_master_write(uint8_t data);
27
-uint8_t i2c_master_read(int);
28
-void i2c_reset_state(void);
29
-void i2c_slave_init(uint8_t address);
30
-
31
-
32
-static inline unsigned char i2c_start_read(unsigned char addr) {
33
-  return i2c_master_start((addr << 1) | I2C_READ);
34
-}
35
-
36
-static inline unsigned char i2c_start_write(unsigned char addr) {
37
-  return i2c_master_start((addr << 1) | I2C_WRITE);
38
-}
39
-
40
-// from SSD1306 scrips
41
-extern unsigned char i2c_rep_start(unsigned char addr);
42
-extern void i2c_start_wait(unsigned char addr);
43
-extern unsigned char i2c_readAck(void);
44
-extern unsigned char i2c_readNak(void);
45
-extern unsigned char i2c_read(unsigned char ack);
46
-
47
-#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();
48
-
49
-#endif

+ 0
- 2
keyboards/sol/keymaps/brianweyer/config.h View File

@@ -20,8 +20,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 20
 
21 21
 #pragma once
22 22
 
23
-#define SSD1306OLED
24
-
25 23
 
26 24
 // place overrides here
27 25
 

+ 54
- 92
keyboards/sol/keymaps/brianweyer/keymap.c View File

@@ -3,9 +3,6 @@
3 3
 #include "lufa.h"
4 4
 #include "split_util.h"
5 5
 #endif
6
-#ifdef SSD1306OLED
7
-  #include "common/ssd1306.h"
8
-#endif
9 6
 
10 7
 extern 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
 
177 174
 void matrix_init_user(void) {
178
-    #ifdef RGBLIGHT_ENABLE
179
-      RGB_current_mode = rgblight_config.mode;
180
-    #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
175
+#ifdef RGBLIGHT_ENABLE
176
+  RGB_current_mode = rgblight_config.mode;
177
+#endif
185 178
 }
186 179
 
187
-void 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
196
-#ifdef SSD1306OLED
184
+uint8_t oled_init_user(uint8_t rotation) {
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
199
-//   'default' keymap's led_test_init() is empty function, do nothing
200
-//   'led_test' keymap's led_test_init() force rgblight_mode_noeeprom(35);
201
-__attribute__ ((weak))
202
-void led_test_init(void) {}
190
+static void render_logo(void) {
191
+  static const char PROGMEM sol_logo[] = {
192
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
193
+    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
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
 
204
-void matrix_update(struct CharacterMatrix *dest,
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
-  }
196
+  oled_write_P(sol_logo, false);
210 197
 }
211 198
 
212 199
 //assign the right code to your layers for OLED display
@@ -215,77 +202,52 @@ void matrix_update(struct CharacterMatrix *dest,
215 202
 #define L_ADJ (1<<_ADJ)
216 203
 #define L_ADJ_TRI (L_ADJ|L_FN)
217 204
 
218
-static void render_logo(struct CharacterMatrix *matrix) {
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
-
230
-void render_status(struct CharacterMatrix *matrix) {
231
-
205
+static void render_status(void) {
232 206
   // Render to mode icon
233
-  static char logo[][2][3]={{{0x95,0x96,0},{0xb5,0xb6,0}},{{0x97,0x98,0},{0xb7,0xb8,0}}};
234
-  if(keymap_config.swap_lalt_lgui==false){
235
-    matrix_write(matrix, logo[0][0]);
236
-    matrix_write_P(matrix, PSTR("\n"));
237
-    matrix_write(matrix, logo[0][1]);
238
-  }else{
239
-    matrix_write(matrix, logo[1][0]);
240
-    matrix_write_P(matrix, PSTR("\n"));
241
-    matrix_write(matrix, logo[1][1]);
207
+  static const char PROGMEM mode_logo[4][4] = {
208
+    {0x95,0x96,0x0a,0},
209
+    {0xb5,0xb6,0x0a,0},
210
+    {0x97,0x98,0x0a,0},
211
+    {0xb7,0xb8,0x0a,0} };
212
+
213
+  if (keymap_config.swap_lalt_lgui != false) {
214
+    oled_write_P(mode_logo[0], false);
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 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];
246
-  snprintf(buf,sizeof(buf), "Undef-%ld", layer_state);
247
-  matrix_write_P(matrix, PSTR("\nLayer: "));
248
-    switch (layer_state) {
249
-        case L_BASE:
250
-           matrix_write_P(matrix, PSTR("Laser"));
251
-           break;
252
-        case L_FN:
253
-           matrix_write_P(matrix, PSTR("Function"));
254
-           break;
255
-        case L_ADJ:
256
-        case L_ADJ_TRI:
257
-           matrix_write_P(matrix, PSTR("Adjustment"));
258
-           break;
259
-        default:
260
-           matrix_write(matrix, buf);
261
-    }
222
+
223
+  oled_write_P(PSTR("Layer: "), false);
224
+  switch (layer_state) {
225
+    case L_BASE:
226
+      oled_write_P(PSTR("Laser     \n"), false);
227
+      break;
228
+    case L_FN:
229
+      oled_write_P(PSTR("Function  \n"), false);
230
+      break;
231
+    case L_ADJ:
232
+    case L_ADJ_TRI:
233
+      oled_write_P(PSTR("Adjustment\n"), false);
234
+      break;
235
+    default:
236
+      oled_write_P(PSTR("Undefined \n"), false);
237
+  }
262 238
 
263 239
   // Host Keyboard LED Status
264
-  char led[40];
265
-    snprintf(led, sizeof(led), "\n%s  %s  %s",
266
-            (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? "NUMLOCK" : "       ",
267
-            (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? "CAPS" : "    ",
268
-            (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) ? "SCLK" : "    ");
269
-  matrix_write(matrix, led);
240
+  uint8_t led_usb_state = host_keyboard_leds();
241
+  oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLOCK ") : PSTR("        "), false);
242
+  oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPS ") : PSTR("     "), false);
243
+  oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCLK ") : PSTR("     "), false);
270 244
 }
271 245
 
272
-
273
-void iota_gfx_task_user(void) {
274
-  struct CharacterMatrix matrix;
275
-
276
-#if DEBUG_TO_SCREEN
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);
246
+void oled_task_user(void) {
247
+  if (is_master)
248
+    render_status();
249
+  else
250
+    render_logo();
289 251
 }
290 252
 
291 253
 #endif

+ 6
- 8
keyboards/sol/keymaps/brianweyer/rules.mk View File

@@ -4,12 +4,13 @@
4 4
 #
5 5
 BOOTMAGIC_ENABLE = no       # Virtual DIP switch configuration(+1000)
6 6
 MOUSEKEY_ENABLE = no        # Mouse keys(+4700)
7
+
7 8
 EXTRAKEY_ENABLE = yes       # Audio control and System control(+450)
8
-CONSOLE_ENABLE = no        # Console for debug(+400)
9
-COMMAND_ENABLE = no        # Commands for debug and configuration
9
+CONSOLE_ENABLE = no         # Console for debug(+400)
10
+COMMAND_ENABLE = no         # Commands for debug and configuration
10 11
 NKRO_ENABLE = no            # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
11 12
 RGBLIGHT_ENABLE = yes       # Enable global lighting effects. Do not enable with RGB Matrix
12
-LED_ANIMATIONS = yes        # LED animations
13
+RGBLIGHT_ANIMATIONS = yes   # LED animations
13 14
 LED_MIRRORED = no           # Mirror LEDs across halves (enable DIP 1 on slave, and DIP 2 and 3 on master)
14 15
 RGB_MATRIX_ENABLE = no      # Enable per-key coordinate based RGB effects. Do not enable with RGBlight (+8500)
15 16
 RGB_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
17 18
 UNICODE_ENABLE = no         # Unicode
18 19
 SWAP_HANDS_ENABLE = no      # Enable one-hand typing
19 20
 ENCODER_ENABLE_CUSTOM = yes # Enable rotary encoder (+90)
20
-OLED_ENABLE = yes           # OLED_ENABLE (+5000)
21
+
22
+OLED_DRIVER_ENABLE = yes    # Enable the OLED Driver (+5000)
21 23
 IOS_DEVICE_ENABLE = no      # Limit max brightness to connect to IOS device (iPad,iPhone)
22 24
 
23 25
 # Do not edit past here
24 26
 
25
-ifeq ($(strip $(OLED_ENABLE)), yes)
26
-    OPT_DEFS += -DOLED_ENABLE
27
-endif
28
-
29 27
 ifeq ($(strip $(ENCODER_ENABLE_CUSTOM)), yes)
30 28
     OPT_DEFS += -DENCODER_ENABLE_CUSTOM
31 29
     SRC += common/knob_v2.c

+ 54
- 91
keyboards/sol/keymaps/danielhklein/keymap.c View File

@@ -3,9 +3,6 @@
3 3
 #include "lufa.h"
4 4
 #include "split_util.h"
5 5
 #endif
6
-#ifdef SSD1306OLED
7
-  #include "common/ssd1306.h"
8
-#endif
9 6
 
10 7
 extern 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
 
242 239
 void matrix_init_user(void) {
243
-    #ifdef RGBLIGHT_ENABLE
244
-      RGB_current_mode = rgblight_config.mode;
245
-    #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
240
+#ifdef RGBLIGHT_ENABLE
241
+  RGB_current_mode = rgblight_config.mode;
242
+#endif
250 243
 }
251 244
 
252 245
 
253
-//SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h
254
-#ifdef SSD1306OLED
246