summaryrefslogtreecommitdiff
path: root/drivers/oled/oled_driver.h
blob: 91c376ec2731b5d57075e71854ce69f44810c994 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

#include <stdint.h>
#include <stdbool.h>

// an enumeration of the chips this driver supports
#define OLED_IC_SSD1306 0
#define OLED_IC_SH1106 1
#define OLED_IC_SH1107 2

#if defined(OLED_DISPLAY_CUSTOM)
// Expected user to implement the necessary defines
#elif defined(OLED_DISPLAY_128X64)
// Double height 128x64
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 128
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 64
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 1024 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint16_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT
#    endif

// For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
// The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8, 16, 24, 32, 40, 48, 56 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 56, 48, 40, 32, 24, 16, 8, 0 }
#    endif
// If OLED_BLOCK_TYPE is uint32_t, these tables would look like:
// #define OLED_SOURCE_MAP { 32, 40, 48, 56 }
// #define OLED_TARGET_MAP { 24, 16, 8, 0 }
// If OLED_BLOCK_TYPE is uint16_t, these tables would look like:
// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
// #define OLED_TARGET_MAP { 56, 48, 40, 32, 24, 16, 8, 0 }
// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }
// #define OLED_TARGET_MAP { 56, 120, 48, 112, 40, 104, 32, 96, 24, 88, 16, 80, 8, 72, 0, 64 }

#elif defined(OLED_DISPLAY_64X32)
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 64
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 32
#    endif
#    ifndef OLED_COLUMN_OFFSET
#        define OLED_COLUMN_OFFSET 32
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint8_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 8 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT
#    endif

#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8, 16, 24 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 24, 16, 8, 0 }
#    endif

#elif defined(OLED_DISPLAY_64X48)
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 64
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 48
#    endif
#    ifndef OLED_COLUMN_OFFSET
#        define OLED_COLUMN_OFFSET 32
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint32_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT 24
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT
#    endif

#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 8, 0 }
#    endif

#elif defined(OLED_DISPLAY_64X128)
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 64
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 128
#    endif
#    ifndef OLED_IC
#        define OLED_IC OLED_IC_SH1107
#    endif
#    ifndef OLED_COM_PIN_OFFSET
#        define OLED_COM_PIN_OFFSET 32
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint16_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT
#    endif

#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8, 16, 24, 32, 40, 48, 56 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 56, 48, 40, 32, 24, 16, 8, 0 }
#    endif

#elif defined(OLED_DISPLAY_128X128)
// Quad height 128x128
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 128
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 128
#    endif
#    ifndef OLED_IC
#        define OLED_IC OLED_IC_SH1107
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 2048 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint32_t
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 32 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 64 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_ALT
#    endif

// For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
// The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8, 16, 24, 32, 40, 48, 56 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 56, 48, 40, 32, 24, 16, 8, 0 }
#    endif
#else // defined(OLED_DISPLAY_128X64)
// Default 128x32
#    ifndef OLED_DISPLAY_WIDTH
#        define OLED_DISPLAY_WIDTH 128
#    endif
#    ifndef OLED_DISPLAY_HEIGHT
#        define OLED_DISPLAY_HEIGHT 32
#    endif
#    ifndef OLED_MATRIX_SIZE
#        define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH) // 512 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_TYPE
#        define OLED_BLOCK_TYPE uint16_t // Type to use for segmenting the oled display for smart rendering, use unsigned types only
#    endif
#    ifndef OLED_BLOCK_COUNT
#        define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8) // 16 (compile time mathed)
#    endif
#    ifndef OLED_BLOCK_SIZE
#        define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT) // 32 (compile time mathed)
#    endif
#    ifndef OLED_COM_PINS
#        define OLED_COM_PINS COM_PINS_SEQ
#    endif

// For 90 degree rotation, we map our internal matrix to oled matrix using fixed arrays
// The OLED writes to it's memory horizontally, starting top left, but our memory starts bottom left in this mode
#    ifndef OLED_SOURCE_MAP
#        define OLED_SOURCE_MAP \
            { 0, 8, 16, 24 }
