aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/adafruit_ble.cpp699
-rw-r--r--drivers/bluetooth/adafruit_ble.h59
-rw-r--r--drivers/bluetooth/outputselect.c79
-rw-r--r--drivers/bluetooth/outputselect.h34
-rw-r--r--drivers/bluetooth/ringbuffer.hpp66
-rw-r--r--drivers/led/apa102.c4
-rw-r--r--drivers/ps2/ps2.h139
-rw-r--r--drivers/ps2/ps2_busywait.c187
-rw-r--r--drivers/ps2/ps2_interrupt.c340
-rw-r--r--drivers/ps2/ps2_io.h11
-rw-r--r--drivers/ps2/ps2_mouse.c270
-rw-r--r--drivers/ps2/ps2_mouse.h177
-rw-r--r--drivers/qwiic/micro_oled.c482
-rw-r--r--drivers/qwiic/micro_oled.h134
-rw-r--r--drivers/qwiic/qwiic.c31
-rw-r--r--drivers/qwiic/qwiic.h28
-rw-r--r--drivers/qwiic/qwiic.mk17
-rw-r--r--drivers/qwiic/util/font5x7.h39
-rw-r--r--drivers/qwiic/util/font8x16.h39
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h105
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/driver.mk3
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c302
-rw-r--r--drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h36
-rw-r--r--drivers/ugfx/gdisp/st7565/board_st7565_template.h96
-rw-r--r--drivers/ugfx/gdisp/st7565/driver.mk3
-rw-r--r--drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c314
-rw-r--r--drivers/ugfx/gdisp/st7565/gdisp_lld_config.h27
-rw-r--r--drivers/ugfx/gdisp/st7565/st7565.h39
-rw-r--r--drivers/usb2422.c402
-rw-r--r--drivers/usb2422.h59
30 files changed, 2524 insertions, 1697 deletions
diff --git a/drivers/bluetooth/adafruit_ble.cpp b/drivers/bluetooth/adafruit_ble.cpp
new file mode 100644
index 000000000..34a780e9a
--- /dev/null
+++ b/drivers/bluetooth/adafruit_ble.cpp
@@ -0,0 +1,699 @@
1#include "adafruit_ble.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <alloca.h>
6#include "debug.h"
7#include "timer.h"
8#include "action_util.h"
9#include "ringbuffer.hpp"
10#include <string.h>
11#include "spi_master.h"
12#include "wait.h"
13#include "analog.h"
14#include "progmem.h"
15
16// These are the pin assignments for the 32u4 boards.
17// You may define them to something else in your config.h
18// if yours is wired up differently.
19#ifndef ADAFRUIT_BLE_RST_PIN
20# define ADAFRUIT_BLE_RST_PIN D4
21#endif
22
23#ifndef ADAFRUIT_BLE_CS_PIN
24# define ADAFRUIT_BLE_CS_PIN B4
25#endif
26
27#ifndef ADAFRUIT_BLE_IRQ_PIN
28# define ADAFRUIT_BLE_IRQ_PIN E6
29#endif
30
31#ifndef ADAFRUIT_BLE_SCK_DIVISOR
32# define ADAFRUIT_BLE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
33#endif
34
35#define SAMPLE_BATTERY
36#define ConnectionUpdateInterval 1000 /* milliseconds */
37
38#ifndef BATTERY_LEVEL_PIN
39# define BATTERY_LEVEL_PIN B5
40#endif
41
42static struct {
43 bool is_connected;
44 bool initialized;
45 bool configured;
46
47#define ProbedEvents 1
48#define UsingEvents 2
49 bool event_flags;
50
51#ifdef SAMPLE_BATTERY
52 uint16_t last_battery_update;
53 uint32_t vbat;
54#endif
55 uint16_t last_connection_update;
56} state;
57
58// Commands are encoded using SDEP and sent via SPI
59// https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md
60
61#define SdepMaxPayload 16
62struct sdep_msg {
63 uint8_t type;
64 uint8_t cmd_low;
65 uint8_t cmd_high;
66 struct __attribute__((packed)) {
67 uint8_t len : 7;
68 uint8_t more : 1;
69 };
70 uint8_t payload[SdepMaxPayload];
71} __attribute__((packed));
72
73// The recv latency is relatively high, so when we're hammering keys quickly,
74// we want to avoid waiting for the responses in the matrix loop. We maintain
75// a short queue for that. Since there is quite a lot of space overhead for
76// the AT command representation wrapped up in SDEP, we queue the minimal
77// information here.
78
79enum queue_type {
80 QTKeyReport, // 1-byte modifier + 6-byte key report
81 QTConsumer, // 16-bit key code
82#ifdef MOUSE_ENABLE
83 QTMouseMove, // 4-byte mouse report
84#endif
85};
86
87struct queue_item {
88 enum queue_type queue_type;
89 uint16_t added;
90 union __attribute__((packed)) {
91 struct __attribute__((packed)) {
92 uint8_t modifier;
93 uint8_t keys[6];
94 } key;
95
96 uint16_t consumer;
97 struct __attribute__((packed)) {
98 int8_t x, y, scroll, pan;
99 uint8_t buttons;
100 } mousemove;
101 };
102};
103
104// Items that we wish to send
105static RingBuffer<queue_item, 40> send_buf;
106// Pending response; while pending, we can't send any more requests.
107// This records the time at which we sent the command for which we
108// are expecting a response.
109static RingBuffer<uint16_t, 2> resp_buf;
110
111static bool process_queue_item(struct queue_item *item, uint16_t timeout);
112
113enum sdep_type {
114 SdepCommand = 0x10,
115 SdepResponse = 0x20,
116 SdepAlert = 0x40,
117 SdepError = 0x80,
118 SdepSlaveNotReady = 0xFE, // Try again later
119 SdepSlaveOverflow = 0xFF, // You read more data than is available
120};
121
122enum ble_cmd {
123 BleInitialize = 0xBEEF,
124 BleAtWrapper = 0x0A00,
125 BleUartTx = 0x0A01,
126 BleUartRx = 0x0A02,
127};
128
129enum ble_system_event_bits {
130 BleSystemConnected = 0,
131 BleSystemDisconnected = 1,
132 BleSystemUartRx = 8,
133 BleSystemMidiRx = 10,
134};
135
136#define SdepTimeout 150 /* milliseconds */
137#define SdepShortTimeout 10 /* milliseconds */
138#define SdepBackOff 25 /* microseconds */
139#define BatteryUpdateInterval 10000 /* milliseconds */
140
141static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
142static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
143
144// Send a single SDEP packet
145static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
146 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
147 uint16_t timerStart = timer_read();
148 bool success = false;
149 bool ready = false;
150
151 do {
152 ready = spi_write(msg->type) != SdepSlaveNotReady;
153 if (ready) {
154 break;
155 }
156
157 // Release it and let it initialize
158 spi_stop();
159 wait_us(SdepBackOff);
160 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
161 } while (timer_elapsed(timerStart) < timeout);
162
163 if (ready) {
164 // Slave is ready; send the rest of the packet
165 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
166 success = true;
167 }
168
169 spi_stop();
170
171 return success;
172}
173
174static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, const uint8_t *payload, uint8_t len, bool moredata) {
175 msg->type = SdepCommand;
176 msg->cmd_low = command & 0xFF;
177 msg->cmd_high = command >> 8;
178 msg->len = len;
179 msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0;
180
181 static_assert(sizeof(*msg) == 20, "msg is correctly packed");
182
183 memcpy(msg->payload, payload, len);
184}
185
186// Read a single SDEP packet
187static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
188 bool success = false;
189 uint16_t timerStart = timer_read();
190 bool ready = false;
191
192 do {
193 ready = readPin(ADAFRUIT_BLE_IRQ_PIN);
194 if (ready) {
195 break;
196 }
197 wait_us(1);
198 } while (timer_elapsed(timerStart) < timeout);
199
200 if (ready) {
201 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
202
203 do {
204 // Read the command type, waiting for the data to be ready
205 msg->type = spi_read();
206 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
207 // Release it and let it initialize
208 spi_stop();
209 wait_us(SdepBackOff);
210 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
211 continue;
212 }
213
214 // Read the rest of the header
215 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
216
217 // and get the payload if there is any
218 if (msg->len <= SdepMaxPayload) {
219 spi_receive(msg->payload, msg->len);
220 }
221 success = true;
222 break;
223 } while (timer_elapsed(timerStart) < timeout);
224
225 spi_stop();
226 }
227 return success;
228}
229
230static void resp_buf_read_one(bool greedy) {
231 uint16_t last_send;
232 if (!resp_buf.peek(last_send)) {
233 return;
234 }
235
236 if (readPin(ADAFRUIT_BLE_IRQ_PIN)) {
237 struct sdep_msg msg;
238
239 again:
240 if (sdep_recv_pkt(&msg, SdepTimeout)) {
241 if (!msg.more) {
242 // We got it; consume this entry
243 resp_buf.get(last_send);
244 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
245 }
246
247 if (greedy && resp_buf.peek(last_send) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
248 goto again;
249 }
250 }
251
252 } else if (timer_elapsed(last_send) > SdepTimeout * 2) {
253 dprintf("waiting_for_result: timeout, resp_buf size %d\n", (int)resp_buf.size());
254
255 // Timed out: consume this entry
256 resp_buf.get(last_send);
257 }
258}
259
260static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
261 struct queue_item item;
262
263 // Don't send anything more until we get an ACK
264 if (!resp_buf.empty()) {
265 return;
266 }
267
268 if (!send_buf.peek(item)) {
269 return;
270 }
271 if (process_queue_item(&item, timeout)) {
272 // commit that peek
273 send_buf.get(item);
274 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
275 } else {
276 dprint("failed to send, will retry\n");
277 wait_ms(SdepTimeout);
278 resp_buf_read_one(true);
279 }
280}
281
282static void resp_buf_wait(const char *cmd) {
283 bool didPrint = false;
284 while (!resp_buf.empty()) {
285 if (!didPrint) {
286 dprintf("wait on buf for %s\n", cmd);
287 didPrint = true;
288 }
289 resp_buf_read_one(true);
290 }
291}
292
293static bool ble_init(void) {
294 state.initialized = false;
295 state.configured = false;
296 state.is_connected = false;
297
298 setPinInput(ADAFRUIT_BLE_IRQ_PIN);
299
300 spi_init();
301
302 // Perform a hardware reset
303 setPinOutput(ADAFRUIT_BLE_RST_PIN);
304 writePinHigh(ADAFRUIT_BLE_RST_PIN);
305 writePinLow(ADAFRUIT_BLE_RST_PIN);
306 wait_ms(10);
307 writePinHigh(ADAFRUIT_BLE_RST_PIN);
308
309 wait_ms(1000); // Give it a second to initialize
310
311 state.initialized = true;
312 return state.initialized;
313}
314
315static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }
316
317static bool read_response(char *resp, uint16_t resplen, bool verbose) {
318 char *dest = resp;
319 char *end = dest + resplen;
320
321 while (true) {
322 struct sdep_msg msg;
323
324 if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) {
325 dprint("sdep_recv_pkt failed\n");
326 return false;
327 }
328
329 if (msg.type != SdepResponse) {
330 *resp = 0;
331 return false;
332 }
333
334 uint8_t len = min(msg.len, end - dest);
335 if (len > 0) {
336 memcpy(dest, msg.payload, len);
337 dest += len;
338 }
339
340 if (!msg.more) {
341 // No more data is expected!
342 break;
343 }
344 }
345
346 // Ensure the response is NUL terminated
347 *dest = 0;
348
349 // "Parse" the result text; we want to snip off the trailing OK or ERROR line
350 // Rewind past the possible trailing CRLF so that we can strip it
351 --dest;
352 while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) {
353 *dest = 0;
354 --dest;
355 }
356
357 // Look back for start of preceeding line
358 char *last_line = strrchr(resp, '\n');
359 if (last_line) {
360 ++last_line;
361 } else {
362 last_line = resp;
363 }
364
365 bool success = false;
366 static const char kOK[] PROGMEM = "OK";
367
368 success = !strcmp_P(last_line, kOK);
369
370 if (verbose || !success) {
371 dprintf("result: %s\n", resp);
372 }
373 return success;
374}
375
376static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout) {
377 const char * end = cmd + strlen(cmd);
378 struct sdep_msg msg;
379
380 if (verbose) {
381 dprintf("ble send: %s\n", cmd);
382 }
383
384 if (resp) {
385 // They want to decode the response, so we need to flush and wait
386 // for all pending I/O to finish before we start this one, so
387 // that we don't confuse the results
388 resp_buf_wait(cmd);
389 *resp = 0;
390 }
391
392 // Fragment the command into a series of SDEP packets
393 while (end - cmd > SdepMaxPayload) {
394 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true);
395 if (!sdep_send_pkt(&msg, timeout)) {
396 return false;
397 }
398 cmd += SdepMaxPayload;
399 }
400
401 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false);
402 if (!sdep_send_pkt(&msg, timeout)) {
403 return false;
404 }
405
406 if (resp == NULL) {
407 uint16_t now = timer_read();
408 while (!resp_buf.enqueue(now)) {
409 resp_buf_read_one(false);
410 }
411 uint16_t later = timer_read();
412 if (TIMER_DIFF_16(later, now) > 0) {
413 dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now));
414 }
415 return true;
416 }
417
418 return read_response(resp, resplen, verbose);
419}
420
421bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
422 char *cmdbuf = (char *)alloca(strlen_P(cmd) + 1);
423 strcpy_P(cmdbuf, cmd);
424 return at_command(cmdbuf, resp, resplen, verbose);
425}
426
427bool adafruit_ble_is_connected(void) { return state.is_connected; }
428
429bool adafruit_ble_enable_keyboard(void) {
430 char resbuf[128];
431
432 if (!state.initialized && !ble_init()) {
433 return false;
434 }
435
436 state.configured = false;
437
438 // Disable command echo
439 static const char kEcho[] PROGMEM = "ATE=0";
440 // Make the advertised name match the keyboard
441 static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT);
442 // Turn on keyboard support
443 static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1";
444
445 // Adjust intervals to improve latency. This causes the "central"
446 // system (computer/tablet) to poll us every 10-30 ms. We can't
447 // set a smaller value than 10ms, and 30ms seems to be the natural
448 // processing time on my macbook. Keeping it constrained to that
449 // feels reasonable to type to.
450 static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,";
451
452 // Reset the device so that it picks up the above changes
453 static const char kATZ[] PROGMEM = "ATZ";
454
455 // Turn down the power level a bit
456 static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12";
457 static PGM_P const configure_commands[] PROGMEM = {
458 kEcho, kGapIntervals, kGapDevName, kHidEnOn, kPower, kATZ,
459 };
460
461 uint8_t i;
462 for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); ++i) {
463 PGM_P cmd;
464 memcpy_P(&cmd, configure_commands + i, sizeof(cmd));
465
466 if (!at_command_P(cmd, resbuf, sizeof(resbuf))) {
467 dprintf("failed BLE command: %S: %s\n", cmd, resbuf);
468 goto fail;
469 }
470 }
471
472 state.configured = true;
473
474 // Check connection status in a little while; allow the ATZ time
475 // to kick in.
476 state.last_connection_update = timer_read();
477fail:
478 return state.configured;
479}
480
481static void set_connected(bool connected) {
482 if (connected != state.is_connected) {
483 if (connected) {
484 dprint("BLE connected\n");
485 } else {
486 dprint("BLE disconnected\n");
487 }
488 state.is_connected = connected;
489
490 // TODO: if modifiers are down on the USB interface and
491 // we cut over to BLE or vice versa, they will remain stuck.
492 // This feels like a good point to do something like clearing
493 // the keyboard and/or generating a fake all keys up message.
494 // However, I've noticed that it takes a couple of seconds
495 // for macOS to to start recognizing key presses after BLE
496 // is in the connected state, so I worry that doing that
497 // here may not be good enough.
498 }
499}
500
501void adafruit_ble_task(void) {
502 char resbuf[48];
503
504 if (!state.configured && !adafruit_ble_enable_keyboard()) {
505 return;
506 }
507 resp_buf_read_one(true);
508 send_buf_send_one(SdepShortTimeout);
509
510 if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
511 // Must be an event update
512 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
513 uint32_t mask = strtoul(resbuf, NULL, 16);
514
515 if (mask & BleSystemConnected) {
516 set_connected(true);
517 } else if (mask & BleSystemDisconnected) {
518 set_connected(false);
519 }
520 }
521 }
522
523 if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) {
524 bool shouldPoll = true;
525 if (!(state.event_flags & ProbedEvents)) {
526 // Request notifications about connection status changes.
527 // This only works in SPIFRIEND firmware > 0.6.7, which is why
528 // we check for this conditionally here.
529 // Note that at the time of writing, HID reports only work correctly
530 // with Apple products on firmware version 0.6.7!
531 // https://forums.adafruit.com/viewtopic.php?f=8&t=104052
532 if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) {
533 at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf));
534 state.event_flags |= UsingEvents;
535 }
536 state.event_flags |= ProbedEvents;
537
538 // leave shouldPoll == true so that we check at least once
539 // before relying solely on events
540 } else {
541 shouldPoll = false;
542 }
543
544 static const char kGetConn[] PROGMEM = "AT+GAPGETCONN";
545 state.last_connection_update = timer_read();
546
547 if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) {
548 set_connected(atoi(resbuf));
549 }
550 }
551
552#ifdef SAMPLE_BATTERY
553 if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && resp_buf.empty()) {
554 state.last_battery_update = timer_read();
555
556 state.vbat = analogReadPin(BATTERY_LEVEL_PIN);
557 }
558#endif
559}
560
561static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
562 char cmdbuf[48];
563 char fmtbuf[64];
564
565 // Arrange to re-check connection after keys have settled
566 state.last_connection_update = timer_read();
567
568#if 1
569 if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) {
570 dprintf("send latency %dms\n", TIMER_DIFF_16(state.last_connection_update, item->added));
571 }
572#endif
573
574 switch (item->queue_type) {
575 case QTKeyReport:
576 strcpy_P(fmtbuf, PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x"));
577 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->key.modifier, item->key.keys[0], item->key.keys[1], item->key.keys[2], item->key.keys[3], item->key.keys[4], item->key.keys[5]);
578 return at_command(cmdbuf, NULL, 0, true, timeout);
579
580 case QTConsumer:
581 strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x"));
582 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer);
583 return at_command(cmdbuf, NULL, 0, true, timeout);
584
585#ifdef MOUSE_ENABLE
586 case QTMouseMove:
587 strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d"));
588 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, item->mousemove.y, item->mousemove.scroll, item->mousemove.pan);
589 if (!at_command(cmdbuf, NULL, 0, true, timeout)) {
590 return false;
591 }
592 strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON="));
593 if (item->mousemove.buttons & MOUSE_BTN1) {
594 strcat(cmdbuf, "L");
595 }
596 if (item->mousemove.buttons & MOUSE_BTN2) {
597 strcat(cmdbuf, "R");
598 }
599 if (item->mousemove.buttons & MOUSE_BTN3) {
600 strcat(cmdbuf, "M");
601 }
602 if (item->mousemove.buttons == 0) {
603 strcat(cmdbuf, "0");
604 }
605 return at_command(cmdbuf, NULL, 0, true, timeout);
606#endif
607 default:
608 return true;
609 }
610}
611
612void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
613 struct queue_item item;
614 bool didWait = false;
615
616 item.queue_type = QTKeyReport;
617 item.key.modifier = hid_modifier_mask;
618 item.added = timer_read();
619
620 while (nkeys >= 0) {
621 item.key.keys[0] = keys[0];
622 item.key.keys[1] = nkeys >= 1 ? keys[1] : 0;
623 item.key.keys[2] = nkeys >= 2 ? keys[2] : 0;
624 item.key.keys[3] = nkeys >= 3 ? keys[3] : 0;
625 item.key.keys[4] = nkeys >= 4 ? keys[4] : 0;
626 item.key.keys[5] = nkeys >= 5 ? keys[5] : 0;
627
628 if (!send_buf.enqueue(item)) {
629 if (!didWait) {
630 dprint("wait for buf space\n");
631 didWait = true;
632 }
633 send_buf_send_one();
634 continue;
635 }
636
637 if (nkeys <= 6) {
638 return;
639 }
640
641 nkeys -= 6;
642 keys += 6;
643 }
644}
645
646void adafruit_ble_send_consumer_key(uint16_t usage) {
647 struct queue_item item;
648
649 item.queue_type = QTConsumer;
650 item.consumer = usage;
651
652 while (!send_buf.enqueue(item)) {
653 send_buf_send_one();
654 }
655}
656
657#ifdef MOUSE_ENABLE
658void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
659 struct queue_item item;
660
661 item.queue_type = QTMouseMove;
662 item.mousemove.x = x;
663 item.mousemove.y = y;
664 item.mousemove.scroll = scroll;
665 item.mousemove.pan = pan;
666 item.mousemove.buttons = buttons;
667
668 while (!send_buf.enqueue(item)) {
669 send_buf_send_one();
670 }
671}
672#endif
673
674uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
675
676bool adafruit_ble_set_mode_leds(bool on) {
677 if (!state.configured) {
678 return false;
679 }
680
681 // The "mode" led is the red blinky one
682 at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0);
683
684 // Pin 19 is the blue "connected" LED; turn that off too.
685 // When turning LEDs back on, don't turn that LED on if we're
686 // not connected, as that would be confusing.
687 at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") : PSTR("AT+HWGPIO=19,0"), NULL, 0);
688 return true;
689}
690
691// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
692bool adafruit_ble_set_power_level(int8_t level) {
693 char cmd[46];
694 if (!state.configured) {
695 return false;
696 }
697 snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level);
698 return at_command(cmd, NULL, 0, false);
699}
diff --git a/drivers/bluetooth/adafruit_ble.h b/drivers/bluetooth/adafruit_ble.h
new file mode 100644
index 000000000..b43e0771d
--- /dev/null
+++ b/drivers/bluetooth/adafruit_ble.h
@@ -0,0 +1,59 @@
1/* Bluetooth Low Energy Protocol for QMK.
2 * Author: Wez Furlong, 2016
3 * Supports the Adafruit BLE board built around the nRF51822 chip.
4 */
5
6#pragma once
7
8#include <stdbool.h>
9#include <stdint.h>
10#include <string.h>
11
12#include "config_common.h"
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18/* Instruct the module to enable HID keyboard support and reset */
19extern bool adafruit_ble_enable_keyboard(void);
20
21/* Query to see if the BLE module is connected */
22extern bool adafruit_ble_query_is_connected(void);
23
24/* Returns true if we believe that the BLE module is connected.
25 * This uses our cached understanding that is maintained by
26 * calling ble_task() periodically. */
27extern bool adafruit_ble_is_connected(void);
28
29/* Call this periodically to process BLE-originated things */
30extern void adafruit_ble_task(void);
31
32/* Generates keypress events for a set of keys.
33 * The hid modifier mask specifies the state of the modifier keys for
34 * this set of keys.
35 * Also sends a key release indicator, so that the keys do not remain
36 * held down. */
37extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
38
39/* Send a consumer usage.
40 * (milliseconds) */
41extern void adafruit_ble_send_consumer_key(uint16_t usage);
42
43#ifdef MOUSE_ENABLE
44/* Send a mouse/wheel movement report.
45 * The parameters are signed and indicate positive or negative direction
46 * change. */
47extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
48#endif
49
50/* Compute battery voltage by reading an analog pin.
51 * Returns the integer number of millivolts */
52extern uint32_t adafruit_ble_read_battery_voltage(void);
53
54extern bool adafruit_ble_set_mode_leds(bool on);
55extern bool adafruit_ble_set_power_level(int8_t level);
56
57#ifdef __cplusplus
58}
59#endif
diff --git a/drivers/bluetooth/outputselect.c b/drivers/bluetooth/outputselect.c
new file mode 100644
index 000000000..f758c6528
--- /dev/null
+++ b/drivers/bluetooth/outputselect.c
@@ -0,0 +1,79 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#include "outputselect.h"
16
17#if defined(PROTOCOL_LUFA)
18# include "lufa.h"
19#endif
20
21#ifdef MODULE_ADAFRUIT_BLE
22# include "adafruit_ble.h"
23#endif
24
25uint8_t desired_output = OUTPUT_DEFAULT;
26
27/** \brief Set Output
28 *
29 * FIXME: Needs doc
30 */
31void set_output(uint8_t output) {
32 set_output_user(output);
33 desired_output = output;
34}
35
36/** \brief Set Output User
37 *
38 * FIXME: Needs doc
39 */
40__attribute__((weak)) void set_output_user(uint8_t output) {}
41
42static bool is_usb_configured(void) {
43#if defined(PROTOCOL_LUFA)
44 return USB_DeviceState == DEVICE_STATE_Configured;
45#endif
46}
47
48/** \brief Auto Detect Output
49 *
50 * FIXME: Needs doc
51 */
52uint8_t auto_detect_output(void) {
53 if (is_usb_configured()) {
54 return OUTPUT_USB;
55 }
56
57#ifdef MODULE_ADAFRUIT_BLE
58 if (adafruit_ble_is_connected()) {
59 return OUTPUT_BLUETOOTH;
60 }
61#endif
62
63#ifdef BLUETOOTH_ENABLE
64 return OUTPUT_BLUETOOTH; // should check if BT is connected here
65#endif
66
67 return OUTPUT_NONE;
68}
69
70/** \brief Where To Send
71 *
72 * FIXME: Needs doc
73 */
74uint8_t where_to_send(void) {
75 if (desired_output == OUTPUT_AUTO) {
76 return auto_detect_output();
77 }
78 return desired_output;
79}
diff --git a/drivers/bluetooth/outputselect.h b/drivers/bluetooth/outputselect.h
new file mode 100644
index 000000000..c4548e112
--- /dev/null
+++ b/drivers/bluetooth/outputselect.h
@@ -0,0 +1,34 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#pragma once
16
17#include <stdint.h>
18
19enum outputs {
20 OUTPUT_AUTO,
21
22 OUTPUT_NONE,
23 OUTPUT_USB,
24 OUTPUT_BLUETOOTH
25};
26
27#ifndef OUTPUT_DEFAULT
28# define OUTPUT_DEFAULT OUTPUT_AUTO
29#endif
30
31void set_output(uint8_t output);
32void set_output_user(uint8_t output);
33uint8_t auto_detect_output(void);
34uint8_t where_to_send(void);
diff --git a/drivers/bluetooth/ringbuffer.hpp b/drivers/bluetooth/ringbuffer.hpp
new file mode 100644
index 000000000..70a3c4881
--- /dev/null
+++ b/drivers/bluetooth/ringbuffer.hpp
@@ -0,0 +1,66 @@
1#pragma once
2// A simple ringbuffer holding Size elements of type T
3template <typename T, uint8_t Size>
4class RingBuffer {
5 protected:
6 T buf_[Size];
7 uint8_t head_{0}, tail_{0};
8 public:
9 inline uint8_t nextPosition(uint8_t position) {
10 return (position + 1) % Size;
11 }
12
13 inline uint8_t prevPosition(uint8_t position) {
14 if (position == 0) {
15 return Size - 1;
16 }
17 return position - 1;
18 }
19
20 inline bool enqueue(const T &item) {
21 static_assert(Size > 1, "RingBuffer size must be > 1");
22 uint8_t next = nextPosition(head_);
23 if (next == tail_) {
24 // Full
25 return false;
26 }
27
28 buf_[head_] = item;
29 head_ = next;
30 return true;
31 }
32
33 inline bool get(T &dest, bool commit = true) {
34 auto tail = tail_;
35 if (tail == head_) {
36 // No more data
37 return false;
38 }
39
40 dest = buf_[tail];
41 tail = nextPosition(tail);
42
43 if (commit) {
44 tail_ = tail;
45 }
46 return true;
47 }
48
49 inline bool empty() const { return head_ == tail_; }
50
51 inline uint8_t size() const {
52 int diff = head_ - tail_;
53 if (diff >= 0) {
54 return diff;
55 }
56 return Size + diff;
57 }
58
59 inline T& front() {
60 return buf_[tail_];
61 }
62
63 inline bool peek(T &item) {
64 return get(item, false);
65 }
66};
diff --git a/drivers/led/apa102.c b/drivers/led/apa102.c
index 7396dc3c5..00e7eb450 100644
--- a/drivers/led/apa102.c
+++ b/drivers/led/apa102.c
@@ -24,8 +24,8 @@
24# elif defined(PROTOCOL_CHIBIOS) 24# elif defined(PROTOCOL_CHIBIOS)
25 25
26# include "hal.h" 26# include "hal.h"
27# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) 27# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(GD32VF103)
28# define APA102_NOPS (100 / (1000000000L / (STM32_SYSCLK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns 28# define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns
29# else 29# else
30# error("APA102_NOPS configuration required") 30# error("APA102_NOPS configuration required")
31# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot 31# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot
diff --git a/drivers/ps2/ps2.h b/drivers/ps2/ps2.h
new file mode 100644
index 000000000..f12319285
--- /dev/null
+++ b/drivers/ps2/ps2.h
@@ -0,0 +1,139 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#pragma once
39
40#include <stdbool.h>
41#include "wait.h"
42#include "ps2_io.h"
43#include "print.h"
44
45/*
46 * Primitive PS/2 Library for AVR
47 *
48 * PS/2 Resources
49 * --------------
50 * [1] The PS/2 Mouse/Keyboard Protocol
51 * http://www.computer-engineering.org/ps2protocol/
52 * Concise and thorough primer of PS/2 protocol.
53 *
54 * [2] Keyboard and Auxiliary Device Controller
55 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
56 * Signal Timing and Format
57 *
58 * [3] Keyboards(101- and 102-key)
59 * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
60 * Keyboard Layout, Scan Code Set, POR, and Commands.
61 *
62 * [4] PS/2 Reference Manuals
63 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
64 * Collection of IBM Personal System/2 documents.
65 *
66 * [5] TrackPoint Engineering Specifications for version 3E
67 * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
68 */
69#define PS2_ACK 0xFA
70#define PS2_RESEND 0xFE
71#define PS2_SET_LED 0xED
72
73// TODO: error numbers
74#define PS2_ERR_NONE 0
75#define PS2_ERR_STARTBIT1 1
76#define PS2_ERR_STARTBIT2 2
77#define PS2_ERR_STARTBIT3 3
78#define PS2_ERR_PARITY 0x10
79#define PS2_ERR_NODATA 0x20
80
81#define PS2_LED_SCROLL_LOCK 0
82#define PS2_LED_NUM_LOCK 1
83#define PS2_LED_CAPS_LOCK 2
84
85extern uint8_t ps2_error;
86
87void ps2_host_init(void);
88uint8_t ps2_host_send(uint8_t data);
89uint8_t ps2_host_recv_response(void);
90uint8_t ps2_host_recv(void);
91void ps2_host_set_led(uint8_t usb_led);
92
93/*--------------------------------------------------------------------
94 * static functions
95 *------------------------------------------------------------------*/
96static inline uint16_t wait_clock_lo(uint16_t us) {
97 while (clock_in() && us) {
98 asm("");
99 wait_us(1);
100 us--;
101 }
102 return us;
103}
104static inline uint16_t wait_clock_hi(uint16_t us) {
105 while (!clock_in() && us) {
106 asm("");
107 wait_us(1);
108 us--;
109 }
110 return us;
111}
112static inline uint16_t wait_data_lo(uint16_t us) {
113 while (data_in() && us) {
114 asm("");
115 wait_us(1);
116 us--;
117 }
118 return us;
119}
120static inline uint16_t wait_data_hi(uint16_t us) {
121 while (!data_in() && us) {
122 asm("");
123 wait_us(1);
124 us--;
125 }
126 return us;
127}
128
129/* idle state that device can send */
130static inline void idle(void) {
131 clock_hi();
132 data_hi();
133}
134
135/* inhibit device to send */
136static inline void inhibit(void) {
137 clock_lo();
138 data_hi();
139}
diff --git a/drivers/ps2/ps2_busywait.c b/drivers/ps2/ps2_busywait.c
new file mode 100644
index 000000000..983194eea
--- /dev/null
+++ b/drivers/ps2/ps2_busywait.c
@@ -0,0 +1,187 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38/*
39 * PS/2 protocol busywait version
40 */
41
42#include <stdbool.h>
43#include "wait.h"
44#include "ps2.h"
45#include "ps2_io.h"
46#include "debug.h"
47
48#define WAIT(stat, us, err) \
49 do { \
50 if (!wait_##stat(us)) { \
51 ps2_error = err; \
52 goto ERROR; \
53 } \
54 } while (0)
55
56uint8_t ps2_error = PS2_ERR_NONE;
57
58void ps2_host_init(void) {
59 clock_init();
60 data_init();
61
62 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
63 wait_ms(2500);
64
65 inhibit();
66}
67
68uint8_t ps2_host_send(uint8_t data) {
69 bool parity = true;
70 ps2_error = PS2_ERR_NONE;
71
72 /* terminate a transmission if we have */
73 inhibit();
74 wait_us(100); // 100us [4]p.13, [5]p.50
75
76 /* 'Request to Send' and Start bit */
77 data_lo();
78 clock_hi();
79 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
80
81 /* Data bit */
82 for (uint8_t i = 0; i < 8; i++) {
83 wait_us(15);
84 if (data & (1 << i)) {
85 parity = !parity;
86 data_hi();
87 } else {
88 data_lo();
89 }
90 WAIT(clock_hi, 50, 2);
91 WAIT(clock_lo, 50, 3);
92 }
93
94 /* Parity bit */
95 wait_us(15);
96 if (parity) {
97 data_hi();
98 } else {
99 data_lo();
100 }
101 WAIT(clock_hi, 50, 4);
102 WAIT(clock_lo, 50, 5);
103
104 /* Stop bit */
105 wait_us(15);
106 data_hi();
107
108 /* Ack */
109 WAIT(data_lo, 50, 6);
110 WAIT(clock_lo, 50, 7);
111
112 /* wait for idle state */
113 WAIT(clock_hi, 50, 8);
114 WAIT(data_hi, 50, 9);
115
116 inhibit();
117 return ps2_host_recv_response();
118ERROR:
119 inhibit();
120 return 0;
121}
122
123/* receive data when host want else inhibit communication */
124uint8_t ps2_host_recv_response(void) {
125 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
126 // 250 * 100us(wait for start bit in ps2_host_recv)
127 uint8_t data = 0;
128 uint8_t try
129 = 250;
130 do {
131 data = ps2_host_recv();
132 } while (try --&&ps2_error);
133 return data;
134}
135
136/* called after start bit comes */
137uint8_t ps2_host_recv(void) {
138 uint8_t data = 0;
139 bool parity = true;
140 ps2_error = PS2_ERR_NONE;
141
142 /* release lines(idle state) */
143 idle();
144
145 /* start bit [1] */
146 WAIT(clock_lo, 100, 1); // TODO: this is enough?
147 WAIT(data_lo, 1, 2);
148 WAIT(clock_hi, 50, 3);
149
150 /* data [2-9] */
151 for (uint8_t i = 0; i < 8; i++) {
152 WAIT(clock_lo, 50, 4);
153 if (data_in()) {
154 parity = !parity;
155 data |= (1 << i);
156 }
157 WAIT(clock_hi, 50, 5);
158 }
159
160 /* parity [10] */
161 WAIT(clock_lo, 50, 6);
162 if (data_in() != parity) {
163 ps2_error = PS2_ERR_PARITY;
164 goto ERROR;
165 }
166 WAIT(clock_hi, 50, 7);
167
168 /* stop bit [11] */
169 WAIT(clock_lo, 50, 8);
170 WAIT(data_hi, 1, 9);
171 WAIT(clock_hi, 50, 10);
172
173 inhibit();
174 return data;
175ERROR:
176 if (ps2_error > PS2_ERR_STARTBIT3) {
177 xprintf("x%02X\n", ps2_error);
178 }
179 inhibit();
180 return 0;
181}
182
183/* send LED state to keyboard */
184void ps2_host_set_led(uint8_t led) {
185 ps2_host_send(0xED);
186 ps2_host_send(led);
187}
diff --git a/drivers/ps2/ps2_interrupt.c b/drivers/ps2/ps2_interrupt.c
new file mode 100644
index 000000000..70debd02f
--- /dev/null
+++ b/drivers/ps2/ps2_interrupt.c
@@ -0,0 +1,340 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38/*
39 * PS/2 protocol Pin interrupt version
40 */
41
42#include <stdbool.h>
43
44#if defined(__AVR__)
45# include <avr/interrupt.h>
46#elif defined(PROTOCOL_CHIBIOS) // TODO: or STM32 ?
47// chibiOS headers
48# include "ch.h"
49# include "hal.h"
50#endif
51
52#include "ps2.h"
53#include "ps2_io.h"
54#include "print.h"
55#include "wait.h"
56
57#define WAIT(stat, us, err) \
58 do { \
59 if (!wait_##stat(us)) { \
60 ps2_error = err; \
61 goto ERROR; \
62 } \
63 } while (0)
64
65uint8_t ps2_error = PS2_ERR_NONE;
66
67static inline uint8_t pbuf_dequeue(void);
68static inline void pbuf_enqueue(uint8_t data);
69static inline bool pbuf_has_data(void);
70static inline void pbuf_clear(void);
71
72#if defined(PROTOCOL_CHIBIOS)
73void ps2_interrupt_service_routine(void);
74void palCallback(void *arg) { ps2_interrupt_service_routine(); }
75
76# define PS2_INT_INIT() \
77 { palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); } \
78 while (0)
79# define PS2_INT_ON() \
80 { \
81 palEnableLineEvent(PS2_CLOCK_PIN, PAL_EVENT_MODE_FALLING_EDGE); \
82 palSetLineCallback(PS2_CLOCK_PIN, palCallback, NULL); \
83 } \
84 while (0)
85# define PS2_INT_OFF() \
86 { palDisableLineEvent(PS2_CLOCK_PIN); } \
87 while (0)
88#endif // PROTOCOL_CHIBIOS
89
90void ps2_host_init(void) {
91 idle();
92 PS2_INT_INIT();
93 PS2_INT_ON();
94 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
95 // wait_ms(2500);
96}
97
98uint8_t ps2_host_send(uint8_t data) {
99 bool parity = true;
100 ps2_error = PS2_ERR_NONE;
101
102 PS2_INT_OFF();
103
104 /* terminate a transmission if we have */
105 inhibit();
106 wait_us(100); // 100us [4]p.13, [5]p.50
107
108 /* 'Request to Send' and Start bit */
109 data_lo();
110 clock_hi();
111 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
112
113 /* Data bit[2-9] */
114 for (uint8_t i = 0; i < 8; i++) {
115 if (data & (1 << i)) {
116 parity = !parity;
117 data_hi();
118 } else {
119 data_lo();
120 }
121 WAIT(clock_hi, 50, 2);
122 WAIT(clock_lo, 50, 3);
123 }
124
125 /* Parity bit */
126 wait_us(15);
127 if (parity) {
128 data_hi();
129 } else {
130 data_lo();
131 }
132 WAIT(clock_hi, 50, 4);
133 WAIT(clock_lo, 50, 5);
134
135 /* Stop bit */
136 wait_us(15);
137 data_hi();
138
139 /* Ack */
140 WAIT(data_lo, 50, 6);
141 WAIT(clock_lo, 50, 7);
142
143 /* wait for idle state */
144 WAIT(clock_hi, 50, 8);
145 WAIT(data_hi, 50, 9);
146
147 idle();
148 PS2_INT_ON();
149 return ps2_host_recv_response();
150ERROR:
151 idle();
152 PS2_INT_ON();
153 return 0;
154}
155
156uint8_t ps2_host_recv_response(void) {
157 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
158 uint8_t retry = 25;
159 while (retry-- && !pbuf_has_data()) {
160 wait_ms(1);
161 }
162 return pbuf_dequeue();
163}
164
165/* get data received by interrupt */
166uint8_t ps2_host_recv(void) {
167 if (pbuf_has_data()) {
168 ps2_error = PS2_ERR_NONE;
169 return pbuf_dequeue();
170 } else {
171 ps2_error = PS2_ERR_NODATA;
172 return 0;
173 }
174}
175
176void ps2_interrupt_service_routine(void) {
177 static enum {
178 INIT,
179 START,
180 BIT0,
181 BIT1,
182 BIT2,
183 BIT3,
184 BIT4,
185 BIT5,
186 BIT6,
187 BIT7,
188 PARITY,
189 STOP,
190 } state = INIT;
191 static uint8_t data = 0;
192 static uint8_t parity = 1;
193
194 // TODO: abort if elapse 100us from previous interrupt
195
196 // return unless falling edge
197 if (clock_in()) {
198 goto RETURN;
199 }
200
201 state++;
202 switch (state) {
203 case START:
204 if (data_in()) goto ERROR;
205 break;
206 case BIT0:
207 case BIT1:
208 case BIT2:
209 case BIT3:
210 case BIT4:
211 case BIT5:
212 case BIT6:
213 case BIT7:
214 data >>= 1;
215 if (data_in()) {
216 data |= 0x80;
217 parity++;
218 }
219 break;
220 case PARITY:
221 if (data_in()) {
222 if (!(parity & 0x01)) goto ERROR;
223 } else {
224 if (parity & 0x01) goto ERROR;
225 }
226 break;
227 case STOP:
228 if (!data_in()) goto ERROR;
229 pbuf_enqueue(data);
230 goto DONE;
231 break;
232 default:
233 goto ERROR;
234 }
235 goto RETURN;
236ERROR:
237 ps2_error = state;
238DONE:
239 state = INIT;
240 data = 0;
241 parity = 1;
242RETURN:
243 return;
244}
245
246#if defined(__AVR__)
247ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); }
248#endif
249
250/* send LED state to keyboard */
251void ps2_host_set_led(uint8_t led) {
252 ps2_host_send(0xED);
253 ps2_host_send(led);
254}
255
256/*--------------------------------------------------------------------
257 * Ring buffer to store scan codes from keyboard
258 *------------------------------------------------------------------*/
259#define PBUF_SIZE 32
260static uint8_t pbuf[PBUF_SIZE];
261static uint8_t pbuf_head = 0;
262static uint8_t pbuf_tail = 0;
263static inline void pbuf_enqueue(uint8_t data) {
264#if defined(__AVR__)
265 uint8_t sreg = SREG;
266 cli();
267#elif defined(PROTOCOL_CHIBIOS)
268 chSysLockFromISR();
269#endif
270
271 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
272 if (next != pbuf_tail) {
273 pbuf[pbuf_head] = data;
274 pbuf_head = next;
275 } else {
276 print("pbuf: full\n");
277 }
278
279#if defined(__AVR__)
280 SREG = sreg;
281#elif defined(PROTOCOL_CHIBIOS)
282 chSysUnlockFromISR();
283#endif
284}
285static inline uint8_t pbuf_dequeue(void) {
286 uint8_t val = 0;
287
288#if defined(__AVR__)
289 uint8_t sreg = SREG;
290 cli();
291#elif defined(PROTOCOL_CHIBIOS)
292 chSysLock();
293#endif
294
295 if (pbuf_head != pbuf_tail) {
296 val = pbuf[pbuf_tail];
297 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
298 }
299
300#if defined(__AVR__)
301 SREG = sreg;
302#elif defined(PROTOCOL_CHIBIOS)
303 chSysUnlock();
304#endif
305
306 return val;
307}
308static inline bool pbuf_has_data(void) {
309#if defined(__AVR__)
310 uint8_t sreg = SREG;
311 cli();
312#elif defined(PROTOCOL_CHIBIOS)
313 chSysLock();
314#endif
315
316 bool has_data = (pbuf_head != pbuf_tail);
317
318#if defined(__AVR__)
319 SREG = sreg;
320#elif defined(PROTOCOL_CHIBIOS)
321 chSysUnlock();
322#endif
323 return has_data;
324}
325static inline void pbuf_clear(void) {
326#if defined(__AVR__)
327 uint8_t sreg = SREG;
328 cli();
329#elif defined(PROTOCOL_CHIBIOS)
330 chSysLock();
331#endif
332
333 pbuf_head = pbuf_tail = 0;
334
335#if defined(__AVR__)
336 SREG = sreg;
337#elif defined(PROTOCOL_CHIBIOS)
338 chSysUnlock();
339#endif
340}
diff --git a/drivers/ps2/ps2_io.h b/drivers/ps2/ps2_io.h
new file mode 100644
index 000000000..de93cb7a3
--- /dev/null
+++ b/drivers/ps2/ps2_io.h
@@ -0,0 +1,11 @@
1#pragma once
2
3void clock_init(void);
4void clock_lo(void);
5void clock_hi(void);
6bool clock_in(void);
7
8void data_init(void);
9void data_lo(void);
10void data_hi(void);
11bool data_in(void);
diff --git a/drivers/ps2/ps2_mouse.c b/drivers/ps2/ps2_mouse.c
new file mode 100644
index 000000000..8a6668b41
--- /dev/null
+++ b/drivers/ps2/ps2_mouse.c
@@ -0,0 +1,270 @@
1/*
2Copyright 2011,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <stdbool.h>
19#include "ps2_mouse.h"
20#include "wait.h"
21#include "gpio.h"
22#include "host.h"
23#include "timer.h"
24#include "print.h"
25#include "report.h"
26#include "debug.h"
27#include "ps2.h"
28
29/* ============================= MACROS ============================ */
30
31static report_mouse_t mouse_report = {};
32
33static inline void ps2_mouse_print_report(report_mouse_t *mouse_report);
34static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report);
35static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report);
36static inline void ps2_mouse_enable_scrolling(void);
37static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report);
38
39/* ============================= IMPLEMENTATION ============================ */
40
41/* supports only 3 button mouse at this time */
42void ps2_mouse_init(void) {
43 ps2_host_init();
44
45 wait_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up
46
47 PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset");
48
49 PS2_MOUSE_RECEIVE("ps2_mouse_init: read BAT");
50 PS2_MOUSE_RECEIVE("ps2_mouse_init: read DevID");
51
52#ifdef PS2_MOUSE_USE_REMOTE_MODE
53 ps2_mouse_set_remote_mode();
54#else
55 ps2_mouse_enable_data_reporting();
56#endif
57
58#ifdef PS2_MOUSE_ENABLE_SCROLLING
59 ps2_mouse_enable_scrolling();
60#endif
61
62#ifdef PS2_MOUSE_USE_2_1_SCALING
63 ps2_mouse_set_scaling_2_1();
64#endif
65
66 ps2_mouse_init_user();
67}
68
69__attribute__((weak)) void ps2_mouse_init_user(void) {}
70
71__attribute__((weak)) void ps2_mouse_moved_user(report_mouse_t *mouse_report) {}
72
73void ps2_mouse_task(void) {
74 static uint8_t buttons_prev = 0;
75 extern int tp_buttons;
76
77 /* receives packet from mouse */
78 uint8_t rcv;
79 rcv = ps2_host_send(PS2_MOUSE_READ_DATA);
80 if (rcv == PS2_ACK) {
81 mouse_report.buttons = ps2_host_recv_response() | tp_buttons;
82 mouse_report.x = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER;
83 mouse_report.y = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER;
84#ifdef PS2_MOUSE_ENABLE_SCROLLING
85 mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER;
86#endif
87 } else {
88 if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n");
89 return;
90 }
91
92 /* if mouse moves or buttons state changes */
93 if (mouse_report.x || mouse_report.y || mouse_report.v || ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) {
94#ifdef PS2_MOUSE_DEBUG_RAW
95 // Used to debug raw ps2 bytes from mouse
96 ps2_mouse_print_report(&mouse_report);
97#endif
98 buttons_prev = mouse_report.buttons;
99 ps2_mouse_convert_report_to_hid(&mouse_report);
100#if PS2_MOUSE_SCROLL_BTN_MASK
101 ps2_mouse_scroll_button_task(&mouse_report);
102#endif
103 if (mouse_report.x || mouse_report.y || mouse_report.v) {
104 ps2_mouse_moved_user(&mouse_report);
105 }
106#ifdef PS2_MOUSE_DEBUG_HID
107 // Used to debug the bytes sent to the host
108 ps2_mouse_print_report(&mouse_report);
109#endif
110 host_mouse_send(&mouse_report);
111 }
112
113 ps2_mouse_clear_report(&mouse_report);
114}
115
116void ps2_mouse_disable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_DISABLE_DATA_REPORTING, "ps2 mouse disable data reporting"); }
117
118void ps2_mouse_enable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_ENABLE_DATA_REPORTING, "ps2 mouse enable data reporting"); }
119
120void ps2_mouse_set_remote_mode(void) {
121 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_REMOTE_MODE, "ps2 mouse set remote mode");
122 ps2_mouse_mode = PS2_MOUSE_REMOTE_MODE;
123}
124
125void ps2_mouse_set_stream_mode(void) {
126 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_STREAM_MODE, "ps2 mouse set stream mode");
127 ps2_mouse_mode = PS2_MOUSE_STREAM_MODE;
128}
129
130void ps2_mouse_set_scaling_2_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_2_1, "ps2 mouse set scaling 2:1"); }
131
132void ps2_mouse_set_scaling_1_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_1_1, "ps2 mouse set scaling 1:1"); }
133
134void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution) { PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_RESOLUTION, resolution, "ps2 mouse set resolution"); }
135
136void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate) { PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_SAMPLE_RATE, sample_rate, "ps2 mouse set sample rate"); }
137
138/* ============================= HELPERS ============================ */
139
140#define X_IS_NEG (mouse_report->buttons & (1 << PS2_MOUSE_X_SIGN))
141#define Y_IS_NEG (mouse_report->buttons & (1 << PS2_MOUSE_Y_SIGN))
142#define X_IS_OVF (mouse_report->buttons & (1 << PS2_MOUSE_X_OVFLW))
143#define Y_IS_OVF (mouse_report->buttons & (1 << PS2_MOUSE_Y_OVFLW))
144static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report) {
145 // PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value.
146 // bit: 8 7 ... 0
147 // sign \8-bit/
148 //
149 // Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used.
150 //
151 // This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit.
152 mouse_report->x = X_IS_NEG ? ((!X_IS_OVF && -127 <= mouse_report->x && mouse_report->x <= -1) ? mouse_report->x : -127) : ((!X_IS_OVF && 0 <= mouse_report->x && mouse_report->x <= 127) ? mouse_report->x : 127);
153 mouse_report->y = Y_IS_NEG ? ((!Y_IS_OVF && -127 <= mouse_report->y && mouse_report->y <= -1) ? mouse_report->y : -127) : ((!Y_IS_OVF && 0 <= mouse_report->y && mouse_report->y <= 127) ? mouse_report->y : 127);
154
155#ifdef PS2_MOUSE_INVERT_BUTTONS
156 // swap left & right buttons
157 uint8_t needs_left = mouse_report->buttons & PS2_MOUSE_BTN_RIGHT;
158 uint8_t needs_right = mouse_report->buttons & PS2_MOUSE_BTN_LEFT;
159 mouse_report->buttons = (mouse_report->buttons & ~(PS2_MOUSE_BTN_MASK)) | (needs_left ? PS2_MOUSE_BTN_LEFT : 0) | (needs_right ? PS2_MOUSE_BTN_RIGHT : 0);
160#else
161 // remove sign and overflow flags
162 mouse_report->buttons &= PS2_MOUSE_BTN_MASK;
163#endif
164
165#ifdef PS2_MOUSE_INVERT_X
166 mouse_report->x = -mouse_report->x;
167#endif
168#ifndef PS2_MOUSE_INVERT_Y // NOTE if not!
169 // invert coordinate of y to conform to USB HID mouse
170 mouse_report->y = -mouse_report->y;
171#endif
172
173#ifdef PS2_MOUSE_ROTATE
174 int8_t x = mouse_report->x;
175 int8_t y = mouse_report->y;
176# if PS2_MOUSE_ROTATE == 90
177 mouse_report->x = y;
178 mouse_report->y = -x;
179# elif PS2_MOUSE_ROTATE == 180
180 mouse_report->x = -x;
181 mouse_report->y = -y;
182# elif PS2_MOUSE_ROTATE == 270
183 mouse_report->x = -y;
184 mouse_report->y = x;
185# endif
186#endif
187}
188
189static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report) {
190 mouse_report->x = 0;
191 mouse_report->y = 0;
192 mouse_report->v = 0;
193 mouse_report->h = 0;
194 mouse_report->buttons = 0;
195}
196
197static inline void ps2_mouse_print_report(report_mouse_t *mouse_report) {
198 if (!debug_mouse) return;
199 print("ps2_mouse: [");
200 print_hex8(mouse_report->buttons);
201 print("|");
202 print_hex8((uint8_t)mouse_report->x);
203 print(" ");
204 print_hex8((uint8_t)mouse_report->y);
205 print(" ");
206 print_hex8((uint8_t)mouse_report->v);
207 print(" ");
208 print_hex8((uint8_t)mouse_report->h);
209 print("]\n");
210}
211
212static inline void ps2_mouse_enable_scrolling(void) {
213 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Initiaing scroll wheel enable: Set sample rate");
214 PS2_MOUSE_SEND(200, "200");
215 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate");
216 PS2_MOUSE_SEND(100, "100");
217 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate");
218 PS2_MOUSE_SEND(80, "80");
219 PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel");
220 wait_ms(20);
221}
222
223#define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK)
224#define RELEASE_SCROLL_BUTTONS mouse_report->buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK)
225static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) {
226 static enum {
227 SCROLL_NONE,
228 SCROLL_BTN,
229 SCROLL_SENT,
230 } scroll_state = SCROLL_NONE;
231 static uint16_t scroll_button_time = 0;
232
233 if (PS2_MOUSE_SCROLL_BTN_MASK == (mouse_report->buttons & (PS2_MOUSE_SCROLL_BTN_MASK))) {
234 // All scroll buttons are pressed
235
236 if (scroll_state == SCROLL_NONE) {
237 scroll_button_time = timer_read();
238 scroll_state = SCROLL_BTN;
239 }
240
241 // If the mouse has moved, update the report to scroll instead of move the mouse
242 if (mouse_report->x || mouse_report->y) {
243 scroll_state = SCROLL_SENT;
244 mouse_report->v = -mouse_report->y / (PS2_MOUSE_SCROLL_DIVISOR_V);
245 mouse_report->h = mouse_report->x / (PS2_MOUSE_SCROLL_DIVISOR_H);
246 mouse_report->x = 0;
247 mouse_report->y = 0;
248#ifdef PS2_MOUSE_INVERT_H
249 mouse_report->h = -mouse_report->h;
250#endif
251#ifdef PS2_MOUSE_INVERT_V
252 mouse_report->v = -mouse_report->v;
253#endif
254 }
255 } else if (0 == (PS2_MOUSE_SCROLL_BTN_MASK & mouse_report->buttons)) {
256 // None of the scroll buttons are pressed
257
258#if PS2_MOUSE_SCROLL_BTN_SEND
259 if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) {
260 PRESS_SCROLL_BUTTONS;
261 host_mouse_send(mouse_report);
262 wait_ms(100);
263 RELEASE_SCROLL_BUTTONS;
264 }
265#endif
266 scroll_state = SCROLL_NONE;
267 }
268
269 RELEASE_SCROLL_BUTTONS;
270}
diff --git a/drivers/ps2/ps2_mouse.h b/drivers/ps2/ps2_mouse.h
new file mode 100644
index 000000000..c97c6c893
--- /dev/null
+++ b/drivers/ps2/ps2_mouse.h
@@ -0,0 +1,177 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdbool.h>
21#include "debug.h"
22#include "report.h"
23
24#define PS2_MOUSE_SEND(command, message) \
25 do { \
26 __attribute__((unused)) uint8_t rcv = ps2_host_send(command); \
27 if (debug_mouse) { \
28 print((message)); \
29 xprintf(" command: %X, result: %X, error: %X \n", command, rcv, ps2_error); \
30 } \
31 } while (0)
32
33#define PS2_MOUSE_SEND_SAFE(command, message) \
34 do { \
35 if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \
36 ps2_mouse_disable_data_reporting(); \
37 } \
38 PS2_MOUSE_SEND(command, message); \
39 if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \
40 ps2_mouse_enable_data_reporting(); \
41 } \
42 } while (0)
43
44#define PS2_MOUSE_SET_SAFE(command, value, message) \
45 do { \
46 if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \
47 ps2_mouse_disable_data_reporting(); \
48 } \
49 PS2_MOUSE_SEND(command, message); \
50 PS2_MOUSE_SEND(value, "Sending value"); \
51 if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \
52 ps2_mouse_enable_data_reporting(); \
53 } \
54 } while (0)
55
56#define PS2_MOUSE_RECEIVE(message) \
57 do { \
58 __attribute__((unused)) uint8_t rcv = ps2_host_recv_response(); \
59 if (debug_mouse) { \
60 print((message)); \
61 xprintf(" result: %X, error: %X \n", rcv, ps2_error); \
62 } \
63 } while (0)
64
65__attribute__((unused)) static enum ps2_mouse_mode_e {
66 PS2_MOUSE_STREAM_MODE,
67 PS2_MOUSE_REMOTE_MODE,
68} ps2_mouse_mode = PS2_MOUSE_STREAM_MODE;
69
70/*
71 * Data format:
72 * byte|7 6 5 4 3 2 1 0
73 * ----+----------------------------------------------------------------
74 * 0|[Yovflw][Xovflw][Ysign ][Xsign ][ 1 ][Middle][Right ][Left ]
75 * 1|[ X movement(0-255) ]
76 * 2|[ Y movement(0-255) ]
77 */
78#define PS2_MOUSE_BTN_MASK 0x07
79#define PS2_MOUSE_BTN_LEFT 0
80#define PS2_MOUSE_BTN_RIGHT 1
81#define PS2_MOUSE_BTN_MIDDLE 2
82#define PS2_MOUSE_X_SIGN 4
83#define PS2_MOUSE_Y_SIGN 5
84#define PS2_MOUSE_X_OVFLW 6
85#define PS2_MOUSE_Y_OVFLW 7
86
87/* mouse button to start scrolling; set 0 to disable scroll */
88#ifndef PS2_MOUSE_SCROLL_BTN_MASK
89# define PS2_MOUSE_SCROLL_BTN_MASK (1 << PS2_MOUSE_BTN_MIDDLE)
90#endif
91/* send button event when button is released within this value(ms); set 0 to disable */
92#ifndef PS2_MOUSE_SCROLL_BTN_SEND
93# define PS2_MOUSE_SCROLL_BTN_SEND 300
94#endif
95/* divide virtical and horizontal mouse move by this to convert to scroll move */
96#ifndef PS2_MOUSE_SCROLL_DIVISOR_V
97# define PS2_MOUSE_SCROLL_DIVISOR_V 2
98#endif
99#ifndef PS2_MOUSE_SCROLL_DIVISOR_H
100# define PS2_MOUSE_SCROLL_DIVISOR_H 2
101#endif
102/* multiply reported mouse values by these */
103#ifndef PS2_MOUSE_X_MULTIPLIER
104# define PS2_MOUSE_X_MULTIPLIER 1
105#endif
106#ifndef PS2_MOUSE_Y_MULTIPLIER
107# define PS2_MOUSE_Y_MULTIPLIER 1
108#endif
109#ifndef PS2_MOUSE_V_MULTIPLIER
110# define PS2_MOUSE_V_MULTIPLIER 1
111#endif
112/* For some mice this will need to be 0x0F */
113#ifndef PS2_MOUSE_SCROLL_MASK
114# define PS2_MOUSE_SCROLL_MASK 0xFF
115#endif
116#ifndef PS2_MOUSE_INIT_DELAY
117# define PS2_MOUSE_INIT_DELAY 1000
118#endif
119
120enum ps2_mouse_command_e {
121 PS2_MOUSE_RESET = 0xFF,
122 PS2_MOUSE_RESEND = 0xFE,
123 PS2_MOSUE_SET_DEFAULTS = 0xF6,
124 PS2_MOUSE_DISABLE_DATA_REPORTING = 0xF5,
125 PS2_MOUSE_ENABLE_DATA_REPORTING = 0xF4,
126 PS2_MOUSE_SET_SAMPLE_RATE = 0xF3,
127 PS2_MOUSE_GET_DEVICE_ID = 0xF2,
128 PS2_MOUSE_SET_REMOTE_MODE = 0xF0,
129 PS2_MOUSE_SET_WRAP_MODE = 0xEC,
130 PS2_MOUSE_READ_DATA = 0xEB,
131 PS2_MOUSE_SET_STREAM_MODE = 0xEA,
132 PS2_MOUSE_STATUS_REQUEST = 0xE9,
133 PS2_MOUSE_SET_RESOLUTION = 0xE8,
134 PS2_MOUSE_SET_SCALING_2_1 = 0xE7,
135 PS2_MOUSE_SET_SCALING_1_1 = 0xE6,
136};
137
138typedef enum ps2_mouse_resolution_e {
139 PS2_MOUSE_1_COUNT_MM,
140 PS2_MOUSE_2_COUNT_MM,
141 PS2_MOUSE_4_COUNT_MM,
142 PS2_MOUSE_8_COUNT_MM,
143} ps2_mouse_resolution_t;
144
145typedef enum ps2_mouse_sample_rate_e {
146 PS2_MOUSE_10_SAMPLES_SEC = 10,
147 PS2_MOUSE_20_SAMPLES_SEC = 20,
148 PS2_MOUSE_40_SAMPLES_SEC = 40,
149 PS2_MOUSE_60_SAMPLES_SEC = 60,
150 PS2_MOUSE_80_SAMPLES_SEC = 80,
151 PS2_MOUSE_100_SAMPLES_SEC = 100,
152 PS2_MOUSE_200_SAMPLES_SEC = 200,
153} ps2_mouse_sample_rate_t;
154
155void ps2_mouse_init(void);
156
157void ps2_mouse_init_user(void);
158
159void ps2_mouse_task(void);
160
161void ps2_mouse_disable_data_reporting(void);
162
163void ps2_mouse_enable_data_reporting(void);
164
165void ps2_mouse_set_remote_mode(void);
166
167void ps2_mouse_set_stream_mode(void);
168
169void ps2_mouse_set_scaling_2_1(void);
170
171void ps2_mouse_set_scaling_1_1(void);
172
173void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution);
174
175void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate);
176
177void ps2_mouse_moved_user(report_mouse_t *mouse_report);
diff --git a/drivers/qwiic/micro_oled.c b/drivers/qwiic/micro_oled.c
deleted file mode 100644
index 8dfff6968..000000000
--- a/drivers/qwiic/micro_oled.c
+++ /dev/null
@@ -1,482 +0,0 @@
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
38const unsigned char* fonts_pointer[] = {font5x7, font8x16};
39
40uint8_t foreColor, drawMode, fontWidth, fontHeight, fontType, fontStartChar, fontTotalChar, cursorX, cursorY;
41uint16_t fontMapWidth;
42
43#ifndef _BV
44# define _BV(x) (1 << (x))
45#endif
46
47#define swap(a, b) \
48 { \
49 uint8_t t = a; \
50 a = b; \
51 b = t; \
52 }
53
54uint8_t micro_oled_transfer_buffer[20];
55static uint8_t micro_oled_screen_current[LCDWIDTH * LCDHEIGHT / 8] = {0};
56
57/* LCD Memory organised in 64 horizontal pixel and 6 rows of byte
58 B B .............B -----
59 y y .............y \
60 t t .............t \
61 e e .............e \
62 0 1 .............63 \
63 \
64 D0 D0.............D0 \
65 D1 D1.............D1 / ROW 0
66 D2 D2.............D2 /
67 D3 D3.............D3 /
68 D4 D4.............D4 /
69 D5 D5.............D5 /
70 D6 D6.............D6 /
71 D7 D7.............D7 ----
72 */
73#ifdef NO_LCD_SPLASH
74// do not initialize with a splash screen
75static uint8_t micro_oled_screen_buffer[LCDWIDTH * LCDHEIGHT / 8] = {0};
76#else
77# if LCDWIDTH == 64
78# if LCDHEIGHT == 48
79static uint8_t micro_oled_screen_buffer[] = {
80 // QMK Logo - generated at http://www.majer.ch/lcd/adf_bitmap.php
81 // 64x48 image
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0xF8, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xF8, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x8C, 0x8C, 0x8C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8C, 0x8C, 0x8C, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x31, 0x31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0xF1, 0xE3, 0xE7, 0xCF, 0xCF, 0xCF, 0xCF, 0x00, 0x00, 0xCF, 0xCF, 0xCF, 0xC7, 0xE7, 0xE3, 0xF1, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x31, 0x31, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x1F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
85# endif
86# elif LCDWIDTH == 128
87# if LCDHEIGHT == 32
88static uint8_t micro_oled_screen_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
89 // 128x32 qmk image
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xFC, 0xFC, 0xE0, 0xFC, 0xFC, 0xE0, 0xF0, 0xFC, 0xE0, 0xE0, 0xFC, 0xE0, 0xE0, 0xFC, 0xFC, 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x30, 0xE0, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xB2, 0xB2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB2, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x02, 0x02, 0x03, 0x01, 0x00, 0x06, 0x1F, 0x10, 0x10, 0x10, 0x1F, 0x06, 0x00, 0x03, 0x1E, 0x18, 0x0F, 0x01, 0x0F, 0x18, 0x1E, 0x01, 0x00, 0x0F, 0x1F, 0x12, 0x02, 0x12, 0x13, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0x12, 0x02, 0x12, 0x13, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x4D, 0x4D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xF9, 0xF3, 0xF3, 0xC0, 0x80, 0xF3, 0xF3, 0xF3, 0xF9, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x20, 0x10, 0x10, 0xE0, 0xC0, 0x00, 0x70, 0xC0, 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x1C, 0xF0, 0x00, 0x00, 0xFC, 0x0C, 0x38, 0xE0, 0x00, 0x00, 0xC0, 0x38, 0x0C, 0xFC, 0x00, 0x00, 0xFC, 0xFC, 0x60, 0x90, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x3F, 0x3F, 0x07, 0x3F, 0x3F, 0x07, 0x0F, 0x3F, 0x07, 0x07, 0x3F, 0x07, 0x07, 0x3F, 0x3F, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x04, 0x04, 0x07, 0x01, 0x00, 0x00, 0x13, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x07, 0x0D, 0x08, 0x00, 0x07, 0x00, 0x00, 0x01, 0x07, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x07, 0x07, 0x00, 0x01, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
94# elif LCDHEIGHT == 64
95static uint8_t micro_oled_screen_buffer[LCDWIDTH * LCDHEIGHT / 8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7F, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xF8, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xF0, 0xF3, 0xF3, 0xE7, 0xE7, 0x00, 0x00, 0xE7, 0xE7, 0xF3, 0xF3, 0xF0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x1F, 0x3F, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x80, 0x03, 0x03, 0x00, 0x00, 0x01, 0x03, 0x00, 0x80, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x11, 0x11, 0x11, 0x0E, 0x00, 0x70, 0x88, 0x04, 0x04, 0x04, 0xF8, 0x00, 0x00, 0x3C, 0xE0, 0xC0, 0x38, 0x1C, 0xE0, 0x80, 0x70, 0x0C, 0x00, 0xF8, 0xAC, 0x24, 0x24, 0x3C, 0x30, 0x00, 0x00, 0xFC, 0x0C, 0x04, 0x00, 0xF8, 0xAC, 0x24, 0x24, 0x2C, 0x30, 0x00, 0x70, 0xDC, 0x04, 0x04, 0x88, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x8C, 0x04, 0x04, 0xF8, 0x00, 0x04, 0x3C, 0xE0, 0x80, 0xF0, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x83, 0x01, 0x01, 0x01, 0x81, 0xFE, 0x3C, 0x00, 0x00, 0xFF, 0x03, 0x0E, 0x70, 0xC0, 0xE0, 0x38, 0x06, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0x18, 0x38, 0x66, 0xC3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
104// TODO: generate bitmap of QMK logo here
105# endif
106# else
107// catchall for custom screen sizes
108static uint8_t micro_oled_screen_buffer[LCDWIDTH * LCDHEIGHT / 8] = {0};
109# endif
110#endif
111
112void micro_oled_init(void) {
113 i2c_init();
114
115#ifdef __AVR__
116 i2c_start(I2C_ADDRESS_SA0_1, 100);
117#else
118 i2c_start(I2C_ADDRESS_SA0_1);
119#endif
120
121 // Display Init sequence for 64x48 OLED module
122 send_command(DISPLAYOFF); // 0xAE
123
124 send_command(SETDISPLAYCLOCKDIV); // 0xD5
125 send_command(0x80); // the suggested ratio 0x80
126
127 send_command(SETMULTIPLEX); // 0xA8
128 send_command(LCDHEIGHT - 1);
129
130 send_command(SETDISPLAYOFFSET); // 0xD3
131 send_command(0x00); // no offset
132
133 send_command(SETSTARTLINE | 0x00); // line #0
134
135 send_command(CHARGEPUMP); // enable charge pump
136 send_command(0x14);
137
138 send_command(NORMALDISPLAY); // 0xA6
139 send_command(DISPLAYALLONRESUME); // 0xA4
140
141 // display at regular orientation
142 send_command(SEGREMAP | 0x1);
143 send_command(COMSCANDEC);
144
145// rotate display 180
146#ifdef micro_oled_rotate_180
147 send_command(SEGREMAP);
148 send_command(COMSCANINC);
149#endif
150
151 send_command(MEMORYMODE);
152 send_command(0x02); // 0x02 = 10b, Page addressing mode
153
154 send_command(SETCOMPINS); // 0xDA
155 if (LCDHEIGHT > 32) {
156 send_command(0x12);
157 } else {
158 send_command(0x02);
159 }
160 send_command(SETCONTRAST); // 0x81
161 send_command(0x8F);
162
163 send_command(SETPRECHARGE); // 0xd9
164 send_command(0xF1);
165
166 send_command(SETVCOMDESELECT); // 0xDB
167 send_command(0x40);
168
169 send_command(DISPLAYON); //--turn on oled panel
170 clear_screen(); // Erase hardware memory inside the OLED controller to avoid random data in memory.
171 send_buffer();
172}
173
174void send_command(uint8_t command) {
175 micro_oled_transfer_buffer[0] = I2C_COMMAND;
176 micro_oled_transfer_buffer[1] = command;
177 i2c_transmit(I2C_ADDRESS_SA0_1 << 1, micro_oled_transfer_buffer, 2, 100);
178}
179
180void send_data(uint8_t data) {
181 micro_oled_transfer_buffer[0] = I2C_DATA;
182 micro_oled_transfer_buffer[1] = data;
183 i2c_transmit(I2C_ADDRESS_SA0_1 << 1, micro_oled_transfer_buffer, 2, 100);
184}
185
186/** \brief Set SSD1306 page address.
187 Send page address command and address to the SSD1306 OLED controller.
188*/
189void set_page_address(uint8_t address) {
190 address = (0xB0 | address);
191 send_command(address);
192}
193
194/** \brief Set SSD1306 column address.
195 Send column address command and address to the SSD1306 OLED controller.
196*/
197void set_column_address(uint8_t address) {
198 send_command((0x10 | (address >> 4)) + ((128 - LCDWIDTH) >> 8));
199 send_command(0x0F & address);
200}
201
202/** \brief Clear SSD1306's memory.
203 To clear GDRAM inside the LCD controller.
204*/
205void clear_screen(void) {
206 for (int i = 0; i < 8; i++) {
207 set_page_address(i);
208 set_column_address(0);
209 for (int j = 0; j < 0x80; j++) {
210 send_data(0);
211 }
212 }
213
214 memset(micro_oled_screen_current, 0, LCDWIDTH * LCDHEIGHT / 8);
215}
216
217/** \brief Clear SSD1306's memory.
218 To clear GDRAM inside the LCD controller.
219*/
220void clear_buffer(void) {
221 // 384
222 memset(micro_oled_screen_buffer, 0, LCDWIDTH * LCDHEIGHT / 8);
223}
224
225/** \brief Invert display.
226 The PIXEL_ON color of the display will turn to PIXEL_OFF and the PIXEL_OFF will turn to PIXEL_ON.
227*/
228void invert_screen(bool invert) {
229 if (invert) {
230 send_command(INVERTDISPLAY);
231 } else {
232 send_command(NORMALDISPLAY);
233 }
234}
235
236/** \brief Set contrast.
237 OLED contract value from 0 to 255. Note: Contrast level is not very obvious.
238*/
239void set_contrast(uint8_t contrast) {
240 send_command(SETCONTRAST); // 0x81
241 send_command(contrast);
242}
243
244/** \brief Transfer display buffer.
245 Sends the updated buffer to the controller - the current status is checked before to save i2c exectution time
246*/
247void send_buffer(void) {
248 uint8_t i, j;
249
250 uint8_t page_addr = 0xFF;
251 for (i = 0; i < LCDHEIGHT / 8; i++) {
252 uint8_t col_addr = 0xFF;
253 for (j = 0; j < LCDWIDTH; j++) {
254 if (micro_oled_screen_buffer[i * LCDWIDTH + j] != micro_oled_screen_current[i * LCDWIDTH + j]) {
255 if (page_addr != i) {
256 set_page_address(i);
257 page_addr = i;
258 }
259 if (col_addr != j) {
260 set_column_address(j);
261 col_addr = j + 1;
262 }
263 send_data(micro_oled_screen_buffer[i * LCDWIDTH + j]);
264 micro_oled_screen_current[i * LCDWIDTH + j] = micro_oled_screen_buffer[i * LCDWIDTH + j];
265 }
266 }
267 }
268}
269
270/** \brief Draw pixel with color and mode.
271 Draw color pixel in the screen buffer's x,y position with NORM or XOR draw mode.
272*/
273void draw_pixel(uint8_t x, uint8_t y, uint8_t color, uint8_t mode) {
274 if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT)) return;
275
276 if (mode == XOR) {
277 if (color == PIXEL_ON) micro_oled_screen_buffer[x + (y / 8) * LCDWIDTH] ^= _BV((y % 8));
278 } else {
279 if (color == PIXEL_ON)
280 micro_oled_screen_buffer[x + (y / 8) * LCDWIDTH] |= _BV((y % 8));
281 else
282 micro_oled_screen_buffer[x + (y / 8) * LCDWIDTH] &= ~_BV((y % 8));
283 }
284}
285
286/** \brief Draw line with color and mode.
287Draw line using color and mode from x0,y0 to x1,y1 of the screen buffer.
288*/
289void draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color, uint8_t mode) {
290 uint8_t steep = abs(y1 - y0) > abs(x1 - x0);
291 if (steep) {
292 swap(x0, y0);
293 swap(x1, y1);
294 }
295
296 if (x0 > x1) {
297 swap(x0, x1);
298 swap(y0, y1);
299 }
300
301 uint8_t dx, dy;
302 dx = x1 - x0;
303 dy = abs(y1 - y0);
304
305 int8_t err = dx / 2;
306 int8_t ystep;
307
308 if (y0 < y1) {
309 ystep = 1;
310 } else {
311 ystep = -1;
312 }
313
314 for (; x0 < x1; x0++) {
315 if (steep) {
316 draw_pixel(y0, x0, color, mode);
317 } else {
318 draw_pixel(x0, y0, color, mode);
319 }
320 err -= dy;
321 if (err < 0) {
322 y0 += ystep;
323 err += dx;
324 }
325 }
326}
327
328/** \brief Draw horizontal line with color and mode.
329Draw horizontal line using color and mode from x,y to x+width,y of the screen buffer.
330*/
331void draw_line_hori(uint8_t x, uint8_t y, uint8_t width, uint8_t color, uint8_t mode) { draw_line(x, y, x + width, y, color, mode); }
332
333/** \brief Draw vertical line.
334Draw vertical line using current fore color and current draw mode from x,y to x,y+height of the screen buffer.
335*/
336void draw_line_vert(uint8_t x, uint8_t y, uint8_t height, bool color, uint8_t mode) { draw_line(x, y, x, y + height, color, mode); }
337
338/** \brief Draw rectangle with color and mode.
339Draw rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
340*/
341void draw_rect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
342 uint8_t tempHeight;
343
344 draw_line_hori(x, y, width, color, mode);
345 draw_line_hori(x, y + height - 1, width, color, mode);
346
347 tempHeight = height - 2;
348
349 // skip drawing vertical lines to avoid overlapping of pixel that will
350 // affect XOR plot if no pixel in between horizontal lines
351 if (tempHeight < 1) return;
352
353 draw_line_vert(x, y + 1, tempHeight, color, mode);
354 draw_line_vert(x + width - 1, y + 1, tempHeight, color, mode);
355}
356
357/** \brief Draw rectangle with color and mode.
358Draw rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
359*/
360void draw_rect_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
361 uint8_t tempHeight;
362
363 draw_line_hori(x + 1, y, width - 2, color, mode);
364 draw_line_hori(x + 1, y + height - 1, width - 2, color, mode);
365
366 tempHeight = height - 2;
367
368 // skip drawing vertical lines to avoid overlapping of pixel that will
369 // affect XOR plot if no pixel in between horizontal lines
370 if (tempHeight < 1) return;
371
372 draw_line_vert(x, y + 1, tempHeight, color, mode);
373 draw_line_vert(x + width - 1, y + 1, tempHeight, color, mode);
374}
375
376/** \brief Draw filled rectangle with color and mode.
377Draw filled rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
378*/
379void draw_rect_filled(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
380 // TODO - need to optimise the memory map draw so that this function will not call pixel one by one
381 for (int i = x; i < x + width; i++) {
382 draw_line_vert(i, y, height, color, mode);
383 }
384}
385
386/** \brief Draw filled rectangle with color and mode.
387Draw filled rectangle using color and mode from x,y to x+width,y+height of the screen buffer.
388*/
389void draw_rect_filled_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode) {
390 // TODO - need to optimise the memory map draw so that this function will not call pixel one by one
391 for (int i = x; i < x + width; i++) {
392 if (i == x || i == (x + width - 1))
393 draw_line_vert(i, y + 1, height - 2, color, mode);
394 else
395 draw_line_vert(i, y, height, color, mode);
396 }
397}
398
399/** \brief Draw character with color and mode.
400 Draw character c using color and draw mode at x,y.
401*/
402void draw_char(uint8_t x, uint8_t y, uint8_t c, uint8_t color, uint8_t mode, uint8_t font) {
403 // TODO - New routine to take font of any height, at the moment limited to font height in multiple of 8 pixels
404
405 uint8_t rowsToDraw, row, tempC;
406 uint8_t i, j, temp;
407 uint16_t charPerBitmapRow, charColPositionOnBitmap, charRowPositionOnBitmap, charBitmapStartPosition;
408
409 if ((font >= TOTALFONTS) || (font < 0)) return;
410
411 uint8_t fontType = font;
412 uint8_t fontWidth = pgm_read_byte(fonts_pointer[fontType] + 0);
413 uint8_t fontHeight = pgm_read_byte(fonts_pointer[fontType] + 1);
414 uint8_t fontStartChar = pgm_read_byte(fonts_pointer[fontType] + 2);
415 uint8_t fontTotalChar = pgm_read_byte(fonts_pointer[fontType] + 3);
416 uint16_t fontMapWidth = (pgm_read_byte(fonts_pointer[fontType] + 4) * 100) + pgm_read_byte(fonts_pointer[fontType] + 5); // two bytes values into integer 16
417
418 if ((c < fontStartChar) || (c > (fontStartChar + fontTotalChar - 1))) // no bitmap for the required c
419 return;
420
421 tempC = c - fontStartChar;
422
423 // each row (in datasheet is call page) is 8 bits high, 16 bit high character will have 2 rows to be drawn
424 rowsToDraw = fontHeight / 8; // 8 is LCD's page size, see SSD1306 datasheet
425 if (rowsToDraw <= 1) rowsToDraw = 1;
426
427 // the following draw function can draw anywhere on the screen, but SLOW pixel by pixel draw
428 if (rowsToDraw == 1) {
429 for (i = 0; i < fontWidth + 1; i++) {
430 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
431 temp = 0;
432 else
433 temp = pgm_read_byte(fonts_pointer[fontType] + FONTHEADERSIZE + (tempC * fontWidth) + i);
434
435 for (j = 0; j < 8; j++) { // 8 is the LCD's page height (see datasheet for explanation)
436 if (temp & 0x1) {
437 draw_pixel(x + i, y + j, color, mode);
438 } else {
439 draw_pixel(x + i, y + j, !color, mode);
440 }
441
442 temp >>= 1;
443 }
444 }
445 return;
446 }
447
448 // font height over 8 bit
449 // take character "0" ASCII 48 as example
450 charPerBitmapRow = fontMapWidth / fontWidth; // 256/8 =32 char per row
451 charColPositionOnBitmap = tempC % charPerBitmapRow; // =16
452 charRowPositionOnBitmap = (int)(tempC / charPerBitmapRow); // =1
453 charBitmapStartPosition = (charRowPositionOnBitmap * fontMapWidth * (fontHeight / 8)) + (charColPositionOnBitmap * fontWidth);
454
455 // each row on LCD is 8 bit height (see datasheet for explanation)
456 for (row = 0; row < rowsToDraw; row++) {
457 for (i = 0; i < fontWidth; i++) {
458 temp = pgm_read_byte(fonts_pointer[fontType] + FONTHEADERSIZE + (charBitmapStartPosition + i + (row * fontMapWidth)));
459 for (j = 0; j < 8; j++) { // 8 is the LCD's page height (see datasheet for explanation)
460 if (temp & 0x1) {
461 draw_pixel(x + i, y + j + (row * 8), color, mode);
462 } else {
463 draw_pixel(x + i, y + j + (row * 8), !color, mode);
464 }
465 temp >>= 1;
466 }
467 }
468 }
469}
470
471void draw_string(uint8_t x, uint8_t y, char* string, uint8_t color, uint8_t mode, uint8_t font) {
472 if ((font >= TOTALFONTS) || (font < 0)) return;
473
474 uint8_t fontType = font;
475 uint8_t fontWidth = pgm_read_byte(fonts_pointer[fontType] + 0);
476
477 uint8_t cur_x = x;
478 for (int i = 0; i < strlen(string); i++) {
479 draw_char(cur_x, y, string[i], color, mode, font);
480 cur_x += fontWidth + 1;
481 }
482}
diff --git a/drivers/qwiic/micro_oled.h b/drivers/qwiic/micro_oled.h
deleted file mode 100644
index 6f9106f58..000000000
--- a/drivers/qwiic/micro_oled.h
+++ /dev/null
@@ -1,134 +0,0 @@
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#pragma once
31
32#include "qwiic.h"
33
34void micro_oled_init(void);
35
36void send_command(uint8_t command);
37void send_data(uint8_t data);
38void set_page_address(uint8_t address);
39void set_column_address(uint8_t address);
40void clear_screen(void);
41void clear_buffer(void);
42void send_buffer(void);
43void draw_pixel(uint8_t x, uint8_t y, uint8_t color, uint8_t mode);
44void draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color, uint8_t mode);
45void draw_line_hori(uint8_t x, uint8_t y, uint8_t width, uint8_t color, uint8_t mode);
46void draw_line_vert(uint8_t x, uint8_t y, uint8_t height, bool color, uint8_t mode);
47void draw_rect(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode);
48void draw_rect_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode);
49void draw_rect_filled(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode);
50void draw_rect_filled_soft(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t color, uint8_t mode);
51void draw_char(uint8_t x, uint8_t y, uint8_t c, uint8_t color, uint8_t mode, uint8_t font);
52void draw_string(uint8_t x, uint8_t y, char* string, uint8_t color, uint8_t mode, uint8_t font);
53
54#define I2C_ADDRESS_SA0_0 0b0111100
55#ifndef I2C_ADDRESS_SA0_1
56# define I2C_ADDRESS_SA0_1 0b0111101
57#endif
58#define I2C_COMMAND 0x00
59#define I2C_DATA 0x40
60#define PIXEL_OFF 0
61#define PIXEL_ON 1
62
63#ifndef LCDWIDTH
64# define LCDWIDTH 64
65#endif
66#ifndef LCDHEIGHT
67# define LCDHEIGHT 48
68#endif
69#define FONTHEADERSIZE 6
70
71#define NORM 0
72#define XOR 1
73
74#define PAGE 0
75#define ALL 1
76
77#define WIDGETSTYLE0 0
78#define WIDGETSTYLE1 1
79#define WIDGETSTYLE2 2
80
81#define SETCONTRAST 0x81
82#define DISPLAYALLONRESUME 0xA4
83#define DISPLAYALLON 0xA5
84#define NORMALDISPLAY 0xA6
85#define INVERTDISPLAY 0xA7
86#define DISPLAYOFF 0xAE
87#define DISPLAYON 0xAF
88#define SETDISPLAYOFFSET 0xD3
89#define SETCOMPINS 0xDA
90#define SETVCOMDESELECT 0xDB
91#define SETDISPLAYCLOCKDIV 0xD5
92#define SETPRECHARGE 0xD9
93#define SETMULTIPLEX 0xA8
94#define SETLOWCOLUMN 0x00
95#define SETHIGHCOLUMN 0x10
96#define SETSTARTLINE 0x40
97#define MEMORYMODE 0x20
98#define COMSCANINC 0xC0
99#define COMSCANDEC 0xC8
100#define SEGREMAP 0xA0
101#define CHARGEPUMP 0x8D
102#define EXTERNALVCC 0x01
103#define SWITCHCAPVCC 0x02
104
105// Scroll
106#define ACTIVATESCROLL 0x2F
107#define DEACTIVATESCROLL 0x2E
108#define SETVERTICALSCROLLAREA 0xA3
109#define RIGHTHORIZONTALSCROLL 0x26
110#define LEFT_HORIZONTALSCROLL 0x27
111#define VERTICALRIGHTHORIZONTALSCROLL 0x29
112#define VERTICALLEFTHORIZONTALSCROLL 0x2A
113
114typedef enum CMD {
115 CMD_CLEAR, // 0
116 CMD_INVERT, // 1
117 CMD_CONTRAST, // 2
118 CMD_DISPLAY, // 3
119 CMD_SETCURSOR, // 4
120 CMD_PIXEL, // 5
121 CMD_LINE, // 6
122 CMD_LINEH, // 7
123 CMD_LINEV, // 8
124 CMD_RECT, // 9
125 CMD_RECTFILL, // 10
126 CMD_CIRCLE, // 11
127 CMD_CIRCLEFILL, // 12
128 CMD_DRAWCHAR, // 13
129 CMD_DRAWBITMAP, // 14
130 CMD_GETLCDWIDTH, // 15
131 CMD_GETLCDHEIGHT, // 16
132 CMD_SETCOLOR, // 17
133 CMD_SETDRAWMODE // 18
134} commCommand_t;
diff --git a/drivers/qwiic/qwiic.c b/drivers/qwiic/qwiic.c
deleted file mode 100644
index 316d6539c..000000000
--- a/drivers/qwiic/qwiic.c
+++ /dev/null
@@ -1,31 +0,0 @@
1/* Copyright 2018 Jack Humbert <jack.humb@gmail.com>
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include "qwiic.h"
17
18void qwiic_init(void) {
19#ifdef QWIIC_JOYSTIIC_ENABLE
20 joystiic_init();
21#endif
22#ifdef QWIIC_MICRO_OLED_ENABLE
23 micro_oled_init();
24#endif
25}
26
27void qwiic_task(void) {
28#ifdef QWIIC_JOYSTIIC_ENABLE
29 joystiic_task();
30#endif
31}
diff --git a/drivers/qwiic/qwiic.h b/drivers/qwiic/qwiic.h
deleted file mode 100644
index 8c3d1c8d6..000000000
--- a/drivers/qwiic/qwiic.h
+++ /dev/null
@@ -1,28 +0,0 @@
1/* Copyright 2018 Jack Humbert <jack.humb@gmail.com>
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "i2c_master.h"
19
20#ifdef QWIIC_JOYSTIIC_ENABLE
21# include "joystiic.h"
22#endif
23#ifdef QWIIC_MICRO_OLED_ENABLE
24# include "micro_oled.h"
25#endif
26
27void qwiic_init(void);
28void qwiic_task(void);
diff --git a/drivers/qwiic/qwiic.mk b/drivers/qwiic/qwiic.mk
deleted file mode 100644
index 164bd7210..000000000
--- a/drivers/qwiic/qwiic.mk
+++ /dev/null
@@ -1,17 +0,0 @@
1ifeq ($(strip $(QWIIC_ENABLE)),yes)
2 COMMON_VPATH += $(DRIVER_PATH)/qwiic
3 OPT_DEFS += -DQWIIC_ENABLE
4 SRC += qwiic.c
5 QUANTUM_LIB_SRC += i2c_master.c
6
7ifneq ($(filter JOYSTIIC, $(QWIIC_DRIVERS)),)
8 OPT_DEFS += -DQWIIC_JOYSTIIC_ENABLE
9 SRC += joystiic.c
10endif
11
12ifneq ($(filter MICRO_OLED, $(QWIIC_DRIVERS)),)
13 OPT_DEFS += -DQWIIC_MICRO_OLED_ENABLE
14 SRC += micro_oled.c
15endif
16
17endif
diff --git a/drivers/qwiic/util/font5x7.h b/drivers/qwiic/util/font5x7.h
deleted file mode 100644
index a641945aa..000000000
--- a/drivers/qwiic/util/font5x7.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/******************************************************************************
2font5x7.h
3Definition for small font
4
5This file was imported from the MicroView library, written by GeekAmmo
6(https://github.com/geekammo/MicroView-Arduino-Library), and released under
7the terms of the GNU General Public License as published by the Free Software
8Foundation, either version 3 of the License, or (at your option) any later
9version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19Modified by:
20Emil Varughese @ Edwin Robotics Pvt. Ltd.
21July 27, 2015
22https://github.com/emil01/SparkFun_Micro_OLED_Arduino_Library/
23
24******************************************************************************/
25#pragma once
26
27#include "progmem.h"
28
29// Standard ASCII 5x7 font
30static const unsigned char font5x7[] PROGMEM = {
31 // first row defines - FONTWIDTH, FONTHEIGHT, ASCII START CHAR, TOTAL CHARACTERS, FONT MAP WIDTH HIGH, FONT MAP WIDTH LOW (2,56 meaning 256)
32 5, 8, 0, 255, 12, 75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24, 0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x30, 0x38, 0x3E, 0x38, 0x30,
33 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41, 0x22, 0x14, 0x08, 0x02,
34 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, 0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40,
35 0x40, 0x40, 0x40, 0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28, 0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, 0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, 0x26, 0x23,
36 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, 0x21, 0x54, 0x54, 0x78, 0x41, 0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0xF0, 0x29, 0x24, 0x29, 0xF0, 0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, 0x32, 0x32, 0x48, 0x48, 0x48, 0x32, 0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x39, 0x44, 0x44, 0x44, 0x39, 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, 0x20, 0xC0, 0x88, 0x7E, 0x09,
37 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, 0x14, 0x08, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10,
38 0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17, 0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, 0x38, 0x44, 0x7C,
39 0x2A, 0x2A, 0x3E, 0x14, 0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/drivers/qwiic/util/font8x16.h b/drivers/qwiic/util/font8x16.h
deleted file mode 100644
index 4d3c23786..000000000
--- a/drivers/qwiic/util/font8x16.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/******************************************************************************
2font8x16.h
3Definition for medium font
4
5This file was imported from the MicroView library, written by GeekAmmo
6(https://github.com/geekammo/MicroView-Arduino-Library), and released under
7the terms of the GNU General Public License as published by the Free Software
8Foundation, either version 3 of the License, or (at your option) any later
9version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19Modified by:
20Emil Varughese @ Edwin Robotics Pvt. Ltd.
21July 27, 2015
22https://github.com/emil01/SparkFun_Micro_OLED_Arduino_Library/
23******************************************************************************/
24#pragma once
25
26#include "progmem.h"
27
28static const unsigned char font8x16[] PROGMEM = {
29 // first row defines - FONTWIDTH, FONTHEIGHT, ASCII START CHAR, TOTAL CHARACTERS, FONT MAP WIDTH HIGH, FONT MAP WIDTH LOW (2,56 meaning 256)
30 8, 16, 32, 96, 2, 56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xBE, 0x90, 0xD0, 0xBE, 0x90, 0x00, 0x00, 0x1C, 0x62, 0xFF, 0xC2, 0x80, 0x00, 0x00, 0x0C, 0x12, 0x92, 0x4C, 0xB0, 0x88, 0x06, 0x00, 0x80, 0x7C, 0x62, 0xB2, 0x1C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x24, 0x18, 0x7E, 0x18, 0x24, 0x00, 0x00, 0x80, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x06, 0x00, 0x00, 0xF8, 0x04, 0xC2, 0x32, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x04, 0x04, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x42, 0x22,
31 0x1C, 0x00, 0x00, 0x00, 0x02, 0x22, 0x22, 0x22, 0xDC, 0x00, 0x00, 0xC0, 0xA0, 0x98, 0x84, 0xFE, 0x80, 0x80, 0x00, 0x00, 0x1E, 0x12, 0x12, 0x22, 0xC2, 0x00, 0x00, 0xF8, 0x44, 0x22, 0x22, 0x22, 0xC0, 0x00, 0x00, 0x00, 0x02, 0x02, 0xC2, 0x32, 0x0A, 0x06, 0x00, 0x00, 0x8C, 0x52, 0x22, 0x52, 0x8C, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x26, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x02, 0x82, 0x42, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x0F, 0x04, 0x03, 0x00, 0x00, 0x04, 0x02, 0x01, 0x03, 0x04, 0x04, 0x03, 0x00,
32 0x03, 0x04, 0x04, 0x04, 0x05, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x08, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x07, 0x04, 0x04, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x04, 0x04,
33 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x04, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x04, 0x72, 0x8A, 0xFA, 0x84, 0x78, 0x00, 0x00, 0xC0, 0x38, 0x06, 0x38, 0xC0, 0x00, 0x00, 0x00, 0xFE, 0x22, 0x22, 0x22, 0xDC, 0x00, 0x00, 0xF8, 0x04, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x04, 0xF8, 0x00, 0x00, 0x00, 0xFE, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0xFE, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0xF8, 0x04, 0x02, 0x02, 0x22, 0xE2, 0x00, 0x00, 0xFE, 0x20, 0x20, 0x20, 0x20, 0xFE, 0x00, 0x00, 0x00, 0x02, 0x02, 0xFE, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0xFE, 0x00, 0x00, 0xFE, 0x40, 0xB0, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
34 0x00, 0x00, 0xFE, 0x0C, 0x70, 0x80, 0x70, 0x0C, 0xFE, 0x00, 0xFE, 0x0C, 0x30, 0xC0, 0x00, 0xFE, 0x00, 0x00, 0xF8, 0x04, 0x02, 0x02, 0x04, 0xF8, 0x00, 0x00, 0xFE, 0x42, 0x42, 0x42, 0x22, 0x1C, 0x00, 0x00, 0xF8, 0x04, 0x02, 0x02, 0x04, 0xF8, 0x00, 0x00, 0x00, 0xFE, 0x42, 0x42, 0xA2, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x42, 0x42, 0x80, 0x00, 0x00, 0x02, 0x02, 0x02, 0xFE, 0x02, 0x02, 0x02, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x06, 0x38, 0xC0, 0x00, 0xC0, 0x38, 0x06, 0x00, 0x3E, 0xC0, 0xF0, 0x0E, 0xF0, 0xC0, 0x3E, 0x00, 0x00, 0x06, 0x98, 0x60, 0x98, 0x06, 0x00, 0x00, 0x00, 0x06, 0x18, 0xE0, 0x18, 0x06, 0x00, 0x00, 0x02, 0x02, 0xC2, 0x32, 0x0A, 0x06, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x06, 0x18, 0x60, 0x80, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x40, 0x30, 0x0C, 0x0C, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
35 0x02, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x06, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x04, 0x07, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0C, 0x12, 0x11, 0x10, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,
36 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0xFE, 0x20, 0x10, 0x10, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xFE, 0x00, 0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00, 0x00, 0x00, 0x20, 0xFC, 0x22, 0x22, 0x22, 0x02,
37 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0xFE, 0x20, 0x10, 0x10, 0xE0, 0x00, 0x00, 0x10, 0x10, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x80, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x20, 0x10, 0xF0, 0x20, 0x10, 0xF0, 0x00, 0x00, 0xF0, 0x20, 0x10, 0x10, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x20, 0x10, 0x10, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0x20, 0x10, 0x10, 0x70, 0x00, 0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x20, 0x00, 0x00, 0x00, 0x20, 0x20, 0xFC, 0x20, 0x20, 0x20, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x70, 0x80, 0x00, 0x80, 0x70, 0x00, 0x00, 0xF0, 0x00, 0xC0, 0x30, 0xC0, 0x00, 0xF0, 0x00, 0x00, 0x30, 0xC0, 0xC0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0xC0, 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x10,
38 0x10, 0x90, 0x50, 0x30, 0x00, 0x00, 0x00, 0x80, 0x80, 0x7E, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x7E, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x02, 0x07, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x02, 0x07, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x24, 0x24, 0x22, 0x1F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00,
39 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x3F, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x02, 0x3F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x00, 0x00, 0x03, 0x04, 0x04, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x00, 0x01, 0x06, 0x01, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x20, 0x20, 0x31, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h b/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h
deleted file mode 100644
index 0755ddf6c..000000000
--- a/drivers/ugfx/gdisp/is31fl3731c/board_is31fl3731c_template.h
+++ /dev/null
@@ -1,105 +0,0 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef _GDISP_LLD_BOARD_H
19#define _GDISP_LLD_BOARD_H
20
21static const I2CConfig i2ccfg = {
22 400000 // clock speed (Hz); 400kHz max for IS31
23};
24
25static const uint8_t led_mask[] = {
26 0xFF, 0x00, /* C1-1 -> C1-16 */
27 0xFF, 0x00, /* C2-1 -> C2-16 */
28 0xFF, 0x00, /* C3-1 -> C3-16 */
29 0xFF, 0x00, /* C4-1 -> C4-16 */
30 0x3F, 0x00, /* C5-1 -> C5-16 */
31 0x00, 0x00, /* C6-1 -> C6-16 */
32 0x00, 0x00, /* C7-1 -> C7-16 */
33 0x00, 0x00, /* C8-1 -> C8-16 */
34 0x00, 0x00, /* C9-1 -> C9-16 */
35};
36
37// The address of the LED
38#define LA(c, r) (c + r * 16)
39// Need to be an address that is not mapped, but inside the range of the controller matrix
40#define NA LA(8, 8)
41
42// The numbers in the comments are the led numbers DXX on the PCB
43// The mapping is taken from the schematic of left hand side
44static const uint8_t led_mapping[GDISP_SCREEN_HEIGHT][GDISP_SCREEN_WIDTH] = {
45 // 45 44 43 42 41 40 39
46 {LA(1, 1), LA(1, 0), LA(0, 4), LA(0, 3), LA(0, 2), LA(0, 1), LA(0, 0)},
47 // 52 51 50 49 48 47 46
48 {LA(2, 3), LA(2, 2), LA(2, 1), LA(2, 0), LA(1, 4), LA(1, 3), LA(1, 2)},
49 // 58 57 56 55 54 53 N/A
50 {LA(3, 4), LA(3, 3), LA(3, 2), LA(3, 1), LA(3, 0), LA(2, 4), NA},
51 // 67 66 65 64 63 62 61
52 {LA(5, 3), LA(5, 2), LA(5, 1), LA(5, 0), LA(4, 4), LA(4, 3), LA(4, 2)},
53 // 76 75 74 73 72 60 59
54 {LA(7, 3), LA(7, 2), LA(7, 1), LA(7, 0), LA(6, 3), LA(4, 1), LA(4, 0)},
55 // N/A N/A N/A N/A N/A N/A 68
56 {NA, NA, NA, NA, NA, NA, LA(5, 4)},
57 // N/A N/A N/A N/A 71 70 69
58 {NA, NA, NA, NA, LA(6, 2), LA(6, 1), LA(6, 0)},
59};
60
61#define IS31_ADDR_DEFAULT 0x74 // AD connected to GND
62#define IS31_TIMEOUT 5000
63
64static GFXINLINE void init_board(GDisplay* g) {
65 (void)g;
66 /* I2C pins */
67 palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
68 palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA
69 palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
70 palClearPad(GPIOB, 16);
71 /* start I2C */
72 i2cStart(&I2CD1, &i2ccfg);
73 // try high drive (from kiibohd)
74 I2CD1.i2c->C2 |= I2Cx_C2_HDRS;
75 // try glitch fixing (from kiibohd)
76 I2CD1.i2c->FLT = 4;
77}
78
79static GFXINLINE void post_init_board(GDisplay* g) { (void)g; }
80
81static GFXINLINE const uint8_t* get_led_mask(GDisplay* g) {
82 (void)g;
83 return led_mask;
84}
85
86static GFXINLINE uint8_t get_led_address(GDisplay* g, uint16_t x, uint16_t y) {
87 (void)g;
88 return led_mapping[y][x];
89}
90
91static GFXINLINE void set_hardware_shutdown(GDisplay* g, bool shutdown) {
92 (void)g;
93 if (!shutdown) {
94 palSetPad(GPIOB, 16);
95 } else {
96 palClearPad(GPIOB, 16);
97 }
98}
99
100static GFXINLINE void write_data(GDisplay* g, uint8_t* data, uint16_t length) {
101 (void)g;
102 i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, data, length, 0, 0, US2ST(IS31_TIMEOUT));
103}
104
105#endif /* _GDISP_LLD_BOARD_H */
diff --git a/drivers/ugfx/gdisp/is31fl3731c/driver.mk b/drivers/ugfx/gdisp/is31fl3731c/driver.mk
deleted file mode 100644
index a53131bf3..000000000
--- a/drivers/ugfx/gdisp/is31fl3731c/driver.mk
+++ /dev/null
@@ -1,3 +0,0 @@
1GFXINC += drivers/ugfx/gdisp/is31fl3731c
2GFXSRC += drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
3GDISP_DRIVER_LIST += GDISPVMT_IS31FL3731C_QMK
diff --git a/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c b/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
deleted file mode 100644
index 718824402..000000000
--- a/drivers/ugfx/gdisp/is31fl3731c/gdisp_is31fl3731c.c
+++ /dev/null
@@ -1,302 +0,0 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "gfx.h"
19
20#if GFX_USE_GDISP
21
22# define GDISP_DRIVER_VMT GDISPVMT_IS31FL3731C_QMK
23# define GDISP_SCREEN_HEIGHT LED_HEIGHT
24# define GDISP_SCREEN_WIDTH LED_WIDTH
25
26# include "gdisp_lld_config.h"
27# include "src/gdisp/gdisp_driver.h"
28
29# include "board_is31fl3731c.h"
30
31// Can't include led_tables from here
32extern const uint8_t CIE1931_CURVE[];
33
34/*===========================================================================*/
35/* Driver local definitions. */
36/*===========================================================================*/
37
38# ifndef GDISP_INITIAL_CONTRAST
39# define GDISP_INITIAL_CONTRAST 0
40# endif
41# ifndef GDISP_INITIAL_BACKLIGHT
42# define GDISP_INITIAL_BACKLIGHT 0
43# endif
44
45# define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0)
46
47# define IS31_ADDR_DEFAULT 0x74
48
49# define IS31_REG_CONFIG 0x00
50// bits in reg
51# define IS31_REG_CONFIG_PICTUREMODE 0x00
52# define IS31_REG_CONFIG_AUTOPLAYMODE 0x08
53# define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18
54// D2:D0 bits are starting frame for autoplay mode
55
56# define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode
57
58# define IS31_REG_AUTOPLAYCTRL1 0x02
59// D6:D4 number of loops (000=infty)
60// D2:D0 number of frames to be used
61
62# define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms)
63
64# define IS31_REG_DISPLAYOPT 0x05
65# define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames
66# define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8
67// D2:D0 bits blink period time (*0.27s)
68
69# define IS31_REG_AUDIOSYNC 0x06
70# define IS31_REG_AUDIOSYNC_ENABLE 0x1
71
72# define IS31_REG_FRAMESTATE 0x07
73
74# define IS31_REG_BREATHCTRL1 0x08
75// D6:D4 fade out time (26ms*2^i)
76// D2:D0 fade in time (26ms*2^i)
77
78# define IS31_REG_BREATHCTRL2 0x09
79# define IS31_REG_BREATHCTRL2_ENABLE 0x10
80// D2:D0 extinguish time (3.5ms*2^i)
81
82# define IS31_REG_SHUTDOWN 0x0A
83# define IS31_REG_SHUTDOWN_OFF 0x0
84# define IS31_REG_SHUTDOWN_ON 0x1
85
86# define IS31_REG_AGCCTRL 0x0B
87# define IS31_REG_ADCRATE 0x0C
88
89# define IS31_COMMANDREGISTER 0xFD
90# define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine'
91# define IS31_FUNCTIONREG_SIZE 0xD
92
93# define IS31_FRAME_SIZE 0xB4
94
95# define IS31_PWM_REG 0x24
96# define IS31_PWM_SIZE 0x90
97
98# define IS31_LED_MASK_SIZE 0x12
99
100# define IS31
101
102/*===========================================================================*/
103/* Driver local functions. */
104/*===========================================================================*/
105
106typedef struct {
107 uint8_t write_buffer_offset;
108 uint8_t write_buffer[IS31_FRAME_SIZE];
109 uint8_t frame_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH];
110 uint8_t page;
111} __attribute__((__packed__)) PrivData;
112
113// Some common routines and macros
114# define PRIV(g) ((PrivData *)g->priv)
115
116/*===========================================================================*/
117/* Driver exported functions. */
118/*===========================================================================*/
119
120static GFXINLINE void write_page(GDisplay *g, uint8_t page) {
121 uint8_t tx[2] __attribute__((aligned(2)));
122 tx[0] = IS31_COMMANDREGISTER;
123 tx[1] = page;
124 write_data(g, tx, 2);
125}
126
127static GFXINLINE void write_register(GDisplay *g, uint8_t page, uint8_t reg, uint8_t data) {
128 uint8_t tx[2] __attribute__((aligned(2)));
129 tx[0] = reg;
130 tx[1] = data;
131 write_page(g, page);
132 write_data(g, tx, 2);
133}
134
135static GFXINLINE void write_ram(GDisplay *g, uint8_t page, uint16_t offset, uint16_t length) {
136 PRIV(g)->write_buffer_offset = offset;
137 write_page(g, page);
138 write_data(g, (uint8_t *)PRIV(g), length + 1);
139}
140
141LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
142 // The private area is the display surface.
143 g->priv = gfxAlloc(sizeof(PrivData));
144 __builtin_memset(PRIV(g), 0, sizeof(PrivData));
145 PRIV(g)->page = 0;
146
147 // Initialise the board interface
148 init_board(g);
149 gfxSleepMilliseconds(10);
150
151 // zero function page, all registers (assuming full_page is all zeroes)
152 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
153 set_hardware_shutdown(g, false);
154 gfxSleepMilliseconds(10);
155 // software shutdown
156 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
157 gfxSleepMilliseconds(10);
158 // zero function page, all registers
159 write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
160 gfxSleepMilliseconds(10);
161
162 // zero all LED registers on all 8 pages, and enable the mask
163 __builtin_memcpy(PRIV(g)->write_buffer, get_led_mask(g), IS31_LED_MASK_SIZE);
164 for (uint8_t i = 0; i < 8; i++) {
165 write_ram(g, i, 0, IS31_FRAME_SIZE);
166 gfxSleepMilliseconds(1);
167 }
168
169 // software shutdown disable (i.e. turn stuff on)
170 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
171 gfxSleepMilliseconds(10);
172
173 // Finish Init
174 post_init_board(g);
175
176 /* Initialise the GDISP structure */
177 g->g.Width = GDISP_SCREEN_WIDTH;
178 g->g.Height = GDISP_SCREEN_HEIGHT;
179 g->g.Orientation = GDISP_ROTATE_0;
180 g->g.Powermode = powerOff;
181 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
182 g->g.Contrast = GDISP_INITIAL_CONTRAST;
183 return TRUE;
184}
185
186# if GDISP_HARDWARE_FLUSH
187LLDSPEC void gdisp_lld_flush(GDisplay *g) {
188 // Don't flush if we don't need it.
189 if (!(g->flags & GDISP_FLG_NEEDFLUSH)) return;
190
191 PRIV(g)->page++;
192 PRIV(g)->page %= 2;
193 // TODO: some smarter algorithm for this
194 // We should run only one physical page at a time
195 // This way we don't need to send so much data, and
196 // we could use slightly less memory
197 uint8_t *src = PRIV(g)->frame_buffer;
198 for (int y = 0; y < GDISP_SCREEN_HEIGHT; y++) {
199 for (int x = 0; x < GDISP_SCREEN_WIDTH; x++) {
200 uint8_t val = (uint16_t)*src * g->g.Backlight / 100;
201 PRIV(g)->write_buffer[get_led_address(g, x, y)] = CIE1931_CURVE[val];
202 ++src;
203 }
204 }
205 write_ram(g, PRIV(g)->page, IS31_PWM_REG, IS31_PWM_SIZE);
206 gfxSleepMilliseconds(1);
207 write_register(g, IS31_FUNCTIONREG, IS31_REG_PICTDISP, PRIV(g)->page);
208
209 g->flags &= ~GDISP_FLG_NEEDFLUSH;
210}
211# endif
212
213# if GDISP_HARDWARE_DRAWPIXEL
214LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
215 coord_t x, y;
216
217 switch (g->g.Orientation) {
218 default:
219 case GDISP_ROTATE_0:
220 x = g->p.x;
221 y = g->p.y;
222 break;
223 case GDISP_ROTATE_180:
224 x = GDISP_SCREEN_WIDTH - 1 - g->p.x;
225 y = g->p.y;
226 break;
227 }
228 PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x] = gdispColor2Native(g->p.color);
229 g->flags |= GDISP_FLG_NEEDFLUSH;
230}
231# endif
232
233# if GDISP_HARDWARE_PIXELREAD
234LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
235 coord_t x, y;
236
237 switch (g->g.Orientation) {
238 default:
239 case GDISP_ROTATE_0:
240 x = g->p.x;
241 y = g->p.y;
242 break;
243 case GDISP_ROTATE_180:
244 x = GDISP_SCREEN_WIDTH - 1 - g->p.x;
245 y = g->p.y;
246 break;
247 }
248 return gdispNative2Color(PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x]);
249}
250# endif
251
252# if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
253LLDSPEC void gdisp_lld_control(GDisplay *g) {
254 switch (g->p.x) {
255 case GDISP_CONTROL_POWER:
256 if (g->g.Powermode == (powermode_t)g->p.ptr) return;
257 switch ((powermode_t)g->p.ptr) {
258 case powerOff:
259 case powerSleep:
260 case powerDeepSleep:
261 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
262 break;
263 case powerOn:
264 write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
265 break;
266 default:
267 return;
268 }
269 g->g.Powermode = (powermode_t)g->p.ptr;
270 return;
271
272 case GDISP_CONTROL_ORIENTATION:
273 if (g->g.Orientation == (orientation_t)g->p.ptr) return;
274 switch ((orientation_t)g->p.ptr) {
275 /* Rotation is handled by the drawing routines */
276 case GDISP_ROTATE_0:
277 case GDISP_ROTATE_180:
278 g->g.Height = GDISP_SCREEN_HEIGHT;
279 g->g.Width = GDISP_SCREEN_WIDTH;
280 break;
281 case GDISP_ROTATE_90:
282 case GDISP_ROTATE_270:
283 g->g.Height = GDISP_SCREEN_WIDTH;
284 g->g.Width = GDISP_SCREEN_HEIGHT;
285 break;
286 default:
287 return;
288 }
289 g->g.Orientation = (orientation_t)g->p.ptr;
290 return;
291
292 case GDISP_CONTROL_BACKLIGHT:
293 if (g->g.Backlight == (unsigned)g->p.ptr) return;
294 unsigned val = (unsigned)g->p.ptr;
295 g->g.Backlight = val > 100 ? 100 : val;
296 g->flags |= GDISP_FLG_NEEDFLUSH;
297 return;
298 }
299}
300# endif // GDISP_NEED_CONTROL
301
302#endif // GFX_USE_GDISP
diff --git a/drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h b/drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h
deleted file mode 100644
index 403c6b040..000000000
--- a/drivers/ugfx/gdisp/is31fl3731c/gdisp_lld_config.h
+++ /dev/null
@@ -1,36 +0,0 @@
1/*
2Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef _GDISP_LLD_CONFIG_H
19#define _GDISP_LLD_CONFIG_H
20
21#if GFX_USE_GDISP
22
23/*===========================================================================*/
24/* Driver hardware support. */
25/*===========================================================================*/
26
27# define GDISP_HARDWARE_FLUSH GFXON // This controller requires flushing
28# define GDISP_HARDWARE_DRAWPIXEL GFXON
29# define GDISP_HARDWARE_PIXELREAD GFXON
30# define GDISP_HARDWARE_CONTROL GFXON
31
32# define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_GRAY256
33
34#endif /* GFX_USE_GDISP */
35
36#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/drivers/ugfx/gdisp/st7565/board_st7565_template.h b/drivers/ugfx/gdisp/st7565/board_st7565_template.h
deleted file mode 100644
index 875ed9e65..000000000
--- a/drivers/ugfx/gdisp/st7565/board_st7565_template.h
+++ /dev/null
@@ -1,96 +0,0 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _GDISP_LLD_BOARD_H
9#define _GDISP_LLD_BOARD_H
10
11#include "quantum.h"
12
13#define ST7565_LCD_BIAS ST7565_LCD_BIAS_7
14#define ST7565_COM_SCAN ST7565_COM_SCAN_DEC
15#define ST7565_PAGE_ORDER 0, 1, 2, 3
16/*
17 * Custom page order for several LCD boards, e.g. HEM12864-99
18 * #define ST7565_PAGE_ORDER 4,5,6,7,0,1,2,3
19 */
20
21#define ST7565_A0_PIN C7
22#define ST7565_RST_PIN C8
23#define ST7565_MOSI_PIN C6
24#define ST7565_SCLK_PIN C5
25#define ST7565_SS_PIN C4
26
27// DSPI Clock and Transfer Attributes
28// Frame Size: 8 bits
29// MSB First
30// CLK Low by default
31static const SPIConfig spi1config = {
32 // Operation complete callback or @p NULL.
33 .end_cb = NULL,
34 // The chip select line port - when not using pcs.
35 .ssport = PAL_PORT(ST7565_SS_PIN),
36 // brief The chip select line pad number - when not using pcs.
37 .sspad = PAL_PAD(ST7565_SS_PIN),
38 // SPI initialization data.
39 .tar0 = SPIx_CTARn_FMSZ(7) // Frame size = 8 bytes
40 | SPIx_CTARn_ASC(1) // After SCK Delay Scaler (min 50 ns) = 55.56ns
41 | SPIx_CTARn_DT(0) // Delay After Transfer Scaler (no minimum)= 27.78ns
42 | SPIx_CTARn_CSSCK(0) // PCS to SCK Delay Scaler (min 20 ns) = 27.78ns
43 | SPIx_CTARn_PBR(0) // Baud Rate Prescaler = 2
44 | SPIx_CTARn_BR(0) // Baud rate (min 50ns) = 55.56ns
45};
46
47static GFXINLINE void acquire_bus(GDisplay *g) {
48 (void)g;
49 // Only the LCD is using the SPI bus, so no need to acquire
50 // spiAcquireBus(&SPID1);
51 spiSelect(&SPID1);
52}
53
54static GFXINLINE void release_bus(GDisplay *g) {
55 (void)g;
56 // Only the LCD is using the SPI bus, so no need to release
57 // spiReleaseBus(&SPID1);
58 spiUnselect(&SPID1);
59}
60
61static GFXINLINE void init_board(GDisplay *g) {
62 (void)g;
63 setPinOutput(ST7565_A0_PIN);
64 writePinHigh(ST7565_A0_PIN);
65 setPinOutput(ST7565_RST_PIN);
66 writePinHigh(ST7565_RST_PIN);
67 setPinOutput(ST7565_SS_PIN);
68
69 palSetPadMode(PAL_PORT(ST7565_MOSI_PIN), PAL_PAD(ST7565_MOSI_PIN), PAL_MODE_ALTERNATIVE_2);
70 palSetPadMode(PAL_PORT(ST7565_SCLK_PIN), PAL_PAD(ST7565_SCLK_PIN), PAL_MODE_ALTERNATIVE_2);
71
72 spiInit();
73 spiStart(&SPID1, &spi1config);
74 release_bus(g);
75}
76
77static GFXINLINE void post_init_board(GDisplay *g) { (void)g; }
78
79static GFXINLINE void setpin_reset(GDisplay *g, bool_t state) {
80 (void)g;
81 writePin(ST7565_RST_PIN, !state);
82}
83
84static GFXINLINE void write_cmd(GDisplay *g, gU8 cmd) {
85 (void)g;
86 writePinLow(ST7565_A0_PIN);
87 spiSend(&SPID1, 1, &cmd);
88}
89
90static GFXINLINE void write_data(GDisplay *g, gU8 *data, gU16 length) {
91 (void)g;
92 writePinHigh(ST7565_A0_PIN);
93 spiSend(&SPID1, length, data);
94}
95
96#endif /* _GDISP_LLD_BOARD_H */
diff --git a/drivers/ugfx/gdisp/st7565/driver.mk b/drivers/ugfx/gdisp/st7565/driver.mk
deleted file mode 100644
index 799a986b0..000000000
--- a/drivers/ugfx/gdisp/st7565/driver.mk
+++ /dev/null
@@ -1,3 +0,0 @@
1GFXINC += drivers/ugfx/gdisp/st7565
2GFXSRC += drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
3GDISP_DRIVER_LIST += GDISPVMT_ST7565_QMK
diff --git a/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c b/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
deleted file mode 100644
index f586f97e3..000000000
--- a/drivers/ugfx/gdisp/st7565/gdisp_lld_ST7565.c
+++ /dev/null
@@ -1,314 +0,0 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#include "gfx.h"
9
10#if GFX_USE_GDISP
11
12# define GDISP_DRIVER_VMT GDISPVMT_ST7565_QMK
13# include "gdisp_lld_config.h"
14# include "src/gdisp/gdisp_driver.h"
15
16# include "board_st7565.h"
17
18/*===========================================================================*/
19/* Driver local definitions. */
20/*===========================================================================*/
21
22# ifndef GDISP_SCREEN_HEIGHT
23# define GDISP_SCREEN_HEIGHT LCD_HEIGHT
24# endif
25# ifndef GDISP_SCREEN_WIDTH
26# define GDISP_SCREEN_WIDTH LCD_WIDTH
27# endif
28# ifndef GDISP_INITIAL_CONTRAST
29# define GDISP_INITIAL_CONTRAST 35
30# endif
31# ifndef GDISP_INITIAL_BACKLIGHT
32# define GDISP_INITIAL_BACKLIGHT 100
33# endif
34
35# define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0)
36
37# include "st7565.h"
38
39/*===========================================================================*/
40/* Driver config defaults for backward compatibility. */
41/*===========================================================================*/
42# ifndef ST7565_LCD_BIAS
43# define ST7565_LCD_BIAS ST7565_LCD_BIAS_7
44# endif
45# ifndef ST7565_ADC
46# define ST7565_ADC ST7565_ADC_NORMAL
47# endif
48# ifndef ST7565_COM_SCAN
49# define ST7565_COM_SCAN ST7565_COM_SCAN_INC
50# endif
51# ifndef ST7565_PAGE_ORDER
52# define ST7565_PAGE_ORDER 0, 1, 2, 3, 4, 5, 6, 7
53# endif
54
55/*===========================================================================*/
56/* Driver local functions. */
57/*===========================================================================*/
58
59// Some common routines and macros
60# define RAM(g) ((gU8 *)g->priv)
61# define write_cmd2(g, cmd1, cmd2) \
62 { \
63 write_cmd(g, cmd1); \
64 write_cmd(g, cmd2); \
65 }
66# define write_cmd3(g, cmd1, cmd2, cmd3) \
67 { \
68 write_cmd(g, cmd1); \
69 write_cmd(g, cmd2); \
70 write_cmd(g, cmd3); \
71 }
72
73// Some common routines and macros
74# define delay(us) gfxSleepMicroseconds(us)
75# define delay_ms(ms) gfxSleepMilliseconds(ms)
76
77# define xyaddr(x, y) ((x) + ((y) >> 3) * GDISP_SCREEN_WIDTH)
78# define xybit(y) (1 << ((y)&7))
79
80/*===========================================================================*/
81/* Driver exported functions. */
82/*===========================================================================*/
83
84/*
85 * As this controller can't update on a pixel boundary we need to maintain the
86 * the entire display surface in memory so that we can do the necessary bit
87 * operations. Fortunately it is a small display in monochrome.
88 * 64 * 128 / 8 = 1024 bytes.
89 */
90
91LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
92 // The private area is the display surface.
93 g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8);
94 if (!g->priv) {
95 return gFalse;
96 }
97
98 // Initialise the board interface
99 init_board(g);
100
101 // Hardware reset
102 setpin_reset(g, TRUE);
103 gfxSleepMilliseconds(20);
104 setpin_reset(g, FALSE);
105 gfxSleepMilliseconds(20);
106 acquire_bus(g);
107
108 write_cmd(g, ST7565_LCD_BIAS);
109 write_cmd(g, ST7565_ADC);
110 write_cmd(g, ST7565_COM_SCAN);
111
112 write_cmd(g, ST7565_START_LINE | 0);
113
114 write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST * 64 / 101);
115 write_cmd(g, ST7565_RESISTOR_RATIO | 0x1);
116
117 // turn on voltage converter (VC=1, VR=0, VF=0)
118 write_cmd(g, ST7565_POWER_CONTROL | 0x04);
119 delay_ms(50);
120
121 // turn on voltage regulator (VC=1, VR=1, VF=0)
122 write_cmd(g, ST7565_POWER_CONTROL | 0x06);
123 delay_ms(50);
124
125 // turn on voltage follower (VC=1, VR=1, VF=1)
126 write_cmd(g, ST7565_POWER_CONTROL | 0x07);
127 delay_ms(50);
128
129 write_cmd(g, ST7565_DISPLAY_ON);
130 write_cmd(g, ST7565_ALLON_NORMAL);
131 write_cmd(g, ST7565_INVERT_DISPLAY); // Disable Inversion of display.
132
133 write_cmd(g, ST7565_RMW);
134
135 // Finish Init
136 post_init_board(g);
137
138 // Release the bus
139 release_bus(g);
140
141 /* Initialise the GDISP structure */
142 g->g.Width = GDISP_SCREEN_WIDTH;
143 g->g.Height = GDISP_SCREEN_HEIGHT;
144 g->g.Orientation = GDISP_ROTATE_0;
145 g->g.Powermode = powerOff;
146 g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
147 g->g.Contrast = GDISP_INITIAL_CONTRAST;
148 return TRUE;
149}
150
151# if GDISP_HARDWARE_FLUSH
152LLDSPEC void gdisp_lld_flush(GDisplay *g) {
153 unsigned p;
154
155 // Don't flush if we don't need it.
156 if (!(g->flags & GDISP_FLG_NEEDFLUSH)) return;
157
158 acquire_bus(g);
159 gU8 pagemap[] = {ST7565_PAGE_ORDER};
160 for (p = 0; p < sizeof(pagemap); p++) {
161 write_cmd(g, ST7565_PAGE | pagemap[p]);
162 write_cmd(g, ST7565_COLUMN_MSB | 0);
163 write_cmd(g, ST7565_COLUMN_LSB | 0);
164 write_cmd(g, ST7565_RMW);
165 write_data(g, RAM(g) + (p * GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH);
166 }
167 release_bus(g);
168
169 g->flags &= ~GDISP_FLG_NEEDFLUSH;
170}
171# endif
172
173# if GDISP_HARDWARE_DRAWPIXEL
174LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
175 coord_t x, y;
176
177 switch (g->g.Orientation) {
178 default:
179 case GDISP_ROTATE_0:
180 x = g->p.x;
181 y = g->p.y;
182 break;
183 case GDISP_ROTATE_90:
184 x = g->p.y;
185 y = GDISP_SCREEN_HEIGHT - 1 - g->p.x;
186 break;
187 case GDISP_ROTATE_180:
188 x = GDISP_SCREEN_WIDTH - 1 - g->p.x;
189 y = GDISP_SCREEN_HEIGHT - 1 - g->p.y;
190 break;
191 case GDISP_ROTATE_270:
192 x = GDISP_SCREEN_HEIGHT - 1 - g->p.y;
193 y = g->p.x;
194 break;
195 }
196 if (gdispColor2Native(g->p.color) != Black)
197 RAM(g)[xyaddr(x, y)] |= xybit(y);
198 else
199 RAM(g)[xyaddr(x, y)] &= ~xybit(y);
200 g->flags |= GDISP_FLG_NEEDFLUSH;
201}
202# endif
203
204# if GDISP_HARDWARE_PIXELREAD
205LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
206 coord_t x, y;
207
208 switch (g->g.Orientation) {
209 default:
210 case GDISP_ROTATE_0:
211 x = g->p.x;
212 y = g->p.y;
213 break;
214 case GDISP_ROTATE_90:
215 x = g->p.y;
216 y = GDISP_SCREEN_HEIGHT - 1 - g->p.x;
217 break;
218 case GDISP_ROTATE_180:
219 x = GDISP_SCREEN_WIDTH - 1 - g->p.x;
220 y = GDISP_SCREEN_HEIGHT - 1 - g->p.y;
221 break;
222 case GDISP_ROTATE_270:
223 x = GDISP_SCREEN_HEIGHT - 1 - g->p.y;
224 y = g->p.x;
225 break;
226 }
227 return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black;
228}
229# endif
230
231# if GDISP_HARDWARE_BITFILLS
232LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
233 uint8_t *buffer = (uint8_t *)g->p.ptr;
234 int linelength = g->p.cx;
235 for (int i = 0; i < g->p.cy; i++) {
236 unsigned dstx = g->p.x;
237 unsigned dsty = g->p.y + i;
238 unsigned srcx = g->p.x1;
239 unsigned srcy = g->p.y1 + i;
240 unsigned srcbit = srcy * g->p.x2 + srcx;
241 for (int j = 0; j < linelength; j++) {
242 uint8_t src = buffer[srcbit / 8];
243 uint8_t bit = 7 - (srcbit % 8);
244 uint8_t bitset = (src >> bit) & 1;
245 uint8_t *dst = &(RAM(g)[xyaddr(dstx, dsty)]);
246 if (bitset) {
247 *dst |= xybit(dsty);
248 } else {
249 *dst &= ~xybit(dsty);
250 }
251 dstx++;
252 srcbit++;
253 }
254 }
255 g->flags |= GDISP_FLG_NEEDFLUSH;
256}
257# endif
258
259# if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
260LLDSPEC void gdisp_lld_control(GDisplay *g) {
261 switch (g->p.x) {
262 case GDISP_CONTROL_POWER:
263 if (g->g.Powermode == (powermode_t)g->p.ptr) return;
264 switch ((powermode_t)g->p.ptr) {
265 case powerOff:
266 case powerSleep:
267 case powerDeepSleep:
268 acquire_bus(g);
269 write_cmd(g, ST7565_DISPLAY_OFF);
270 release_bus(g);
271 break;
272 case powerOn:
273 acquire_bus(g);
274 write_cmd(g, ST7565_DISPLAY_ON);
275 release_bus(g);
276 break;
277 default:
278 return;
279 }
280 g->g.Powermode = (powermode_t)g->p.ptr;
281 return;
282
283 case GDISP_CONTROL_ORIENTATION:
284 if (g->g.Orientation == (orientation_t)g->p.ptr) return;
285 switch ((orientation_t)g->p.ptr) {
286 /* Rotation is handled by the drawing routines */
287 case GDISP_ROTATE_0:
288 case GDISP_ROTATE_180:
289 g->g.Height = GDISP_SCREEN_HEIGHT;
290 g->g.Width = GDISP_SCREEN_WIDTH;
291 break;
292 case GDISP_ROTATE_90:
293 case GDISP_ROTATE_270:
294 g->g.Height = GDISP_SCREEN_WIDTH;
295 g->g.Width = GDISP_SCREEN_HEIGHT;
296 break;
297 default:
298 return;
299 }
300 g->g.Orientation = (orientation_t)g->p.ptr;
301 return;
302
303 case GDISP_CONTROL_CONTRAST:
304 if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
305 acquire_bus(g);
306 write_cmd2(g, ST7565_CONTRAST, ((((unsigned)g->p.ptr) << 6) / 101) & 0x3F);
307 release_bus(g);
308 g->g.Contrast = (unsigned)g->p.ptr;
309 return;
310 }
311}
312# endif // GDISP_NEED_CONTROL
313
314#endif // GFX_USE_GDISP
diff --git a/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h b/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h
deleted file mode 100644
index 6052058ec..000000000
--- a/drivers/ugfx/gdisp/st7565/gdisp_lld_config.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _GDISP_LLD_CONFIG_H
9#define _GDISP_LLD_CONFIG_H
10
11#if GFX_USE_GDISP
12
13/*===========================================================================*/
14/* Driver hardware support. */
15/*===========================================================================*/
16
17# define GDISP_HARDWARE_FLUSH GFXON // This controller requires flushing
18# define GDISP_HARDWARE_DRAWPIXEL GFXON
19# define GDISP_HARDWARE_PIXELREAD GFXON
20# define GDISP_HARDWARE_CONTROL GFXON
21# define GDISP_HARDWARE_BITFILLS GFXON
22
23# define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO
24
25#endif /* GFX_USE_GDISP */
26
27#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/drivers/ugfx/gdisp/st7565/st7565.h b/drivers/ugfx/gdisp/st7565/st7565.h
deleted file mode 100644
index 3c77a8856..000000000
--- a/drivers/ugfx/gdisp/st7565/st7565.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * This file is subject to the terms of the GFX License. If a copy of
3 * the license was not distributed with this file, you can obtain one at:
4 *
5 * http://ugfx.org/license.html
6 */
7
8#ifndef _ST7565_H
9#define _ST7565_H
10
11#define ST7565_CONTRAST 0x81
12#define ST7565_ALLON_NORMAL 0xA4
13#define ST7565_ALLON 0xA5
14#define ST7565_POSITIVE_DISPLAY 0xA6
15#define ST7565_INVERT_DISPLAY 0xA7
16#define ST7565_DISPLAY_OFF 0xAE
17#define ST7565_DISPLAY_ON 0xAF
18
19#define ST7565_LCD_BIAS_7 0xA3
20#define ST7565_LCD_BIAS_9 0xA2
21
22#define ST7565_ADC_NORMAL 0xA0
23#define ST7565_ADC_REVERSE 0xA1
24
25#define ST7565_COM_SCAN_INC 0xC0
26#define ST7565_COM_SCAN_DEC 0xC8
27
28#define ST7565_START_LINE 0x40
29#define ST7565_PAGE 0xB0
30#define ST7565_COLUMN_MSB 0x10
31#define ST7565_COLUMN_LSB 0x00
32#define ST7565_RMW 0xE0
33
34#define ST7565_RESISTOR_RATIO 0x20
35#define ST7565_POWER_CONTROL 0x28
36
37#define ST7565_RESET 0xE2
38
39#endif /* _ST7565_H */
diff --git a/drivers/usb2422.c b/drivers/usb2422.c
new file mode 100644
index 000000000..62b919093
--- /dev/null
+++ b/drivers/usb2422.c
@@ -0,0 +1,402 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include <string.h>
17#include "usb2422.h"
18#include "i2c_master.h"
19#include "wait.h"
20#include "gpio.h"
21
22/* -------- USB2422_VID : (USB2422L Offset: 0x00) (R/W 16) Vendor ID -------- */
23typedef union {
24 struct {
25 uint16_t VID_LSB : 8;
26 uint16_t VID_MSB : 8;
27 } bit; /*!< Structure used for bit access */
28 uint16_t reg; /*!< Type used for register access */
29} USB2422_VID_Type;
30
31/* -------- USB2422_PID : (USB2422L Offset: 0x02) (R/W 16) Product ID -------- */
32typedef union {
33 struct {
34 uint16_t PID_LSB : 8;
35 uint16_t PID_MSB : 8;
36 } bit; /*!< Structure used for bit access */
37 uint16_t reg; /*!< Type used for register access */
38} USB2422_PID_Type;
39
40/* -------- USB2422_DID : (USB2422L Offset: 0x04) (R/W 16) Device ID -------- */
41typedef union {
42 struct {
43 uint16_t DID_LSB : 8;
44 uint16_t DID_MSB : 8;
45 } bit; /*!< Structure used for bit access */
46 uint16_t reg; /*!< Type used for register access */
47} USB2422_DID_Type;
48
49/* -------- USB2422_CFG1 : (USB2422L Offset: 0x06) (R/W 8) Configuration Data Byte 1-------- */
50typedef union {
51 struct {
52 uint8_t PORT_PWR : 1;
53 uint8_t CURRENT_SNS : 2;
54 uint8_t EOP_DISABLE : 1;
55 uint8_t MTT_ENABLE : 1;
56 uint8_t HS_DISABLE : 1;
57 uint8_t : 1;
58 uint8_t SELF_BUS_PWR : 1;
59 } bit; /*!< Structure used for bit access */
60 uint8_t reg; /*!< Type used for register access */
61} USB2422_CFG1_Type;
62
63/* -------- USB2422_CFG2 : (USB2422L Offset: 0x07) (R/W 8) Configuration Data Byte 2-------- */
64typedef union {
65 struct {
66 uint8_t : 3;
67 uint8_t COMPOUND : 1;
68 uint8_t OC_TIMER : 2;
69 uint8_t : 1;
70 uint8_t DYNAMIC : 1;
71 } bit; /*!< Structure used for bit access */
72 uint8_t reg; /*!< Type used for register access */
73} USB2422_CFG2_Type;
74
75/* -------- USB2422_CFG3 : (USB2422L Offset: 0x08) (R/W 16) Configuration Data Byte 3-------- */
76typedef union {
77 struct {
78 uint8_t STRING_EN : 1;
79 uint8_t : 2;
80 uint8_t PRTMAP_EN : 1;
81 uint8_t : 4;
82 } bit; /*!< Structure used for bit access */
83 uint8_t reg; /*!< Type used for register access */
84} USB2422_CFG3_Type;
85
86/* -------- USB2422_NRD : (USB2422L Offset: 0x09) (R/W 8) Non Removable Device -------- */
87typedef union {
88 struct {
89 uint8_t : 5;
90 uint8_t PORT2_NR : 1;
91 uint8_t PORT1_NR : 1;
92 uint8_t : 1;
93 } bit; /*!< Structure used for bit access */
94 uint8_t reg; /*!< Type used for register access */
95} USB2422_NRD_Type;
96
97/* -------- USB2422_PDS : (USB2422L Offset: 0x0A) (R/W 8) Port Diable for Self-Powered Operation -------- */
98typedef union {
99 struct {
100 uint8_t : 1;
101 uint8_t PORT1_DIS : 1;
102 uint8_t PORT2_DIS : 1;
103 uint8_t : 5;
104 } bit; /*!< Structure used for bit access */
105 uint8_t reg; /*!< Type used for register access */
106} USB2422_PDS_Type;
107
108/* -------- USB2422_PDB : (USB2422L Offset: 0x0B) (R/W 8) Port Diable for Bus-Powered Operation -------- */
109
110typedef union {
111 struct {
112 uint8_t : 1;
113 uint8_t PORT1_DIS : 1;
114 uint8_t PORT2_DIS : 1;
115 uint8_t : 5;
116 } bit; /*!< Structure used for bit access */
117 uint8_t reg; /*!< Type used for register access */
118} USB2422_PDB_Type;
119
120/* -------- USB2422_MAXPS : (USB2422L Offset: 0x0C) (R/W 8) Max Power for Self-Powered Operation -------- */
121typedef union {
122 struct {
123 uint8_t MAX_PWR_SP : 8;
124 } bit; /*!< Structure used for bit access */
125 uint8_t reg; /*!< Type used for register access */
126} USB2422_MAXPS_Type;
127
128/* -------- USB2422_MAXPB : (USB2422L Offset: 0x0D) (R/W 8) Max Power for Bus-Powered Operation -------- */
129typedef union {
130 struct {
131 uint8_t MAX_PWR_BP : 8;
132 } bit; /*!< Structure used for bit access */
133 uint8_t reg; /*!< Type used for register access */
134} USB2422_MAXPB_Type;
135
136/* -------- USB2422_HCMCS : (USB2422L Offset: 0x0E) (R/W 8) Hub Controller Max Current for Self-Powered Operation -------- */
137typedef union {
138 struct {
139 uint8_t HC_MAX_C_SP : 8;
140 } bit; /*!< Structure used for bit access */
141 uint8_t reg; /*!< Type used for register access */
142} USB2422_HCMCS_Type;
143
144/* -------- USB2422_HCMCB : (USB2422L Offset: 0x0F) (R/W 8) Hub Controller Max Current for Bus-Powered Operation -------- */
145typedef union {
146 struct {
147 uint8_t HC_MAX_C_BP : 8;
148 } bit; /*!< Structure used for bit access */
149 uint8_t reg; /*!< Type used for register access */
150} USB2422_HCMCB_Type;
151
152/* -------- USB2422_PWRT : (USB2422L Offset: 0x10) (R/W 8) Power On Time -------- */
153typedef union {
154 struct {
155 uint8_t POWER_ON_TIME : 8;
156 } bit; /*!< Structure used for bit access */
157 uint8_t reg; /*!< Type used for register access */
158} USB2422_PWRT_Type;
159
160/* -------- USB2422_LANGID LSB : (USB2422L Offset: 0x11) (R/W 16) Language ID -------- */
161typedef union {
162 struct {
163 uint8_t LANGID_LSB : 8;
164 } bit; /*!< Structure used for bit access */
165 uint8_t reg; /*!< Type used for register access */
166} USB2422_LANGID_LSB_Type;
167
168/* -------- USB2422_LANGID MSB : (USB2422L Offset: 0x12) (R/W 16) Language ID -------- */
169typedef union {
170 struct {
171 uint8_t LANGID_MSB : 8;
172 } bit; /*!< Structure used for bit access */
173 uint8_t reg; /*!< Type used for register access */
174} USB2422_LANGID_MSB_Type;
175
176/* -------- USB2422_MFRSL : (USB2422L Offset: 0x13) (R/W 8) Manufacturer String Length -------- */
177typedef union {
178 struct {
179 uint8_t MFR_STR_LEN : 8;
180 } bit; /*!< Structure used for bit access */
181 uint8_t reg; /*!< Type used for register access */
182} USB2422_MFRSL_Type;
183
184/* -------- USB2422_PRDSL : (USB2422L Offset: 0x14) (R/W 8) Product String Length -------- */
185typedef union {
186 struct {
187 uint8_t PRD_STR_LEN : 8;
188 } bit; /*!< Structure used for bit access */
189 uint8_t reg; /*!< Type used for register access */
190} USB2422_PRDSL_Type;
191
192/* -------- USB2422_SERSL : (USB2422L Offset: 0x15) (R/W 8) Serial String Length -------- */
193typedef union {
194 struct {
195 uint8_t SER_STR_LEN : 8;
196 } bit; /*!< Structure used for bit access */
197 uint8_t reg; /*!< Type used for register access */
198} USB2422_SERSL_Type;
199
200/* -------- USB2422_MFRSTR : (USB2422L Offset: 0x16-53) (R/W 8) Maufacturer String -------- */
201typedef uint16_t USB2422_MFRSTR_Type;
202
203/* -------- USB2422_PRDSTR : (USB2422L Offset: 0x54-91) (R/W 8) Product String -------- */
204typedef uint16_t USB2422_PRDSTR_Type;
205
206/* -------- USB2422_SERSTR : (USB2422L Offset: 0x92-CF) (R/W 8) Serial String -------- */
207typedef uint16_t USB2422_SERSTR_Type;
208
209/* -------- USB2422_BCEN : (USB2422L Offset: 0xD0) (R/W 8) Battery Charging Enable -------- */
210
211typedef union {
212 struct {
213 uint8_t : 1;
214 uint8_t PORT1_BCE : 1;
215 uint8_t PORT2_BCE : 1;
216 uint8_t : 5;
217 } bit; /*!< Structure used for bit access */
218 uint8_t reg; /*!< Type used for register access */
219} USB2422_BCEN_Type;
220
221/* -------- USB2422_BOOSTUP : (USB2422L Offset: 0xF6) (R/W 8) Boost Upstream -------- */
222typedef union {
223 struct {
224 uint8_t BOOST : 2;
225 uint8_t : 6;
226 } bit; /*!< Structure used for bit access */
227 uint8_t reg; /*!< Type used for register access */
228} USB2422_BOOSTUP_Type;
229
230/* -------- USB2422_BOOSTDOWN : (USB2422L Offset: 0xF8) (R/W 8) Boost Downstream -------- */
231typedef union {
232 struct {
233 uint8_t BOOST1 : 2;
234 uint8_t BOOST2 : 2;
235 uint8_t : 4;
236 } bit; /*!< Structure used for bit access */
237 uint8_t reg; /*!< Type used for register access */
238} USB2422_BOOSTDOWN_Type;
239
240/* -------- USB2422_PRTSP : (USB2422L Offset: 0xFA) (R/W 8) Port Swap -------- */
241typedef union {
242 struct {
243 uint8_t : 1;
244 uint8_t PORT1_SP : 1;
245 uint8_t PORT2_SP : 1;
246 uint8_t : 5;
247 } bit; /*!< Structure used for bit access */
248 uint8_t reg; /*!< Type used for register access */
249} USB2422_PRTSP_Type;
250
251/* -------- USB2422_PRTR12 : (USB2422L Offset: 0xFB) (R/W 8) Port 1/2 Remap -------- */
252typedef union {
253 struct {
254 uint8_t PORT1_REMAP : 4;
255 uint8_t PORT2_REMAP : 4;
256 } bit; /*!< Structure used for bit access */
257 uint8_t reg; /*!< Type used for register access */
258} USB2422_PRTR12_Type;
259
260#define USB2422_PRTR12_DISABLE 0
261#define USB2422_PRT12_P2TOL1 1
262#define USB2422_PRT12_P2XTOL2 2
263#define USB2422_PRT12_P1TOL1 1
264#define USB2422_PRT12_P1XTOL2 2
265
266/* -------- USB2422_STCD : (USB2422L Offset: 0xFF) (R/W 8) Status Command -------- */
267typedef union {
268 struct {
269 uint8_t USB_ATTACH : 1;
270 uint8_t RESET : 1;
271 uint8_t INTF_PWRDN : 1;
272 uint8_t : 5;
273 } bit; /*!< Structure used for bit access */
274 uint8_t reg; /*!< Type used for register access */
275} USB2422_STCD_Type;
276
277/** \brief USB2422 device hardware registers */
278typedef struct {
279 USB2422_VID_Type VID; /**< \brief Offset: 0x00*/
280 USB2422_PID_Type PID; /**< \brief Offset: 0x02*/
281 USB2422_DID_Type DID; /**< \brief Offset: 0x04*/
282 USB2422_CFG1_Type CFG1; /**< \brief Offset: 0x06*/
283 USB2422_CFG2_Type CFG2; /**< \brief Offset: 0x07*/
284 USB2422_CFG3_Type CFG3; /**< \brief Offset: 0x08*/
285 USB2422_NRD_Type NRD; /**< \brief Offset: 0x09*/
286 USB2422_PDS_Type PDS; /**< \brief Offset: 0x0A*/
287 USB2422_PDB_Type PDB; /**< \brief Offset: 0x0B*/
288 USB2422_MAXPS_Type MAXPS; /**< \brief Offset: 0x0C*/
289 USB2422_MAXPB_Type MAXPB; /**< \brief Offset: 0x0D*/
290 USB2422_HCMCS_Type HCMCS; /**< \brief Offset: 0x0E*/
291 USB2422_HCMCB_Type HCMCB; /**< \brief Offset: 0x0F*/
292 USB2422_PWRT_Type PWRT; /**< \brief Offset: 0x10*/
293 USB2422_LANGID_LSB_Type LANGID_LSB; /**< \brief Offset: 0x11*/
294 USB2422_LANGID_MSB_Type LANGID_MSB; /**< \brief Offset: 0x12*/
295 USB2422_MFRSL_Type MFRSL; /**< \brief Offset: 0x13*/
296 USB2422_PRDSL_Type PRDSL; /**< \brief Offset: 0x14*/
297 USB2422_SERSL_Type SERSL; /**< \brief Offset: 0x15*/
298 USB2422_MFRSTR_Type MFRSTR[31]; /**< \brief Offset: 0x16*/
299 USB2422_PRDSTR_Type PRDSTR[31]; /**< \brief Offset: 0x54*/
300 USB2422_SERSTR_Type SERSTR[31]; /**< \brief Offset: 0x92*/
301 USB2422_BCEN_Type BCEN; /**< \brief Offset: 0xD0*/
302 uint8_t Reserved1[0x25];
303 USB2422_BOOSTUP_Type BOOSTUP; /**< \brief Offset: 0xF6*/
304 uint8_t Reserved2[0x1];
305 USB2422_BOOSTDOWN_Type BOOSTDOWN; /**< \brief Offset: 0xF8*/
306 uint8_t Reserved3[0x1];
307 USB2422_PRTSP_Type PRTSP; /**< \brief Offset: 0xFA*/
308 USB2422_PRTR12_Type PRTR12; /**< \brief Offset: 0xFB*/
309 uint8_t Reserved4[0x3];
310 USB2422_STCD_Type STCD; /**< \brief Offset: 0xFF*/
311} Usb2422_t;
312
313// ***************************************************************
314
315static Usb2422_t config;
316
317// ***************************************************************
318
319/** \brief Handle the conversion to allow simple strings
320 */
321static void USB2422_strcpy(const char* str, USB2422_MFRSTR_Type* dest, uint8_t len) {
322 for (uint8_t i = 0; i < len; i++) {
323 dest[i] = str[i];
324 }
325}
326
327/** \brief Handle the conversion to allow simple strings
328 */
329static void USB2422_write_block(void) {
330 static unsigned char i2c0_buf[34];
331
332 unsigned char* dest = i2c0_buf;
333 unsigned char* src;
334 unsigned char* base = (unsigned char*)&config;
335
336 for (src = base; src < base + 256; src += 32) {
337 dest[0] = src - base;
338 dest[1] = 32;
339 memcpy(&dest[2], src, 32);
340 i2c_transmit(USB2422_ADDRESS, dest, 34, 50000);
341 wait_us(100);
342 }
343}
344
345// ***************************************************************
346
347void USB2422_init() {
348#ifdef USB2422_RESET_PIN
349 setPinOutput(USB2422_RESET_PIN);
350#endif
351#ifdef USB2422_ACTIVE_PIN
352 setPinInput(USB2422_ACTIVE_PIN);
353#endif
354
355 i2c_init(); // IC2 clk must be high at USB2422 reset release time to signal SMB configuration
356}
357
358void USB2422_configure() {
359 static const char SERNAME[] = "Unavailable";
360
361 memset(&config, 0, sizeof(Usb2422_t));
362
363 // configure Usb2422 registers
364 config.VID.reg = USB2422_VENDOR_ID;
365 config.PID.reg = USB2422_PRODUCT_ID;
366 config.DID.reg = USB2422_DEVICE_VER; // BCD format, eg 01.01
367 config.CFG1.bit.SELF_BUS_PWR = 1; // self powered for now
368 config.CFG1.bit.HS_DISABLE = 1; // full or high speed
369 // config.CFG2.bit.COMPOUND = 0; // compound device
370 config.CFG3.bit.STRING_EN = 1; // strings enabled
371 // config.NRD.bit.PORT2_NR = 0; // MCU is non-removable
372 config.MAXPB.reg = 20; // 0mA
373 config.HCMCB.reg = 20; // 0mA
374 config.MFRSL.reg = sizeof(USB2422_MANUFACTURER);
375 config.PRDSL.reg = sizeof(USB2422_PRODUCT);
376 config.SERSL.reg = sizeof(SERNAME);
377 USB2422_strcpy(USB2422_MANUFACTURER, config.MFRSTR, sizeof(USB2422_MANUFACTURER));
378 USB2422_strcpy(USB2422_PRODUCT, config.PRDSTR, sizeof(USB2422_PRODUCT));
379 USB2422_strcpy(SERNAME, config.SERSTR, sizeof(SERNAME));
380 // config.BOOSTUP.bit.BOOST=3; //upstream port
381 // config.BOOSTDOWN.bit.BOOST1=0; // extra port
382 // config.BOOSTDOWN.bit.BOOST2=2; //MCU is close
383 config.STCD.bit.USB_ATTACH = 1;
384
385 USB2422_write_block();
386}
387
388void USB2422_reset() {
389#ifdef USB2422_RESET_PIN
390 writePinLow(USB2422_RESET_PIN);
391 wait_us(2);
392 writePinHigh(USB2422_RESET_PIN);
393#endif
394}
395
396bool USB2422_active() {
397#ifdef USB2422_ACTIVE_PIN
398 return readPin(USB2422_ACTIVE_PIN);
399#else
400 return 1;
401#endif
402}
diff --git a/drivers/usb2422.h b/drivers/usb2422.h
new file mode 100644
index 000000000..2e435b02b
--- /dev/null
+++ b/drivers/usb2422.h
@@ -0,0 +1,59 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <stdbool.h>
19
20#ifndef USB2422_ADDRESS
21# define USB2422_ADDRESS 0x58
22#endif
23
24#ifndef USB2422_VENDOR_ID
25# define USB2422_VENDOR_ID 0xFEED
26#endif
27#ifndef USB2422_PRODUCT_ID
28# define USB2422_PRODUCT_ID 0x0001
29#endif
30#ifndef USB2422_DEVICE_VER
31# define USB2422_DEVICE_VER 0x0001
32#endif
33
34#ifndef USB2422_MANUFACTURER
35# define USB2422_MANUFACTURER "QMK"
36#endif
37#ifndef USB2422_PRODUCT
38# define USB2422_PRODUCT "QMK Hub"
39#endif
40
41/** \brief Initialises the dependent subsystems */
42void USB2422_init(void);
43
44/** \brief Push configuration to the USB2422 device */
45void USB2422_configure(void);
46
47/** \brief Reset the chip (RESET_N)
48 *
49 * NOTE:
50 * Depends on a valid USB2422_RESET_PIN configuration
51 */
52void USB2422_reset(void);
53
54/** \brief Indicates the USB state of the hub (SUSP_IND)
55 *
56 * NOTE:
57 * Depends on a valid USB2422_ACTIVE_PIN configuration
58 */
59bool USB2422_active(void);