]> git.donarmstrong.com Git - qmk_firmware.git/blob - drivers/qwiic/micro_oled.c
[Keymap] Jarred's Plaid keymap (#6049)
[qmk_firmware.git] / drivers / qwiic / micro_oled.c
1 /* Jim Lindblom @ SparkFun Electronics
2  * October 26, 2014
3  * https://github.com/sparkfun/Micro_OLED_Breakout/tree/master/Firmware/Arduino/libraries/SFE_MicroOLED
4  *
5  * Modified by:
6  * Emil Varughese @ Edwin Robotics Pvt. Ltd.
7  * July 27, 2015
8  * https://github.com/emil01/SparkFun_Micro_OLED_Arduino_Library/
9  *
10  * This code was heavily based around the MicroView library, written by GeekAmmo
11  * (https://github.com/geekammo/MicroView-Arduino-Library).
12  *
13  * Adapted for QMK by:
14  * Jack Humbert <jack.humb@gmail.com>
15  * October 11, 2018
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  */
30 #include "micro_oled.h"
31 #include <print.h>
32 #include <stdlib.h>
33 #include "util/font5x7.h"
34 #include "util/font8x16.h"
35 #include "string.h"
36
37 #define TOTALFONTS 2
38 const unsigned char * fonts_pointer[]= { font5x7, font8x16 };
39
40 uint8_t foreColor,drawMode,fontWidth, fontHeight, fontType, fontStartChar, fontTotalChar, cursorX, cursorY;
41 uint16_t fontMapWidth;
42
43 #define _BV(x) (1 << (x))
44 #define swap(a, b) { uint8_t t = a; a = b; b = t; }
45
46 uint8_t micro_oled_transfer_buffer[20];
47 static uint8_t micro_oled_screen_current[LCDWIDTH*LCDWIDTH/8] = { 0 };
48
49 /* LCD Memory organised in 64 horizontal pixel and 6 rows of byte
50    B  B .............B  -----
51    y  y .............y        \
52    t  t .............t         \
53    e  e .............e          \
54    0  1 .............63          \
55                                   \
56    D0 D0.............D0            \
57    D1 D1.............D1            / ROW 0
58    D2 D2.............D2           /
59    D3 D3.............D3          /
60    D4 D4.............D4         /
61    D5 D5.............D5        /
62    D6 D6.............D6       /
63    D7 D7.............D7  ----
64   */
65
66 #if LCDWIDTH == 64
67   #if LCDWIDTH == 48
68 static uint8_t micro_oled_screen_buffer[] = {
69 // QMK Logo - generated at http://www.majer.ch/lcd/adf_bitmap.php
70 //64x48 image
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00,
74 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00,
75 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x60,
79 0xF8, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF,
80 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF,
81 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFE,
82 0xFE, 0xF8, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x8C, 0x8C, 0x8C, 0x8C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
86 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
87 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
88 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8C, 0x8C, 0x8C, 0x8C,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x31, 0x31, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0xF1, 0xE3, 0xE7, 0xCF,
93 0xCF, 0xCF, 0xCF, 0x00, 0x00, 0xCF, 0xCF, 0xCF, 0xC7, 0xE7,
94 0xE3, 0xF1, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
95 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
98 0x06, 0x06, 0x1F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
99 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF,
100 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
101 0xFF, 0x7F, 0x7F, 0x1F, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
106 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
107 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00
110 };
111   #endif
112 #elif LCDWIDTH == 128
113   #if LCDHEIGHT == 32
114      static uint8_t micro_oled_screen_buffer[LCDWIDTH*LCDWIDTH/8] = {
115 //128x32 qmk image
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xFC, 0xFC, 0xE0, 0xFC, 0xFC,
119 0xE0, 0xF0, 0xFC, 0xE0, 0xE0, 0xFC, 0xE0, 0xE0, 0xFC, 0xFC,
120 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x30, 0xE0, 0x00, 0x00,
123 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00,
124 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80,
125 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00,
126 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
127 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xB2, 0xB2, 0xFF,
131 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x03, 0xFF, 0xFF, 0xFF, 0x03,
132 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x03, 0xFF, 0xFF, 0xFF,
133 0xFF, 0xB7, 0xB2, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x1F, 0x02, 0x02, 0x03, 0x01, 0x00, 0x06, 0x1F, 0x10,
136 0x10, 0x10, 0x1F, 0x06, 0x00, 0x03, 0x1E, 0x18, 0x0F, 0x01,
137 0x0F, 0x18, 0x1E, 0x01, 0x00, 0x0F, 0x1F, 0x12, 0x02, 0x12,
138 0x13, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0x12,
139 0x02, 0x12, 0x13, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x1F,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x48, 0x4D, 0x4D, 0xFF, 0xFF, 0xFF,
144 0xFF, 0xFF, 0xFE, 0xF8, 0xF9, 0xF3, 0xF3, 0xC0, 0x80, 0xF3,
145 0xF3, 0xF3, 0xF9, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED,
146 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0xFE, 0x20, 0x10, 0x10, 0xE0, 0xC0, 0x00, 0x70, 0xC0,
149 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0C,
150 0x04, 0x04, 0x04, 0x04, 0x1C, 0xF0, 0x00, 0x00, 0xFC, 0x0C,
151 0x38, 0xE0, 0x00, 0x00, 0xC0, 0x38, 0x0C, 0xFC, 0x00, 0x00,
152 0xFC, 0xFC, 0x60, 0x90, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x3F,
157 0x3F, 0x07, 0x3F, 0x3F, 0x07, 0x0F, 0x3F, 0x07, 0x07, 0x3F,
158 0x07, 0x07, 0x3F, 0x3F, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
161 0x06, 0x04, 0x04, 0x07, 0x01, 0x00, 0x00, 0x13, 0x1E, 0x03,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x04, 0x04,
163 0x04, 0x04, 0x07, 0x0D, 0x08, 0x00, 0x07, 0x00, 0x00, 0x01,
164 0x07, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x07, 0x07,
165 0x00, 0x01, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00, 0x00
168     };
169   #elif LCDHEIGHT == 64
170     static uint8_t micro_oled_screen_buffer[LCDWIDTH*LCDWIDTH/8] = {
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
179 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00,
180 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0xC0, 0xC0, 0xC0, 0xC0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFF,
194 0x7F, 0x7E, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7F, 0xFE,
195 0xFE, 0xFF, 0xFF, 0xFE, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0xFC,
196 0xFC, 0xF8, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x88, 0x88, 0x88, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
209 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
210 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
211 0xFF, 0xFF, 0xFF, 0xDD, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF,
224 0xFF, 0xFF, 0xFE, 0xF8, 0xF0, 0xF3, 0xF3, 0xE7, 0xE7, 0x00,
225 0x00, 0xE7, 0xE7, 0xF3, 0xF3, 0xF0, 0xF8, 0xFE, 0xFF, 0xFF,
226 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x1F, 0x3F,
239 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F,
240 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF,
241 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00,
255 0x80, 0x03, 0x03, 0x00, 0x00, 0x01, 0x03, 0x00, 0x80, 0x01,
256 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0xFF, 0x11, 0x11, 0x11, 0x0E, 0x00, 0x70,
266 0x88, 0x04, 0x04, 0x04, 0xF8, 0x00, 0x00, 0x3C, 0xE0, 0xC0,
267 0x38, 0x1C, 0xE0, 0x80, 0x70, 0x0C, 0x00, 0xF8, 0xAC, 0x24,
268 0x24, 0x3C, 0x30, 0x00, 0x00, 0xFC, 0x0C, 0x04, 0x00, 0xF8,
269 0xAC, 0x24, 0x24, 0x2C, 0x30, 0x00, 0x70, 0xDC, 0x04, 0x04,
270 0x88, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
271 0x8C, 0x04, 0x04, 0xF8, 0x00, 0x04, 0x3C, 0xE0, 0x80, 0xF0,
272 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x83, 0x01, 0x01,
273 0x01, 0x81, 0xFE, 0x3C, 0x00, 0x00, 0xFF, 0x03, 0x0E, 0x70,
274 0xC0, 0xE0, 0x38, 0x06, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0x18,
275 0x38, 0x66, 0xC3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
282 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
283 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
284 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01,
285 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
288 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00,
289 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
290 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
307     };
308 //TODO: generate bitmap of QMK logo here
309   #endif
310 #else
311 //catchall for custom screen szies
312     static uint8_t micro_oled_screen_buffer[LCDWIDTH*LCDWIDTH/8] = {0};
313 #endif
314
315
316
317 void micro_oled_init(void) {
318   i2c_init();
319   i2c_start(I2C_ADDRESS_SA0_1);
320
321   // Display Init sequence for 64x48 OLED module
322   send_command(DISPLAYOFF);      // 0xAE
323
324   send_command(SETDISPLAYCLOCKDIV);  // 0xD5
325   send_command(0x80);          // the suggested ratio 0x80
326
327   send_command(SETMULTIPLEX);      // 0xA8
328   send_command(LCDHEIGHT - 1);
329
330   send_command(SETDISPLAYOFFSET);    // 0xD3
331   send_command(0x00);         // no offset
332
333   send_command(SETSTARTLINE | 0x00);  // line #0
334
335   send_command(CHARGEPUMP);      // enable charge pump
336   send_command(0x14);
337
338   send_command(NORMALDISPLAY);     // 0xA6
339   send_command(DISPLAYALLONRESUME);  // 0xA4
340
341 //display at regular orientation
342   send_command(SEGREMAP | 0x1);
343   send_command(COMSCANDEC);
344
345 //rotate display 180
346 #ifdef micro_oled_rotate_180
347   send_command(SEGREMAP);
348   send_command(COMSCANINC);
349 #endif
350
351   send_command(MEMORYMODE);
352   send_command(0x10);
353
354   send_command(SETCOMPINS);      // 0xDA
355 if (LCDHEIGHT > 32) {
356   send_command(0x12);
357 } else {
358   send_command(0x02);
359 }
360   send_command(SETCONTRAST);     // 0x81
361   send_command(0x8F);
362
363   send_command(SETPRECHARGE);      // 0xd9
364   send_command(0xF1);
365
366   send_command(SETVCOMDESELECT);     // 0xDB
367   send_command(0x40);
368
369   send_command(DISPLAYON);       //--turn on oled panel
370   clear_screen();           // Erase hardware memory inside the OLED controller to avoid random data in memory.
371   send_buffer();
372 }
373
374 void send_command(uint8_t command) {
375   micro_oled_transfer_buffer[0] = I2C_COMMAND;
376   micro_oled_transfer_buffer[1] = command;
377   i2c_transmit(I2C_ADDRESS_SA0_1 << 1, micro_oled_transfer_buffer, 2, 100);
378 }
379
380 void send_data(uint8_t data) {
381   micro_oled_transfer_buffer[0] = I2C_DATA;
382   micro_oled_transfer_buffer[1] = data;
383   i2c_transmit(I2C_ADDRESS_SA0_1 << 1, micro_oled_transfer_buffer, 2, 100);
384 }
385
386 /** \brief Set SSD1306 page address.
387     Send page address command and address to the SSD1306 OLED controller.
388 */
389 void set_page_address(uint8_t address) {
390   address = (0xB0 | address);
391   send_command(address);
392 }
393
394 /** \brief Set SSD1306 column address.
395     Send column address command and address to the SSD1306 OLED controller.
396 */
397 void set_column_address(uint8_t address) {
398   send_command( ( 0x10 | (address >> 4) ) + ((128 - LCDWIDTH) >> 8) );
399   send_command( 0x0F & address );
400 }
401
402 /** \brief Clear SSD1306's memory.
403     To clear GDRAM inside the LCD controller.
404 */
405 void clear_screen(void) {
406   for (int i=0;i<8; i++) {
407     set_page_address(i);
408     set_column_address(0);
409     for (int j=0; j<0x80; j++) {
410       send_data(0);
411     }
412   }
413 }
414
415 /** \brief Clear SSD1306's memory.
416     To clear GDRAM inside the LCD controller.
417 */
418 void clear_buffer(void) {
419 //384
420   memset(micro_oled_screen_buffer, 0, LCDWIDTH*LCDWIDTH/8);
421 }
422
423 /** \brief Invert display.
424     The PIXEL_ON color of the display will turn to PIXEL_OFF and the PIXEL_OFF will turn to PIXEL_ON.
425 */
426 void invert_screen(bool invert) {
427   if (invert) {
428     send_command(INVERTDISPLAY);
429   } else {
430     send_command(NORMALDISPLAY);
431   }
432 }
433
434 /** \brief Set contrast.
435     OLED contract value from 0 to 255. Note: Contrast level is not very obvious.
436 */
437 void set_contrast(uint8_t contrast) {
438   send_command(SETCONTRAST);     // 0x81
439   send_command(contrast);
440 }
441
442 /** \brief Transfer display buffer.
443   Sends the updated buffer to the controller - the current status is checked before to save i2c exectution time
444 */
445 void send_buffer(void) {
446   uint8_t i, j;
447
448   uint8_t page_addr = 0xFF;
449   for (i = 0; i < LCDHEIGHT/8; i++) {
450     uint8_t col_addr = 0xFF;
451     for (j = 0; j < LCDWIDTH; j++) {
452       if (micro_oled_screen_buffer[i*LCDWIDTH+j] != micro_oled_screen_current[i*LCDWIDTH+j]) {
453         if (page_addr != i) {
454           set_page_address(i);
455         }
456         if (col_addr != j) {
457           set_column_address(j);
458         }
459         send_data(micro_oled_screen_buffer[i*LCDWIDTH+j]);
460         micro_oled_screen_current[i*LCDWIDTH+j] = micro_oled_screen_buffer[i*LCDWIDTH+j];
461         col_addr = j + 1;
462       }
463     }
464   }
465 }
466
467 /** \brief Draw pixel with color and mode.
468   Draw color pixel in the screen buffer's x,y position with NORM or XOR draw mode.
469 */
470 void draw_pixel(uint8_t x, uint8_t y, uint8_t color, uint8_t mode) {
471   if ((x<0) ||  (x>=LCDWIDTH) || (y<0) || (y>=LCDHEIGHT))
472     return;
473
474   if (mode == XOR) {
475     if (color == PIXEL_ON)
476       micro_oled_screen_buffer[x + (y/8)*LCDWIDTH] ^= _BV((y%8));
477   } else {
478     if (color == PIXEL_ON)
479       micro_oled_screen_buffer[x + (y/8)*LCDWIDTH] |= _BV((y%8));
480     else
481       micro_oled_screen_buffer[x + (y/8)*LCDWIDTH] &= ~_BV((y%8));
482   }
483 }
484
485 /** \brief Draw line with color and mode.
486 Draw line using color and mode from x0,y0 to x1,y1 of the screen buffer.
487 */
488 void draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color, uint8_t mode) {
489   uint8_t steep = abs(y1 - y0) > abs(x1 - x0);
490   if (steep) {
491     swap(x0, y0);
492     swap(x1, y1);
493   }
494
495   if (x0 > x1) {
496     swap(x0, x1);
497     swap(y0, y1);
498   }
499
500   uint8_t dx, dy;
501   dx = x1 - x0;
502   dy = abs(y1 - y0);
503
504   int8_t err = dx / 2;
505   int8_t ystep;
506
507   if (y0 < y1) {
508     ystep = 1;
509   } else {
510     ystep = -1;}
511
512   for (; x0<x1; x0++) {
513     if (steep) {
514       draw_pixel(y0, x0, color, mode);
515     } else {
516       draw_pixel(x0, y0, color, mode);
517     }
518     err -= dy;
519     if (err < 0) {
520       y0 += ystep;
521       err += dx;
522     }
523   }
524 }
525
526 /** \brief Draw horizontal line with color and mode.
527 Draw horizontal line using color and mode from x,y to x+width,y of the screen buffer.
528 */
529 void draw_line_hori(uint8_t x, uint8_t y, uint8_t width, uint8_t color, uint8_t mode) {
530   draw_line(x,y,x+width,y,color,mode);
531 }
532
533 /** \brief Draw vertical line.
534 Draw vertical line using current fore color and current draw mode from x,y to x,y+height of the screen buffer.
535 */
536 void draw_line_vert(uint8_t x, uint8_t y, uint8_t height, bool color, uint8_t mode) {
537   draw_line(x,y,x,y+height,color,mode);
538 }
539
540 /** \brief Draw rectangle with color and mode.
541 Draw rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
542 */
543 void draw_rect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
544   uint8_t tempHeight;
545
546   draw_line_hori(x,y, width, color, mode);
547   draw_line_hori(x,y+height-1, width, color, mode);
548
549   tempHeight=height-2;
550
551   // skip drawing vertical lines to avoid overlapping of pixel that will
552   // affect XOR plot if no pixel in between horizontal lines
553   if (tempHeight<1) return;
554
555   draw_line_vert(x,y+1, tempHeight, color, mode);
556   draw_line_vert(x+width-1, y+1, tempHeight, color, mode);
557 }
558
559 /** \brief Draw rectangle with color and mode.
560 Draw rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
561 */
562 void draw_rect_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
563   uint8_t tempHeight;
564
565   draw_line_hori(x+1,y, width-2, color, mode);
566   draw_line_hori(x+1,y+height-1, width-2, color, mode);
567
568   tempHeight=height-2;
569
570   // skip drawing vertical lines to avoid overlapping of pixel that will
571   // affect XOR plot if no pixel in between horizontal lines
572   if (tempHeight<1) return;
573
574   draw_line_vert(x,y+1, tempHeight, color, mode);
575   draw_line_vert(x+width-1, y+1, tempHeight, color, mode);
576 }
577
578 /** \brief Draw filled rectangle with color and mode.
579 Draw filled rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
580 */
581 void draw_rect_filled(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
582   // TODO - need to optimise the memory map draw so that this function will not call pixel one by one
583   for (int i=x; i<x+width;i++) {
584     draw_line_vert(i,y, height, color, mode);
585   }
586 }
587
588 /** \brief Draw filled rectangle with color and mode.
589 Draw filled rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
590 */
591 void draw_rect_filled_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
592   // TODO - need to optimise the memory map draw so that this function will not call pixel one by one
593   for (int i=x; i<x+width;i++) {
594     if (i == x || i == (x + width - 1))
595       draw_line_vert(i, y+1, height-2, color, mode);
596     else
597       draw_line_vert(i, y, height, color, mode);
598   }
599 }
600
601 /** \brief Draw character with color and mode.
602   Draw character c using color and draw mode at x,y.
603 */
604 void draw_char(uint8_t x, uint8_t y, uint8_t c, uint8_t color, uint8_t mode, uint8_t font) {
605   // TODO - New routine to take font of any height, at the moment limited to font height in multiple of 8 pixels
606
607   uint8_t rowsToDraw,row, tempC;
608   uint8_t i,j,temp;
609   uint16_t charPerBitmapRow,charColPositionOnBitmap,charRowPositionOnBitmap,charBitmapStartPosition;
610
611   if ((font>=TOTALFONTS) || (font<0))
612     return;
613
614   uint8_t fontType = font;
615   uint8_t fontWidth = pgm_read_byte(fonts_pointer[fontType]+0);
616   uint8_t fontHeight = pgm_read_byte(fonts_pointer[fontType]+1);
617   uint8_t fontStartChar = pgm_read_byte(fonts_pointer[fontType]+2);
618   uint8_t fontTotalChar = pgm_read_byte(fonts_pointer[fontType]+3);
619   uint16_t fontMapWidth = (pgm_read_byte(fonts_pointer[fontType]+4)*100)+pgm_read_byte(fonts_pointer[fontType]+5); // two bytes values into integer 16
620
621   if ((c<fontStartChar) || (c>(fontStartChar+fontTotalChar-1)))   // no bitmap for the required c
622     return;
623
624   tempC=c-fontStartChar;
625
626   // each row (in datasheet is call page) is 8 bits high, 16 bit high character will have 2 rows to be drawn
627   rowsToDraw=fontHeight/8;  // 8 is LCD's page size, see SSD1306 datasheet
628   if (rowsToDraw<=1) rowsToDraw=1;
629
630   // the following draw function can draw anywhere on the screen, but SLOW pixel by pixel draw
631   if (rowsToDraw==1) {
632     for  (i=0;i<fontWidth+1;i++) {
633       if (i==fontWidth) // this is done in a weird way because for 5x7 font, there is no margin, this code add a margin after col 5
634       temp=0;
635       else
636       temp=pgm_read_byte(fonts_pointer[fontType]+FONTHEADERSIZE+(tempC*fontWidth)+i);
637
638       for (j=0;j<8;j++) {     // 8 is the LCD's page height (see datasheet for explanation)
639         if (temp & 0x1) {
640           draw_pixel(x+i, y+j, color,mode);
641         }
642         else {
643           draw_pixel(x+i, y+j, !color,mode);
644         }
645
646         temp >>=1;
647       }
648     }
649     return;
650   }
651
652   // font height over 8 bit
653   // take character "0" ASCII 48 as example
654   charPerBitmapRow = fontMapWidth/fontWidth;  // 256/8 =32 char per row
655   charColPositionOnBitmap = tempC % charPerBitmapRow;  // =16
656   charRowPositionOnBitmap = (int)(tempC/charPerBitmapRow); // =1
657   charBitmapStartPosition = (charRowPositionOnBitmap * fontMapWidth * (fontHeight/8)) + (charColPositionOnBitmap * fontWidth) ;
658
659   // each row on LCD is 8 bit height (see datasheet for explanation)
660   for(row=0;row<rowsToDraw;row++) {
661     for (i=0; i<fontWidth;i++) {
662       temp=pgm_read_byte(fonts_pointer[fontType]+FONTHEADERSIZE+(charBitmapStartPosition+i+(row*fontMapWidth)));
663       for (j=0;j<8;j++) {     // 8 is the LCD's page height (see datasheet for explanation)
664         if (temp & 0x1) {
665           draw_pixel(x+i,y+j+(row*8), color, mode);
666         }
667         else {
668           draw_pixel(x+i,y+j+(row*8), !color, mode);
669         }
670         temp >>=1;
671       }
672     }
673   }
674
675 }
676
677 void draw_string(uint8_t x, uint8_t y, char * string, uint8_t color, uint8_t mode, uint8_t font) {
678
679   if ((font>=TOTALFONTS) || (font<0))
680     return;
681
682   uint8_t fontType = font;
683   uint8_t fontWidth = pgm_read_byte(fonts_pointer[fontType]+0);
684
685   uint8_t cur_x = x;
686   for (int i = 0; i < strlen(string); i++) {
687     draw_char(cur_x, y, string[i], color, mode, font);
688     cur_x += fontWidth + 1;
689   }
690
691 }