#    endif
#    ifndef OLED_TARGET_MAP
#        define OLED_TARGET_MAP \
            { 24, 16, 8, 0 }
#    endif
// If OLED_BLOCK_TYPE is uint8_t, these tables would look like:
// #define OLED_SOURCE_MAP { 0, 8, 16, 24, 32, 40, 48, 56 }
// #define OLED_TARGET_MAP { 48, 32, 16, 0, 56, 40, 24, 8 }
#endif // defined(OLED_DISPLAY_CUSTOM)

#if !defined(OLED_IC)
#    define OLED_IC OLED_IC_SSD1306
#endif

// the column address corresponding to the first column in the display hardware
#if !defined(OLED_COLUMN_OFFSET)
#    define OLED_COLUMN_OFFSET 0
#endif

// Address to use for the i2c oled communication
#if !defined(OLED_DISPLAY_ADDRESS)
#    define OLED_DISPLAY_ADDRESS 0x3C
#endif

// Custom font file to use
#if !defined(OLED_FONT_H)
#    define OLED_FONT_H "glcdfont.c"
#endif
// unsigned char value of the first character in the font file
#if !defined(OLED_FONT_START)
#    define OLED_FONT_START 0
#endif
// unsigned char value of the last character in the font file
#if !defined(OLED_FONT_END)
#    define OLED_FONT_END 223
#endif
// Font render width
#if !defined(OLED_FONT_WIDTH)
#    define OLED_FONT_WIDTH 6
#endif
// Font render height
#if !defined(OLED_FONT_HEIGHT)
#    define OLED_FONT_HEIGHT 8
#endif
// Default brightness level
#if !defined(OLED_BRIGHTNESS)
#    define OLED_BRIGHTNESS 255
#endif

#if !defined(OLED_TIMEOUT)
#    if defined(OLED_DISABLE_TIMEOUT)
#        define OLED_TIMEOUT 0
#    else
#        define OLED_TIMEOUT 60000
#    endif
#endif

#if !defined(OLED_FADE_OUT_INTERVAL)
#    define OLED_FADE_OUT_INTERVAL 0x00
#endif

#if OLED_FADE_OUT_INTERVAL > 0x0F || OLED_FADE_OUT_INTERVAL < 0x00
#    error OLED_FADE_OUT_INTERVAL must be between 0x00 and 0x0F
#endif

#if !defined(OLED_I2C_TIMEOUT)
#    define OLED_I2C_TIMEOUT 100
#endif

#if !defined(OLED_UPDATE_INTERVAL) && defined(SPLIT_KEYBOARD)
#    define OLED_UPDATE_INTERVAL 50
#endif

#if !defined(OLED_UPDATE_PROCESS_LIMIT)
#    define OLED_UPDATE_PROCESS_LIMIT 1
#endif

typedef struct __attribute__((__packed__)) {
    uint8_t *current_element;
    uint16_t remaining_element_count;
} oled_buffer_reader_t;

// OLED Rotation enum values are flags
typedef enum {
    OLED_ROTATION_0   = 0,
    OLED_ROTATION_90  = 1,
    OLED_ROTATION_180 = 2,
    OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
} oled_rotation_t;

// Initialize the oled display, rotating the rendered output based on the define passed in.
// Returns true if the OLED was initialized successfully
bool oled_init(oled_rotation_t rotation);

// Send commands and data to screen
bool oled_send_cmd(const uint8_t *data, uint16_t size);
bool oled_send_cmd_P(const uint8_t *data, uint16_t size);
bool oled_send_data(const uint8_t *data, uint16_t size);
void oled_driver_init(void);

// Called at the start of oled_init, weak function overridable by the user
// rotation - the value passed into oled_init
// Return new oled_rotation_t if you want to override default rotation
oled_rotation_t oled_init_kb(oled_rotation_t rotation);
oled_rotation_t oled_init_user(oled_rotation_t rotation);

// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
void oled_clear(void);

// Renders the dirty chunks of the buffer to oled display
void oled_render(void);

// Moves cursor to character position indicated by column and line, wraps if out of bounds
// Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions
void oled_set_cursor(uint8_t col, uint8_t line);

// Advances the cursor to the next page, writing ' ' if true
// Wraps to the begining when out of bounds
void oled_advance_page(bool clearPageRemainder);

// Moves the cursor forward 1 character length
// Advance page if there is not enough room for the next character
// Wraps to the begining when out of bounds
void oled_advance_char(void);

// Writes a single character to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Main handler that writes character data to the display buffer
void oled_write_char(const char data, bool invert);

// Writes a string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
void oled_write(const char *data, bool invert);

// Writes a string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
void oled_write_ln(const char *data, bool invert);

// Pans the buffer to the right (or left by passing true) by moving contents of the buffer
// Useful for moving the screen in preparation for new drawing
void oled_pan(bool left);

// Returns a pointer to the requested start index in the buffer plus remaining
// buffer length as struct
oled_buffer_reader_t oled_read_raw(uint16_t start_index);

// Writes a string to the buffer at current cursor position
void oled_write_raw(const char *data, uint16_t size);

// Writes a single byte into the buffer at the specified index
void oled_write_raw_byte(const char data, uint16_t index);

// Sets a specific pixel on or off
// Coordinates start at top-left and go right and down for positive x and y
void oled_write_pixel(uint8_t x, uint8_t y, bool on);

#if defined(__AVR__)
// Writes a PROGMEM string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Remapped to call 'void oled_write(const char *data, bool invert);' on ARM
void oled_write_P(const char *data, bool invert);

// Writes a PROGMEM string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM
void oled_write_ln_P(const char *data, bool invert);

// Writes a PROGMEM string to the buffer at current cursor position
void oled_write_raw_P(const char *data, uint16_t size);
#else
#    define oled_write_P(data, invert) oled_write(data, invert)
#    define oled_write_ln_P(data, invert) oled_write_ln(data, invert)
#    define oled_write_raw_P(data, size) oled_write_raw(data, size)
#endif // defined(__AVR__)

// Can be used to manually turn on the screen if it is off
// Returns true if the screen was on or turns on
bool oled_on(void);

// Can be used to manually turn off the screen if it is on
// Returns true if the screen was off or turns off
bool oled_off(void);

// Returns true if the oled is currently on, false if it is
// not
bool is_oled_on(void);

// Sets the brightness of the display
uint8_t oled_set_brightness(uint8_t level);

// Gets the current brightness of the display
uint8_t oled_get_brightness(void);

// Basically it's oled_render, but with timeout management and oled_task_user calling!
void oled_task(void);

// Called at the start of oled_task, weak function overridable by the user
bool oled_task_kb(void);
bool oled_task_user(void);

// Set the specific 8 lines rows of the screen to scroll.
// 0 is the default for start, and 7 for end, which is the entire
// height of the screen.  For 128x32 screens, rows 4-7 are not used.
void oled_scroll_set_area(uint8_t start_line, uint8_t end_line);

// Sets scroll speed, 0-7, fastest to slowest. Default is three.
// Does not take effect until scrolling is either started or restarted
// the ssd1306 supports 8 speeds with the delay
// listed below between each frame of the scrolling effect
// 0=2, 1=3, 2=4, 3=5, 4=25, 5=64, 6=128, 7=256
void oled_scroll_set_speed(uint8_t speed);

// Scrolls the entire display right
// Returns true if the screen was scrolling or starts scrolling
// NOTE: display contents cannot be changed while scrolling
bool oled_scroll_right(void);

// Scrolls the entire display left
// Returns true if the screen was scrolling or starts scrolling
// NOTE: display contents cannot be changed while scrolling
bool oled_scroll_left(void);

// Turns off display scrolling
// Returns true if the screen was not scrolling or stops scrolling
bool oled_scroll_off(void);

// Returns true if the oled is currently scrolling, false if it is
// not
bool is_oled_scrolling(void);

// Inverts the display
// Returns true if the screen was or is inverted
bool oled_invert(bool invert);

// Returns the maximum number of characters that will fit on a line
uint8_t oled_max_chars(void);

// Returns the maximum number of lines that will fit on the oled
uint8_t oled_max_lines(void);