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/haptic/solenoid.c16
-rw-r--r--drivers/haptic/solenoid.h8
-rw-r--r--drivers/led/apa102.c4
-rw-r--r--drivers/led/ckled2001.c226
-rw-r--r--drivers/led/ckled2001.h339
-rw-r--r--drivers/led/issi/is31fl3731-simple.c7
-rw-r--r--drivers/led/issi/is31fl3731.c7
-rw-r--r--drivers/led/issi/is31fl3733.c19
-rw-r--r--drivers/led/issi/is31fl3733.h9
-rw-r--r--drivers/led/issi/is31fl3736.c13
-rw-r--r--drivers/led/issi/is31fl3736.h10
-rw-r--r--drivers/led/issi/is31fl3737.c13
-rw-r--r--drivers/led/issi/is31fl3737.h10
-rw-r--r--drivers/led/issi/is31fl3741.c10
-rw-r--r--drivers/led/issi/is31fl3741.h9
-rw-r--r--drivers/oled/oled_driver.h4
-rw-r--r--drivers/oled/ssd1306_sh1106.c10
-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/sensors/adns5050.c23
-rw-r--r--drivers/sensors/adns5050.h18
-rw-r--r--drivers/sensors/adns9800.c119
-rw-r--r--drivers/sensors/adns9800.h4
-rw-r--r--drivers/sensors/pmw3360.c96
-rw-r--r--drivers/sensors/pmw3360.h19
-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
52 files changed, 3351 insertions, 1859 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/haptic/solenoid.c b/drivers/haptic/solenoid.c
index 25cf34465..7a09940f7 100644
--- a/drivers/haptic/solenoid.c
+++ b/drivers/haptic/solenoid.c
@@ -19,6 +19,7 @@
19#include "solenoid.h" 19#include "solenoid.h"
20#include "haptic.h" 20#include "haptic.h"
21#include "gpio.h" 21#include "gpio.h"
22#include "usb_device_state.h"
22 23
23bool solenoid_on = false; 24bool solenoid_on = false;
24bool solenoid_buzzing = false; 25bool solenoid_buzzing = false;
@@ -36,7 +37,7 @@ void solenoid_set_buzz(int buzz) { haptic_set_buzz(buzz); }
36void solenoid_set_dwell(uint8_t dwell) { solenoid_dwell = dwell; } 37void solenoid_set_dwell(uint8_t dwell) { solenoid_dwell = dwell; }
37 38
38void solenoid_stop(void) { 39void solenoid_stop(void) {
39 writePinLow(SOLENOID_PIN); 40 SOLENOID_PIN_WRITE_INACTIVE();
40 solenoid_on = false; 41 solenoid_on = false;
41 solenoid_buzzing = false; 42 solenoid_buzzing = false;
42} 43}
@@ -48,7 +49,7 @@ void solenoid_fire(void) {
48 solenoid_on = true; 49 solenoid_on = true;
49 solenoid_buzzing = true; 50 solenoid_buzzing = true;
50 solenoid_start = timer_read(); 51 solenoid_start = timer_read();
51 writePinHigh(SOLENOID_PIN); 52 SOLENOID_PIN_WRITE_ACTIVE();
52} 53}
53 54
54void solenoid_check(void) { 55void solenoid_check(void) {
@@ -69,20 +70,23 @@ void solenoid_check(void) {
69 if ((elapsed % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) { 70 if ((elapsed % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) {
70 if (!solenoid_buzzing) { 71 if (!solenoid_buzzing) {
71 solenoid_buzzing = true; 72 solenoid_buzzing = true;
72 writePinHigh(SOLENOID_PIN); 73 SOLENOID_PIN_WRITE_ACTIVE();
73 } 74 }
74 } else { 75 } else {
75 if (solenoid_buzzing) { 76 if (solenoid_buzzing) {
76 solenoid_buzzing = false; 77 solenoid_buzzing = false;
77 writePinLow(SOLENOID_PIN); 78 SOLENOID_PIN_WRITE_INACTIVE();
78 } 79 }
79 } 80 }
80 } 81 }
81} 82}
82 83
83void solenoid_setup(void) { 84void solenoid_setup(void) {
85 SOLENOID_PIN_WRITE_INACTIVE();
84 setPinOutput(SOLENOID_PIN); 86 setPinOutput(SOLENOID_PIN);
85 solenoid_fire(); 87 if ((!HAPTIC_OFF_IN_LOW_POWER) || (usb_device_state == USB_DEVICE_STATE_CONFIGURED)) {
88 solenoid_fire();
89 }
86} 90}
87 91
88void solenoid_shutdown(void) { writePinLow(SOLENOID_PIN); } 92void solenoid_shutdown(void) { SOLENOID_PIN_WRITE_INACTIVE(); }
diff --git a/drivers/haptic/solenoid.h b/drivers/haptic/solenoid.h
index f2a3bc4c3..653148154 100644
--- a/drivers/haptic/solenoid.h
+++ b/drivers/haptic/solenoid.h
@@ -49,6 +49,14 @@
49# error SOLENOID_PIN not defined 49# error SOLENOID_PIN not defined
50#endif 50#endif
51 51
52#ifdef SOLENOID_PIN_ACTIVE_LOW
53# define SOLENOID_PIN_WRITE_ACTIVE() writePinLow(SOLENOID_PIN)
54# define SOLENOID_PIN_WRITE_INACTIVE() writePinHigh(SOLENOID_PIN)
55#else
56# define SOLENOID_PIN_WRITE_ACTIVE() writePinHigh(SOLENOID_PIN)
57# define SOLENOID_PIN_WRITE_INACTIVE() writePinLow(SOLENOID_PIN)
58#endif
59
52void solenoid_buzz_on(void); 60void solenoid_buzz_on(void);
53void solenoid_buzz_off(void); 61void solenoid_buzz_off(void);
54void solenoid_set_buzz(int buzz); 62void solenoid_set_buzz(int buzz);
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/led/ckled2001.c b/drivers/led/ckled2001.c
new file mode 100644
index 000000000..630730343
--- /dev/null
+++ b/drivers/led/ckled2001.c
@@ -0,0 +1,226 @@
1/* Copyright 2021 @ Keychron (https://www.keychron.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
17#include "ckled2001.h"
18#include "i2c_master.h"
19#include "wait.h"
20
21#ifndef CKLED2001_TIMEOUT
22# define CKLED2001_TIMEOUT 100
23#endif
24
25#ifndef CKLED2001_PERSISTENCE
26# define CKLED2001_PERSISTENCE 0
27#endif
28
29#ifndef PHASE_CHANNEL
30# define PHASE_CHANNEL MSKPHASE_12CHANNEL
31#endif
32
33// Transfer buffer for TWITransmitData()
34uint8_t g_twi_transfer_buffer[20];
35
36// These buffers match the CKLED2001 PWM registers.
37// The control buffers match the PG0 LED On/Off registers.
38// Storing them like this is optimal for I2C transfers to the registers.
39// We could optimize this and take out the unused registers from these
40// buffers and the transfers in CKLED2001_write_pwm_buffer() but it's
41// probably not worth the extra complexity.
42uint8_t g_pwm_buffer[DRIVER_COUNT][192];
43bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false};
44
45uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0};
46bool g_led_control_registers_update_required[DRIVER_COUNT] = {false};
47
48bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
49 // If the transaction fails function returns false.
50 g_twi_transfer_buffer[0] = reg;
51 g_twi_transfer_buffer[1] = data;
52
53#if CKLED2001_PERSISTENCE > 0
54 for (uint8_t i = 0; i < CKLED2001_PERSISTENCE; i++) {
55 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, CKLED2001_TIMEOUT) != 0) {
56 return false;
57 }
58 }
59#else
60 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, CKLED2001_TIMEOUT) != 0) {
61 return false;
62 }
63#endif
64 return true;
65}
66
67bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
68 // Assumes PG1 is already selected.
69 // If any of the transactions fails function returns false.
70 // Transmit PWM registers in 12 transfers of 16 bytes.
71 // g_twi_transfer_buffer[] is 20 bytes
72
73 // Iterate over the pwm_buffer contents at 16 byte intervals.
74 for (int i = 0; i < 192; i += 16) {
75 g_twi_transfer_buffer[0] = i;
76 // Copy the data from i to i+15.
77 // Device will auto-increment register for data after the first byte
78 // Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
79 for (int j = 0; j < 16; j++) {
80 g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
81 }
82
83#if CKLED2001_PERSISTENCE > 0
84 for (uint8_t i = 0; i < CKLED2001_PERSISTENCE; i++) {
85 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, CKLED2001_TIMEOUT) != 0) {
86 return false;
87 }
88 }
89#else
90 if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, CKLED2001_TIMEOUT) != 0) {
91 return false;
92 }
93#endif
94 }
95 return true;
96}
97
98void CKLED2001_init(uint8_t addr) {
99 // Select to function page
100 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE);
101 // Setting LED driver to shutdown mode
102 CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE);
103 // Setting internal channel pulldown/pullup
104 CKLED2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL);
105 // Select number of scan phase
106 CKLED2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL);
107 // Setting PWM Delay Phase
108 CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE);
109 // Setting Driving/Sinking Channel Slew Rate
110 CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE);
111 // Setting Iref
112 CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE);
113 // Set LED CONTROL PAGE (Page 0)
114 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE);
115 for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) {
116 CKLED2001_write_register(addr, i, 0x00);
117 }
118
119 // Set PWM PAGE (Page 1)
120 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE);
121 for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) {
122 CKLED2001_write_register(addr, i, 0x00);
123 }
124
125 // Set CURRENT PAGE (Page 4)
126 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE);
127 for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) {
128 CKLED2001_write_register(addr, i, 0xFF);
129 }
130
131 // Enable LEDs ON/OFF
132 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE);
133 for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) {
134 CKLED2001_write_register(addr, i, 0xFF);
135 }
136
137 // Select to function page
138 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE);
139 // Setting LED driver to normal mode
140 CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE);
141}
142
143void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
144 if (index >= 0 && index < DRIVER_LED_TOTAL) {
145 ckled2001_led led = g_ckled2001_leds[index];
146
147 g_pwm_buffer[led.driver][led.r] = red;
148 g_pwm_buffer[led.driver][led.g] = green;
149 g_pwm_buffer[led.driver][led.b] = blue;
150 g_pwm_buffer_update_required[led.driver] = true;
151 }
152}
153
154void CKLED2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
155 for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
156 CKLED2001_set_color(i, red, green, blue);
157 }
158}
159
160void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue) {
161 ckled2001_led led = g_ckled2001_leds[index];
162
163 uint8_t control_register_r = led.r / 8;
164 uint8_t control_register_g = led.g / 8;
165 uint8_t control_register_b = led.b / 8;
166 uint8_t bit_r = led.r % 8;
167 uint8_t bit_g = led.g % 8;
168 uint8_t bit_b = led.b % 8;
169
170 if (red) {
171 g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
172 } else {
173 g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
174 }
175 if (green) {
176 g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
177 } else {
178 g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
179 }
180 if (blue) {
181 g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
182 } else {
183 g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
184 }
185
186 g_led_control_registers_update_required[led.driver] = true;
187}
188
189void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index) {
190 if (g_pwm_buffer_update_required[index]) {
191 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE);
192
193 // If any of the transactions fail we risk writing dirty PG0,
194 // refresh page 0 just in case.
195 if (!CKLED2001_write_pwm_buffer(addr, g_pwm_buffer[index])) {
196 g_led_control_registers_update_required[index] = true;
197 }
198 }
199 g_pwm_buffer_update_required[index] = false;
200}
201
202void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index) {
203 if (g_led_control_registers_update_required[index]) {
204 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE);
205 for (int i = 0; i < 24; i++) {
206 CKLED2001_write_register(addr, i, g_led_control_registers[index][i]);
207 }
208 }
209 g_led_control_registers_update_required[index] = false;
210}
211
212void CKLED2001_return_normal(uint8_t addr) {
213 // Select to function page
214 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE);
215 // Setting LED driver to normal mode
216 CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE);
217}
218
219void CKLED2001_shutdown(uint8_t addr) {
220 // Select to function page
221 CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE);
222 // Setting LED driver to shutdown mode
223 CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE);
224 // Write SW Sleep Register
225 CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE);
226}
diff --git a/drivers/led/ckled2001.h b/drivers/led/ckled2001.h
new file mode 100644
index 000000000..efe399690
--- /dev/null
+++ b/drivers/led/ckled2001.h
@@ -0,0 +1,339 @@
1/* Copyright 2021 @ Keychron (https://www.keychron.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
17#pragma once
18
19#include <stdint.h>
20#include <stdbool.h>
21#include "progmem.h"
22
23typedef struct ckled2001_led {
24 uint8_t driver : 2;
25 uint8_t r;
26 uint8_t g;
27 uint8_t b;
28} __attribute__((packed)) ckled2001_led;
29
30extern const ckled2001_led __flash g_ckled2001_leds[DRIVER_LED_TOTAL];
31
32void CKLED2001_init(uint8_t addr);
33bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data);
34bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
35
36void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
37void CKLED2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
38
39void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue);
40
41// This should not be called from an interrupt
42// (eg. from a timer interrupt).
43// Call this while idle (in between matrix scans).
44// If the buffer is dirty, it will update the driver with the buffer.
45void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index);
46void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index);
47
48void CKLED2001_return_normal(uint8_t addr);
49void CKLED2001_shutdown(uint8_t addr);
50
51// Registers Page Define
52#define CONFIGURE_CMD_PAGE 0xFD
53#define LED_CONTROL_PAGE 0x00
54#define LED_PWM_PAGE 0x01
55#define FUNCTION_PAGE 0x03
56#define CURRENT_TUNE_PAGE 0x04
57
58// Function Register: address 0x00
59#define CONFIGURATION_REG 0x00
60#define MSKSW_SHUT_DOWN_MODE (0x0 << 0)
61#define MSKSW_NORMAL_MODE (0x1 << 0)
62
63#define DRIVER_ID_REG 0x11
64#define CKLED2001_ID 0x8A
65
66#define PDU_REG 0x13
67#define MSKSET_CA_CB_CHANNEL 0xAA
68#define MSKCLR_CA_CB_CHANNEL 0x00
69
70#define SCAN_PHASE_REG 0x14
71#define MSKPHASE_12CHANNEL 0x00
72#define MSKPHASE_11CHANNEL 0x01
73#define MSKPHASE_10CHANNEL 0x02
74#define MSKPHASE_9CHANNEL 0x03
75#define MSKPHASE_8CHANNEL 0x04
76#define MSKPHASE_7CHANNEL 0x05
77#define MSKPHASE_6CHANNEL 0x06
78#define MSKPHASE_5CHANNEL 0x07
79#define MSKPHASE_4CHANNEL 0x08
80#define MSKPHASE_3CHANNEL 0x09
81#define MSKPHASE_2CHANNEL 0x0A
82#define MSKPHASE_1CHANNEL 0x0B
83
84#define SLEW_RATE_CONTROL_MODE1_REG 0x15
85#define MSKPWM_DELAY_PHASE_ENABLE 0x04
86#define MSKPWM_DELAY_PHASE_DISABLE 0x00
87
88#define SLEW_RATE_CONTROL_MODE2_REG 0x16
89#define MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE 0xC0
90#define MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_DISABLE 0x00
91
92#define OPEN_SHORT_ENABLE_REG 0x17
93#define MSKOPEN_DETECTION_ENABLE (0x01 << 7)
94#define MSKOPEN_DETECTION_DISABLE (0x00)
95
96#define MSKSHORT_DETECTION_ENABLE (0x01 << 6)
97#define MSKSHORT_DETECTION_DISABLE (0x00)
98
99#define OPEN_SHORT_DUTY_REG 0x18
100#define OPEN_SHORT_FLAG_REG 0x19
101
102#define MSKOPEN_DETECTION_INTERRUPT_ENABLE (0x01 << 7)
103#define MSKOPEN_DETECTION_INTERRUPT_DISABLE (0x00)
104
105#define MSKSHORT_DETECTION_INTERRUPT_ENABLE (0x01 << 6)
106#define MSKSHORT_DETECTION_INTERRUPT_DISABLE (0x00)
107
108#define SOFTWARE_SLEEP_REG 0x1A
109#define MSKSLEEP_ENABLE 0x02
110#define MSKSLEEP_DISABLE 0x00
111
112// LED Control Registers
113#define LED_CONTROL_ON_OFF_FIRST_ADDR 0x0
114#define LED_CONTROL_ON_OFF_LAST_ADDR 0x17
115#define LED_CONTROL_ON_OFF_LENGTH ((LED_CONTROL_ON_OFF_LAST_ADDR - LED_CONTROL_ON_OFF_FIRST_ADDR) + 1)
116
117#define LED_CONTROL_OPEN_FIRST_ADDR 0x18
118#define LED_CONTROL_OPEN_LAST_ADDR 0x2F
119#define LED_CONTROL_OPEN_LENGTH ((LED_CONTROL_OPEN_LAST_ADDR - LED_CONTROL_OPEN_FIRST_ADDR) + 1)
120
121#define LED_CONTROL_SHORT_FIRST_ADDR 0x30
122#define LED_CONTROL_SHORT_LAST_ADDR 0x47
123#define LED_CONTROL_SHORT_LENGTH ((LED_CONTROL_SHORT_LAST_ADDR - LED_CONTROL_SHORT_FIRST_ADDR) + 1)
124
125#define LED_CONTROL_PAGE_LENGTH 0x48
126
127// LED Control Registers
128#define LED_PWM_FIRST_ADDR 0x00
129#define LED_PWM_LAST_ADDR 0xBF
130#define LED_PWM_LENGTH 0xC0
131
132// Current Tune Registers
133#define LED_CURRENT_TUNE_FIRST_ADDR 0x00
134#define LED_CURRENT_TUNE_LAST_ADDR 0x0B
135#define LED_CURRENT_TUNE_LENGTH 0x0C
136
137#define A_1 0x00
138#define A_2 0x01
139#define A_3 0x02
140#define A_4 0x03
141#define A_5 0x04
142#define A_6 0x05
143#define A_7 0x06
144#define A_8 0x07
145#define A_9 0x08
146#define A_10 0x09
147#define A_11 0x0A
148#define A_12 0x0B
149#define A_13 0x0C
150#define A_14 0x0D
151#define A_15 0x0E
152#define A_16 0x0F
153
154#define B_1 0x10
155#define B_2 0x11
156#define B_3 0x12
157#define B_4 0x13
158#define B_5 0x14
159#define B_6 0x15
160#define B_7 0x16
161#define B_8 0x17
162#define B_9 0x18
163#define B_10 0x19
164#define B_11 0x1A
165#define B_12 0x1B
166#define B_13 0x1C
167#define B_14 0x1D
168#define B_15 0x1E
169#define B_16 0x1F
170
171#define C_1 0x20
172#define C_2 0x21
173#define C_3 0x22
174#define C_4 0x23
175#define C_5 0x24
176#define C_6 0x25
177#define C_7 0x26
178#define C_8 0x27
179#define C_9 0x28
180#define C_10 0x29
181#define C_11 0x2A
182#define C_12 0x2B
183#define C_13 0x2C
184#define C_14 0x2D
185#define C_15 0x2E
186#define C_16 0x2F
187
188#define D_1 0x30
189#define D_2 0x31
190#define D_3 0x32
191#define D_4 0x33
192#define D_5 0x34
193#define D_6 0x35
194#define D_7 0x36
195#define D_8 0x37
196#define D_9 0x38
197#define D_10 0x39
198#define D_11 0x3A
199#define D_12 0x3B
200#define D_13 0x3C
201#define D_14 0x3D
202#define D_15 0x3E
203#define D_16 0x3F
204
205#define E_1 0x40
206#define E_2 0x41
207#define E_3 0x42
208#define E_4 0x43
209#define E_5 0x44
210#define E_6 0x45
211#define E_7 0x46
212#define E_8 0x47
213#define E_9 0x48
214#define E_10 0x49
215#define E_11 0x4A
216#define E_12 0x4B
217#define E_13 0x4C
218#define E_14 0x4D
219#define E_15 0x4E
220#define E_16 0x4F
221
222#define F_1 0x50
223#define F_2 0x51
224#define F_3 0x52
225#define F_4 0x53
226#define F_5 0x54
227#define F_6 0x55
228#define F_7 0x56
229#define F_8 0x57
230#define F_9 0x58
231#define F_10 0x59
232#define F_11 0x5A
233#define F_12 0x5B
234#define F_13 0x5C
235#define F_14 0x5D
236#define F_15 0x5E
237#define F_16 0x5F
238
239#define G_1 0x60
240#define G_2 0x61
241#define G_3 0x62
242#define G_4 0x63
243#define G_5 0x64
244#define G_6 0x65
245#define G_7 0x66
246#define G_8 0x67
247#define G_9 0x68
248#define G_10 0x69
249#define G_11 0x6A
250#define G_12 0x6B
251#define G_13 0x6C
252#define G_14 0x6D
253#define G_15 0x6E
254#define G_16 0x6F
255
256#define H_1 0x70
257#define H_2 0x71
258#define H_3 0x72
259#define H_4 0x73
260#define H_5 0x74
261#define H_6 0x75
262#define H_7 0x76
263#define H_8 0x77
264#define H_9 0x78
265#define H_10 0x79
266#define H_11 0x7A
267#define H_12 0x7B
268#define H_13 0x7C
269#define H_14 0x7D
270#define H_15 0x7E
271#define H_16 0x7F
272
273#define I_1 0x80
274#define I_2 0x81
275#define I_3 0x82
276#define I_4 0x83
277#define I_5 0x84
278#define I_6 0x85
279#define I_7 0x86
280#define I_8 0x87
281#define I_9 0x88
282#define I_10 0x89
283#define I_11 0x8A
284#define I_12 0x8B
285#define I_13 0x8C
286#define I_14 0x8D
287#define I_15 0x8E
288#define I_16 0x8F
289
290#define J_1 0x90
291#define J_2 0x91
292#define J_3 0x92
293#define J_4 0x93
294#define J_5 0x94
295#define J_6 0x95
296#define J_7 0x96
297#define J_8 0x97
298#define J_9 0x98
299#define J_10 0x99
300#define J_11 0x9A
301#define J_12 0x9B
302#define J_13 0x9C
303#define J_14 0x9D
304#define J_15 0x9E
305#define J_16 0x9F
306
307#define K_1 0xA0
308#define K_2 0xA1
309#define K_3 0xA2
310#define K_4 0xA3
311#define K_5 0xA4
312#define K_6 0xA5
313#define K_7 0xA6
314#define K_8 0xA7
315#define K_9 0xA8
316#define K_10 0xA9
317#define K_11 0xAA
318#define K_12 0xAB
319#define K_13 0xAC
320#define K_14 0xAD
321#define K_15 0xAE
322#define K_16 0xAF
323
324#define L_1 0xB0
325#define L_2 0xB1
326#define L_3 0xB2
327#define L_4 0xB3
328#define L_5 0xB4
329#define L_6 0xB5
330#define L_7 0xB6
331#define L_8 0xB7
332#define L_9 0xB8
333#define L_10 0xB9
334#define L_11 0xBA
335#define L_12 0xBB
336#define L_13 0xBC
337#define L_14 0xBD
338#define L_15 0xBE
339#define L_16 0xBF \ No newline at end of file
diff --git a/drivers/led/issi/is31fl3731-simple.c b/drivers/led/issi/is31fl3731-simple.c
index d295772f5..9d28ea91d 100644
--- a/drivers/led/issi/is31fl3731-simple.c
+++ b/drivers/led/issi/is31fl3731-simple.c
@@ -1,6 +1,7 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2019 Clueboard 3 * Copyright 2019 Clueboard
4 * Copyright 2021 Doni Crosby
4 * 5 *
5 * This program is free software: you can redistribute it and/or modify 6 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -40,6 +41,9 @@
40 41
41#define ISSI_REG_PICTUREFRAME 0x01 42#define ISSI_REG_PICTUREFRAME 0x01
42 43
44// Not defined in the datasheet -- See AN for IC
45#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2 // Set bit 4 to enable de-ghosting
46
43#define ISSI_REG_SHUTDOWN 0x0A 47#define ISSI_REG_SHUTDOWN 0x0A
44#define ISSI_REG_AUDIOSYNC 0x06 48#define ISSI_REG_AUDIOSYNC 0x06
45 49
@@ -144,6 +148,9 @@ void IS31FL3731_init(uint8_t addr) {
144 148
145 // enable software shutdown 149 // enable software shutdown
146 IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); 150 IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00);
151#ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array
152 IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10);
153#endif
147 154
148 // this delay was copied from other drivers, might not be needed 155 // this delay was copied from other drivers, might not be needed
149 wait_ms(10); 156 wait_ms(10);
diff --git a/drivers/led/issi/is31fl3731.c b/drivers/led/issi/is31fl3731.c
index 110bdc1be..fbf24c30f 100644
--- a/drivers/led/issi/is31fl3731.c
+++ b/drivers/led/issi/is31fl3731.c
@@ -1,5 +1,6 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2021 Doni Crosby
3 * 4 *
4 * This program is free software: you can redistribute it and/or modify 5 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -39,6 +40,9 @@
39 40
40#define ISSI_REG_PICTUREFRAME 0x01 41#define ISSI_REG_PICTUREFRAME 0x01
41 42
43// Not defined in the datasheet -- See AN for IC
44#define ISSI_REG_GHOST_IMAGE_PREVENTION 0xC2 // Set bit 4 to enable de-ghosting
45
42#define ISSI_REG_SHUTDOWN 0x0A 46#define ISSI_REG_SHUTDOWN 0x0A
43#define ISSI_REG_AUDIOSYNC 0x06 47#define ISSI_REG_AUDIOSYNC 0x06
44 48
@@ -132,6 +136,9 @@ void IS31FL3731_init(uint8_t addr) {
132 136
133 // enable software shutdown 137 // enable software shutdown
134 IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); 138 IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00);
139#ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array
140 IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10);
141#endif
135 142
136 // this delay was copied from other drivers, might not be needed 143 // this delay was copied from other drivers, might not be needed
137 wait_ms(10); 144 wait_ms(10);
diff --git a/drivers/led/issi/is31fl3733.c b/drivers/led/issi/is31fl3733.c
index d99e5339c..371010fd8 100644
--- a/drivers/led/issi/is31fl3733.c
+++ b/drivers/led/issi/is31fl3733.c
@@ -1,6 +1,7 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar 3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
4 * 5 *
5 * This program is free software: you can redistribute it and/or modify 6 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -56,6 +57,18 @@
56# define ISSI_PERSISTENCE 0 57# define ISSI_PERSISTENCE 0
57#endif 58#endif
58 59
60#ifndef ISSI_PWM_FREQUENCY
61# define ISSI_PWM_FREQUENCY 0b000 // PFS - IS31FL3733B only
62#endif
63
64#ifndef ISSI_SWPULLUP
65# define ISSI_SWPULLUP PUR_0R
66#endif
67
68#ifndef ISSI_CSPULLUP
69# define ISSI_CSPULLUP PUR_0R
70#endif
71
59// Transfer buffer for TWITransmitData() 72// Transfer buffer for TWITransmitData()
60uint8_t g_twi_transfer_buffer[20]; 73uint8_t g_twi_transfer_buffer[20];
61 74
@@ -154,10 +167,14 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {
154 167
155 // Select PG3 168 // Select PG3
156 IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); 169 IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION);
170 // Set de-ghost pull-up resistors (SWx)
171 IS31FL3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP);
172 // Set de-ghost pull-down resistors (CSx)
173 IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
157 // Set global current to maximum. 174 // Set global current to maximum.
158 IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); 175 IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
159 // Disable software shutdown. 176 // Disable software shutdown.
160 IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, (sync << 6) | 0x01); 177 IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01);
161 178
162 // Wait 10ms to ensure the device has woken up. 179 // Wait 10ms to ensure the device has woken up.
163 wait_ms(10); 180 wait_ms(10);
diff --git a/drivers/led/issi/is31fl3733.h b/drivers/led/issi/is31fl3733.h
index 64fd38eb1..daa226b41 100644
--- a/drivers/led/issi/is31fl3733.h
+++ b/drivers/led/issi/is31fl3733.h
@@ -1,6 +1,7 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar 3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
4 * 5 *
5 * This program is free software: you can redistribute it and/or modify 6 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -47,6 +48,14 @@ void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bo
47void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index); 48void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index);
48void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index); 49void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index);
49 50
51#define PUR_0R 0x00 // No PUR resistor
52#define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL
53#define PUR_3KR 0x03 // 3.0k Ohm resistor on all the time
54#define PUR_4KR 0x04 // 4.0k Ohm resistor on all the time
55#define PUR_8KR 0x05 // 8.0k Ohm resistor on all the time
56#define PUR_16KR 0x06 // 16k Ohm resistor on all the time
57#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL
58
50#define A_1 0x00 59#define A_1 0x00
51#define A_2 0x01 60#define A_2 0x01
52#define A_3 0x02 61#define A_3 0x02
diff --git a/drivers/led/issi/is31fl3736.c b/drivers/led/issi/is31fl3736.c
index 7dece1b1e..dcaabba2e 100644
--- a/drivers/led/issi/is31fl3736.c
+++ b/drivers/led/issi/is31fl3736.c
@@ -1,4 +1,5 @@
1/* Copyright 2018 Jason Williams (Wilba) 1/* Copyright 2018 Jason Williams (Wilba)
2 * Copyright 2021 Doni Crosby
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -54,6 +55,14 @@
54# define ISSI_PERSISTENCE 0 55# define ISSI_PERSISTENCE 0
55#endif 56#endif
56 57
58#ifndef ISSI_SWPULLUP
59# define ISSI_SWPULLUP PUR_0R
60#endif
61
62#ifndef ISSI_CSPULLUP
63# define ISSI_CSPULLUP PUR_0R
64#endif
65
57// Transfer buffer for TWITransmitData() 66// Transfer buffer for TWITransmitData()
58uint8_t g_twi_transfer_buffer[20]; 67uint8_t g_twi_transfer_buffer[20];
59 68
@@ -140,6 +149,10 @@ void IS31FL3736_init(uint8_t addr) {
140 149
141 // Select PG3 150 // Select PG3
142 IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); 151 IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION);
152 // Set de-ghost pull-up resistors (SWx)
153 IS31FL3736_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP);
154 // Set de-ghost pull-down resistors (CSx)
155 IS31FL3736_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
143 // Set global current to maximum. 156 // Set global current to maximum.
144 IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); 157 IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
145 // Disable software shutdown. 158 // Disable software shutdown.
diff --git a/drivers/led/issi/is31fl3736.h b/drivers/led/issi/is31fl3736.h
index c956c87f7..a30be9055 100644
--- a/drivers/led/issi/is31fl3736.h
+++ b/drivers/led/issi/is31fl3736.h
@@ -1,4 +1,5 @@
1/* Copyright 2018 Jason Williams (Wilba) 1/* Copyright 2018 Jason Williams (Wilba)
2 * Copyright 2021 Doni Crosby
2 * 3 *
3 * This program is free software: you can redistribute it and/or modify 4 * 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 * it under the terms of the GNU General Public License as published by
@@ -60,6 +61,15 @@ void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled);
60void IS31FL3736_update_pwm_buffers(uint8_t addr1, uint8_t addr2); 61void IS31FL3736_update_pwm_buffers(uint8_t addr1, uint8_t addr2);
61void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2); 62void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2);
62 63
64#define PUR_0R 0x00 // No PUR resistor
65#define PUR_05KR 0x01 // 0.5k Ohm resistor
66#define PUR_1KR 0x02 // 1.0k Ohm resistor
67#define PUR_2KR 0x03 // 2.0k Ohm resistor
68#define PUR_4KR 0x04 // 4.0k Ohm resistor
69#define PUR_8KR 0x05 // 8.0k Ohm resistor
70#define PUR_16KR 0x06 // 16k Ohm resistor
71#define PUR_32KR 0x07 // 32k Ohm resistor
72
63#define A_1 0x00 73#define A_1 0x00
64#define A_2 0x02 74#define A_2 0x02
65#define A_3 0x04 75#define A_3 0x04
diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c
index 0bb4ddd42..62862e0d4 100644
--- a/drivers/led/issi/is31fl3737.c
+++ b/drivers/led/issi/is31fl3737.c
@@ -1,6 +1,7 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar 3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
4 * 5 *
5 * This program is free software: you can redistribute it and/or modify 6 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -56,6 +57,14 @@
56# define ISSI_PERSISTENCE 0 57# define ISSI_PERSISTENCE 0
57#endif 58#endif
58 59
60#ifndef ISSI_SWPULLUP
61# define ISSI_SWPULLUP PUR_0R
62#endif
63
64#ifndef ISSI_CSPULLUP
65# define ISSI_CSPULLUP PUR_0R
66#endif
67
59// Transfer buffer for TWITransmitData() 68// Transfer buffer for TWITransmitData()
60uint8_t g_twi_transfer_buffer[20]; 69uint8_t g_twi_transfer_buffer[20];
61 70
@@ -143,6 +152,10 @@ void IS31FL3737_init(uint8_t addr) {
143 152
144 // Select PG3 153 // Select PG3
145 IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); 154 IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION);
155 // Set de-ghost pull-up resistors (SWx)
156 IS31FL3737_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP);
157 // Set de-ghost pull-down resistors (CSx)
158 IS31FL3737_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
146 // Set global current to maximum. 159 // Set global current to maximum.
147 IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); 160 IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
148 // Disable software shutdown. 161 // Disable software shutdown.
diff --git a/drivers/led/issi/is31fl3737.h b/drivers/led/issi/is31fl3737.h
index 06886e9c9..97917f1d4 100644
--- a/drivers/led/issi/is31fl3737.h
+++ b/drivers/led/issi/is31fl3737.h
@@ -1,6 +1,7 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert 2 * Copyright 2018 Jack Humbert
3 * Copyright 2018 Yiancar 3 * Copyright 2018 Yiancar
4 * Copyright 2021 Doni Crosby
4 * 5 *
5 * This program is free software: you can redistribute it and/or modify 6 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -47,6 +48,15 @@ void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bo
47void IS31FL3737_update_pwm_buffers(uint8_t addr1, uint8_t addr2); 48void IS31FL3737_update_pwm_buffers(uint8_t addr1, uint8_t addr2);
48void IS31FL3737_update_led_control_registers(uint8_t addr1, uint8_t addr2); 49void IS31FL3737_update_led_control_registers(uint8_t addr1, uint8_t addr2);
49 50
51#define PUR_0R 0x00 // No PUR resistor
52#define PUR_05KR 0x01 // 0.5k Ohm resistor in t_NOL
53#define PUR_1KR 0x02 // 1.0k Ohm resistor in t_NOL
54#define PUR_2KR 0x03 // 2.0k Ohm resistor in t_NOL
55#define PUR_4KR 0x04 // 4.0k Ohm resistor in t_NOL
56#define PUR_8KR 0x05 // 8.0k Ohm resistor in t_NOL
57#define PUR_16KR 0x06 // 16k Ohm resistor in t_NOL
58#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL
59
50#define A_1 0x00 60#define A_1 0x00
51#define A_2 0x01 61#define A_2 0x01
52#define A_3 0x02 62#define A_3 0x02
diff --git a/drivers/led/issi/is31fl3741.c b/drivers/led/issi/is31fl3741.c
index 24a273514..5084f3b9f 100644
--- a/drivers/led/issi/is31fl3741.c
+++ b/drivers/led/issi/is31fl3741.c
@@ -61,6 +61,14 @@
61# define ISSI_PERSISTENCE 0 61# define ISSI_PERSISTENCE 0
62#endif 62#endif
63 63
64#ifndef ISSI_SWPULLUP
65# define ISSI_SWPULLUP PUR_32KR
66#endif
67
68#ifndef ISSI_CSPULLUP
69# define ISSI_CSPULLUP PUR_32KR
70#endif
71
64#define ISSI_MAX_LEDS 351 72#define ISSI_MAX_LEDS 351
65 73
66// Transfer buffer for TWITransmitData() 74// Transfer buffer for TWITransmitData()
@@ -157,7 +165,7 @@ void IS31FL3741_init(uint8_t addr) {
157 // Set Golbal Current Control Register 165 // Set Golbal Current Control Register
158 IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF); 166 IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
159 // Set Pull up & Down for SWx CSy 167 // Set Pull up & Down for SWx CSy
160 IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, 0x77); 168 IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, ((ISSI_CSPULLUP << 4) | ISSI_SWPULLUP));
161 169
162 // IS31FL3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF); 170 // IS31FL3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF);
163 171
diff --git a/drivers/led/issi/is31fl3741.h b/drivers/led/issi/is31fl3741.h
index 163a03523..563022b9b 100644
--- a/drivers/led/issi/is31fl3741.h
+++ b/drivers/led/issi/is31fl3741.h
@@ -51,6 +51,15 @@ void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t
51 51
52void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); 52void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue);
53 53
54#define PUR_0R 0x00 // No PUR resistor
55#define PUR_05KR 0x01 // 0.5k Ohm resistor
56#define PUR_1KR 0x02 // 1.0k Ohm resistor
57#define PUR_2KR 0x03 // 2.0k Ohm resistor
58#define PUR_4KR 0x04 // 4.0k Ohm resistor
59#define PUR_8KR 0x05 // 8.0k Ohm resistor
60#define PUR_16KR 0x06 // 16k Ohm resistor
61#define PUR_32KR 0x07 // 32k Ohm resistor
62
54#define CS1_SW1 0x00 63#define CS1_SW1 0x00
55#define CS2_SW1 0x01 64#define CS2_SW1 0x01
56#define CS3_SW1 0x02 65#define CS3_SW1 0x02
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index 13b73ede9..3b56d370d 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -190,6 +190,7 @@ bool oled_init(oled_rotation_t rotation);
190// Called at the start of oled_init, weak function overridable by the user 190// Called at the start of oled_init, weak function overridable by the user
191// rotation - the value passed into oled_init 191// rotation - the value passed into oled_init
192// Return new oled_rotation_t if you want to override default rotation 192// Return new oled_rotation_t if you want to override default rotation
193oled_rotation_t oled_init_kb(oled_rotation_t rotation);
193oled_rotation_t oled_init_user(oled_rotation_t rotation); 194oled_rotation_t oled_init_user(oled_rotation_t rotation);
194 195
195// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering 196// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
@@ -285,7 +286,8 @@ uint8_t oled_get_brightness(void);
285void oled_task(void); 286void oled_task(void);
286 287
287// Called at the start of oled_task, weak function overridable by the user 288// Called at the start of oled_task, weak function overridable by the user
288void oled_task_user(void); 289bool oled_task_kb(void);
290bool oled_task_user(void);
289 291
290// Set the specific 8 lines rows of the screen to scroll. 292// Set the specific 8 lines rows of the screen to scroll.
291// 0 is the default for start, and 7 for end, which is the entire 293// 0 is the default for start, and 7 for end, which is the entire
diff --git a/drivers/oled/ssd1306_sh1106.c b/drivers/oled/ssd1306_sh1106.c
index e9049438f..d9bd3c14b 100644
--- a/drivers/oled/ssd1306_sh1106.c
+++ b/drivers/oled/ssd1306_sh1106.c
@@ -167,7 +167,7 @@ bool oled_init(oled_rotation_t rotation) {
167 } 167 }
168#endif 168#endif
169 169
170 oled_rotation = oled_init_user(rotation); 170 oled_rotation = oled_init_user(oled_init_kb(rotation));
171 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) { 171 if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
172 oled_rotation_width = OLED_DISPLAY_WIDTH; 172 oled_rotation_width = OLED_DISPLAY_WIDTH;
173 } else { 173 } else {
@@ -232,6 +232,7 @@ bool oled_init(oled_rotation_t rotation) {
232 return true; 232 return true;
233} 233}
234 234
235__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return rotation; }
235__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; } 236__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; }
236 237
237void oled_clear(void) { 238void oled_clear(void) {
@@ -741,11 +742,11 @@ void oled_task(void) {
741 if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) { 742 if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) {
742 oled_update_timeout = timer_read(); 743 oled_update_timeout = timer_read();
743 oled_set_cursor(0, 0); 744 oled_set_cursor(0, 0);
744 oled_task_user(); 745 oled_task_kb();
745 } 746 }
746#else 747#else
747 oled_set_cursor(0, 0); 748 oled_set_cursor(0, 0);
748 oled_task_user(); 749 oled_task_kb();
749#endif 750#endif
750 751
751#if OLED_SCROLL_TIMEOUT > 0 752#if OLED_SCROLL_TIMEOUT > 0
@@ -776,4 +777,5 @@ void oled_task(void) {
776#endif 777#endif
777} 778}
778 779
779__attribute__((weak)) void oled_task_user(void) {} 780__attribute__((weak)) bool oled_task_kb(void) { return oled_task_user(); }
781__attribute__((weak)) bool oled_task_user(void) { return true; }
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/sensors/adns5050.c b/drivers/sensors/adns5050.c
index e7273977d..254ef2ee8 100644
--- a/drivers/sensors/adns5050.c
+++ b/drivers/sensors/adns5050.c
@@ -17,7 +17,6 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20
21#include "adns5050.h" 20#include "adns5050.h"
22#include "wait.h" 21#include "wait.h"
23#include "debug.h" 22#include "debug.h"
@@ -61,13 +60,9 @@ void adns_sync(void) {
61 writePinHigh(ADNS_CS_PIN); 60 writePinHigh(ADNS_CS_PIN);
62} 61}
63 62
64void adns_cs_select(void) { 63void adns_cs_select(void) { writePinLow(ADNS_CS_PIN); }
65 writePinLow(ADNS_CS_PIN);
66}
67 64
68void adns_cs_deselect(void) { 65void adns_cs_deselect(void) { writePinHigh(ADNS_CS_PIN); }
69 writePinHigh(ADNS_CS_PIN);
70}
71 66
72uint8_t adns_serial_read(void) { 67uint8_t adns_serial_read(void) {
73 setPinInput(ADNS_SDIO_PIN); 68 setPinInput(ADNS_SDIO_PIN);
@@ -121,7 +116,7 @@ uint8_t adns_read_reg(uint8_t reg_addr) {
121 // We don't need a minimum tSRAD here. That's because a 4ms wait time is 116 // We don't need a minimum tSRAD here. That's because a 4ms wait time is
122 // already included in adns_serial_write(), so we're good. 117 // already included in adns_serial_write(), so we're good.
123 // See page 10 and 15 of the ADNS spec sheet. 118 // See page 10 and 15 of the ADNS spec sheet.
124 //wait_us(4); 119 // wait_us(4);
125 120
126 uint8_t byte = adns_serial_read(); 121 uint8_t byte = adns_serial_read();
127 122
@@ -138,7 +133,7 @@ uint8_t adns_read_reg(uint8_t reg_addr) {
138 133
139void adns_write_reg(uint8_t reg_addr, uint8_t data) { 134void adns_write_reg(uint8_t reg_addr, uint8_t data) {
140 adns_cs_select(); 135 adns_cs_select();
141 adns_serial_write( 0b10000000 | reg_addr ); 136 adns_serial_write(0b10000000 | reg_addr);
142 adns_serial_write(data); 137 adns_serial_write(data);
143 adns_cs_deselect(); 138 adns_cs_deselect();
144} 139}
@@ -155,7 +150,7 @@ report_adns_t adns_read_burst(void) {
155 // We don't need a minimum tSRAD here. That's because a 4ms wait time is 150 // We don't need a minimum tSRAD here. That's because a 4ms wait time is
156 // already included in adns_serial_write(), so we're good. 151 // already included in adns_serial_write(), so we're good.
157 // See page 10 and 15 of the ADNS spec sheet. 152 // See page 10 and 15 of the ADNS spec sheet.
158 //wait_us(4); 153 // wait_us(4);
159 154
160 uint8_t x = adns_serial_read(); 155 uint8_t x = adns_serial_read();
161 uint8_t y = adns_serial_read(); 156 uint8_t y = adns_serial_read();
@@ -180,13 +175,11 @@ int8_t convert_twoscomp(uint8_t data) {
180} 175}
181 176
182// Don't forget to use the definitions for CPI in the header file. 177// Don't forget to use the definitions for CPI in the header file.
183void adns_set_cpi(uint8_t cpi) { 178void adns_set_cpi(uint8_t cpi) { adns_write_reg(REG_MOUSE_CONTROL2, cpi); }
184 adns_write_reg(REG_MOUSE_CONTROL2, cpi);
185}
186 179
187bool adns_check_signature(void) { 180bool adns_check_signature(void) {
188 uint8_t pid = adns_read_reg(REG_PRODUCT_ID); 181 uint8_t pid = adns_read_reg(REG_PRODUCT_ID);
189 uint8_t rid = adns_read_reg(REG_REVISION_ID); 182 uint8_t rid = adns_read_reg(REG_REVISION_ID);
190 uint8_t pid2 = adns_read_reg(REG_PRODUCT_ID2); 183 uint8_t pid2 = adns_read_reg(REG_PRODUCT_ID2);
191 184
192 return (pid == 0x12 && rid == 0x01 && pid2 == 0x26); 185 return (pid == 0x12 && rid == 0x01 && pid2 == 0x26);
diff --git a/drivers/sensors/adns5050.h b/drivers/sensors/adns5050.h
index ff8e8f78e..5e9edc296 100644
--- a/drivers/sensors/adns5050.h
+++ b/drivers/sensors/adns5050.h
@@ -67,13 +67,13 @@ typedef struct {
67// A bunch of functions to implement the ADNS5050-specific serial protocol. 67// A bunch of functions to implement the ADNS5050-specific serial protocol.
68// Note that the "serial.h" driver is insufficient, because it does not 68// Note that the "serial.h" driver is insufficient, because it does not
69// manually manipulate a serial clock signal. 69// manually manipulate a serial clock signal.
70void adns_init(void); 70void adns_init(void);
71void adns_sync(void); 71void adns_sync(void);
72uint8_t adns_serial_read(void); 72uint8_t adns_serial_read(void);
73void adns_serial_write(uint8_t data); 73void adns_serial_write(uint8_t data);
74uint8_t adns_read_reg(uint8_t reg_addr); 74uint8_t adns_read_reg(uint8_t reg_addr);
75void adns_write_reg(uint8_t reg_addr, uint8_t data); 75void adns_write_reg(uint8_t reg_addr, uint8_t data);
76report_adns_t adns_read_burst(void); 76report_adns_t adns_read_burst(void);
77int8_t convert_twoscomp(uint8_t data); 77int8_t convert_twoscomp(uint8_t data);
78void adns_set_cpi(uint8_t cpi); 78void adns_set_cpi(uint8_t cpi);
79bool adns_check_signature(void); 79bool adns_check_signature(void);
diff --git a/drivers/sensors/adns9800.c b/drivers/sensors/adns9800.c
index 17966b81f..b4f683452 100644
--- a/drivers/sensors/adns9800.c
+++ b/drivers/sensors/adns9800.c
@@ -20,57 +20,57 @@
20#include "adns9800.h" 20#include "adns9800.h"
21 21
22// registers 22// registers
23#define REG_Product_ID 0x00 23#define REG_Product_ID 0x00
24#define REG_Revision_ID 0x01 24#define REG_Revision_ID 0x01
25#define REG_Motion 0x02 25#define REG_Motion 0x02
26#define REG_Delta_X_L 0x03 26#define REG_Delta_X_L 0x03
27#define REG_Delta_X_H 0x04 27#define REG_Delta_X_H 0x04
28#define REG_Delta_Y_L 0x05 28#define REG_Delta_Y_L 0x05
29#define REG_Delta_Y_H 0x06 29#define REG_Delta_Y_H 0x06
30#define REG_SQUAL 0x07 30#define REG_SQUAL 0x07
31#define REG_Pixel_Sum 0x08 31#define REG_Pixel_Sum 0x08
32#define REG_Maximum_Pixel 0x09 32#define REG_Maximum_Pixel 0x09
33#define REG_Minimum_Pixel 0x0a 33#define REG_Minimum_Pixel 0x0a
34#define REG_Shutter_Lower 0x0b 34#define REG_Shutter_Lower 0x0b
35#define REG_Shutter_Upper 0x0c 35#define REG_Shutter_Upper 0x0c
36#define REG_Frame_Period_Lower 0x0d 36#define REG_Frame_Period_Lower 0x0d
37#define REG_Frame_Period_Upper 0x0e 37#define REG_Frame_Period_Upper 0x0e
38#define REG_Configuration_I 0x0f 38#define REG_Configuration_I 0x0f
39#define REG_Configuration_II 0x10 39#define REG_Configuration_II 0x10
40#define REG_Frame_Capture 0x12 40#define REG_Frame_Capture 0x12
41#define REG_SROM_Enable 0x13 41#define REG_SROM_Enable 0x13
42#define REG_Run_Downshift 0x14 42#define REG_Run_Downshift 0x14
43#define REG_Rest1_Rate 0x15 43#define REG_Rest1_Rate 0x15
44#define REG_Rest1_Downshift 0x16 44#define REG_Rest1_Downshift 0x16
45#define REG_Rest2_Rate 0x17 45#define REG_Rest2_Rate 0x17
46#define REG_Rest2_Downshift 0x18 46#define REG_Rest2_Downshift 0x18
47#define REG_Rest3_Rate 0x19 47#define REG_Rest3_Rate 0x19
48#define REG_Frame_Period_Max_Bound_Lower 0x1a 48#define REG_Frame_Period_Max_Bound_Lower 0x1a
49#define REG_Frame_Period_Max_Bound_Upper 0x1b 49#define REG_Frame_Period_Max_Bound_Upper 0x1b
50#define REG_Frame_Period_Min_Bound_Lower 0x1c 50#define REG_Frame_Period_Min_Bound_Lower 0x1c
51#define REG_Frame_Period_Min_Bound_Upper 0x1d 51#define REG_Frame_Period_Min_Bound_Upper 0x1d
52#define REG_Shutter_Max_Bound_Lower 0x1e 52#define REG_Shutter_Max_Bound_Lower 0x1e
53#define REG_Shutter_Max_Bound_Upper 0x1f 53#define REG_Shutter_Max_Bound_Upper 0x1f
54#define REG_LASER_CTRL0 0x20 54#define REG_LASER_CTRL0 0x20
55#define REG_Observation 0x24 55#define REG_Observation 0x24
56#define REG_Data_Out_Lower 0x25 56#define REG_Data_Out_Lower 0x25
57#define REG_Data_Out_Upper 0x26 57#define REG_Data_Out_Upper 0x26
58#define REG_SROM_ID 0x2a 58#define REG_SROM_ID 0x2a
59#define REG_Lift_Detection_Thr 0x2e 59#define REG_Lift_Detection_Thr 0x2e
60#define REG_Configuration_V 0x2f 60#define REG_Configuration_V 0x2f
61#define REG_Configuration_IV 0x39 61#define REG_Configuration_IV 0x39
62#define REG_Power_Up_Reset 0x3a 62#define REG_Power_Up_Reset 0x3a
63#define REG_Shutdown 0x3b 63#define REG_Shutdown 0x3b
64#define REG_Inverse_Product_ID 0x3f 64#define REG_Inverse_Product_ID 0x3f
65#define REG_Motion_Burst 0x50 65#define REG_Motion_Burst 0x50
66#define REG_SROM_Load_Burst 0x62 66#define REG_SROM_Load_Burst 0x62
67#define REG_Pixel_Burst 0x64 67#define REG_Pixel_Burst 0x64
68 68
69#define ADNS_CLOCK_SPEED 2000000 69#define ADNS_CLOCK_SPEED 2000000
70#define MIN_CPI 200 70#define MIN_CPI 200
71#define MAX_CPI 8200 71#define MAX_CPI 8200
72#define CPI_STEP 200 72#define CPI_STEP 200
73#define CLAMP_CPI(value) value < MIN_CPI ? MIN_CPI : value > MAX_CPI ? MAX_CPI : value 73#define CLAMP_CPI(value) value<MIN_CPI ? MIN_CPI : value> MAX_CPI ? MAX_CPI : value
74#define SPI_MODE 3 74#define SPI_MODE 3
75#define SPI_DIVISOR (F_CPU / ADNS_CLOCK_SPEED) 75#define SPI_DIVISOR (F_CPU / ADNS_CLOCK_SPEED)
76#define US_BETWEEN_WRITES 120 76#define US_BETWEEN_WRITES 120
@@ -80,12 +80,9 @@
80 80
81extern const uint8_t firmware_data[]; 81extern const uint8_t firmware_data[];
82 82
83void adns_spi_start(void){ 83void adns_spi_start(void) { spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR); }
84 spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR);
85}
86
87void adns_write(uint8_t reg_addr, uint8_t data){
88 84
85void adns_write(uint8_t reg_addr, uint8_t data) {
89 adns_spi_start(); 86 adns_spi_start();
90 spi_write(reg_addr | MSB1); 87 spi_write(reg_addr | MSB1);
91 spi_write(data); 88 spi_write(data);
@@ -93,10 +90,9 @@ void adns_write(uint8_t reg_addr, uint8_t data){
93 wait_us(US_BETWEEN_WRITES); 90 wait_us(US_BETWEEN_WRITES);
94} 91}
95 92
96uint8_t adns_read(uint8_t reg_addr){ 93uint8_t adns_read(uint8_t reg_addr) {
97
98 adns_spi_start(); 94 adns_spi_start();
99 spi_write(reg_addr & 0x7f ); 95 spi_write(reg_addr & 0x7f);
100 uint8_t data = spi_read(); 96 uint8_t data = spi_read();
101 spi_stop(); 97 spi_stop();
102 wait_us(US_BETWEEN_READS); 98 wait_us(US_BETWEEN_READS);
@@ -105,7 +101,6 @@ uint8_t adns_read(uint8_t reg_addr){
105} 101}
106 102
107void adns_init() { 103void adns_init() {
108
109 setPinOutput(SPI_SS_PIN); 104 setPinOutput(SPI_SS_PIN);
110 105
111 spi_init(); 106 spi_init();
@@ -144,7 +139,7 @@ void adns_init() {
144 139
145 // send all bytes of the firmware 140 // send all bytes of the firmware
146 unsigned char c; 141 unsigned char c;
147 for(int i = 0; i < FIRMWARE_LENGTH; i++){ 142 for (int i = 0; i < FIRMWARE_LENGTH; i++) {
148 c = (unsigned char)pgm_read_byte(firmware_data + i); 143 c = (unsigned char)pgm_read_byte(firmware_data + i);
149 spi_write(c); 144 spi_write(c);
150 wait_us(15); 145 wait_us(15);
@@ -161,7 +156,7 @@ void adns_init() {
161 156
162config_adns_t adns_get_config(void) { 157config_adns_t adns_get_config(void) {
163 uint8_t config_1 = adns_read(REG_Configuration_I); 158 uint8_t config_1 = adns_read(REG_Configuration_I);
164 return (config_adns_t){ (config_1 & 0xFF) * CPI_STEP }; 159 return (config_adns_t){(config_1 & 0xFF) * CPI_STEP};
165} 160}
166 161
167void adns_set_config(config_adns_t config) { 162void adns_set_config(config_adns_t config) {
@@ -169,20 +164,17 @@ void adns_set_config(config_adns_t config) {
169 adns_write(REG_Configuration_I, config_1); 164 adns_write(REG_Configuration_I, config_1);
170} 165}
171 166
172static int16_t convertDeltaToInt(uint8_t high, uint8_t low){ 167static int16_t convertDeltaToInt(uint8_t high, uint8_t low) {
173
174 // join bytes into twos compliment 168 // join bytes into twos compliment
175 uint16_t twos_comp = (high << 8) | low; 169 uint16_t twos_comp = (high << 8) | low;
176 170
177 // convert twos comp to int 171 // convert twos comp to int
178 if (twos_comp & 0x8000) 172 if (twos_comp & 0x8000) return -1 * (~twos_comp + 1);
179 return -1 * (~twos_comp + 1);
180 173
181 return twos_comp; 174 return twos_comp;
182} 175}
183 176
184report_adns_t adns_get_report(void) { 177report_adns_t adns_get_report(void) {
185
186 report_adns_t report = {0, 0}; 178 report_adns_t report = {0, 0};
187 179
188 adns_spi_start(); 180 adns_spi_start();
@@ -194,8 +186,7 @@ report_adns_t adns_get_report(void) {
194 186
195 uint8_t motion = spi_read(); 187 uint8_t motion = spi_read();
196 188
197 if(motion & 0x80) { 189 if (motion & 0x80) {
198
199 // clear observation register 190 // clear observation register
200 spi_read(); 191 spi_read();
201 192
diff --git a/drivers/sensors/adns9800.h b/drivers/sensors/adns9800.h
index 2f50b8f1b..d19ded401 100644
--- a/drivers/sensors/adns9800.h
+++ b/drivers/sensors/adns9800.h
@@ -28,8 +28,8 @@ typedef struct {
28 int16_t y; 28 int16_t y;
29} report_adns_t; 29} report_adns_t;
30 30
31void adns_init(void); 31void adns_init(void);
32config_adns_t adns_get_config(void); 32config_adns_t adns_get_config(void);
33void adns_set_config(config_adns_t); 33void adns_set_config(config_adns_t);
34/* Reads and clears the current delta values on the ADNS sensor */ 34/* Reads and clears the current delta values on the ADNS sensor */
35report_adns_t adns_get_report(void); 35report_adns_t adns_get_report(void);
diff --git a/drivers/sensors/pmw3360.c b/drivers/sensors/pmw3360.c
index 5463bfc59..79b653e45 100644
--- a/drivers/sensors/pmw3360.c
+++ b/drivers/sensors/pmw3360.c
@@ -23,55 +23,55 @@
23#include "pmw3360_firmware.h" 23#include "pmw3360_firmware.h"
24 24
25// Registers 25// Registers
26#define REG_Product_ID 0x00 26#define REG_Product_ID 0x00
27#define REG_Revision_ID 0x01 27#define REG_Revision_ID 0x01
28#define REG_Motion 0x02 28#define REG_Motion 0x02
29#define REG_Delta_X_L 0x03 29#define REG_Delta_X_L 0x03
30#define REG_Delta_X_H 0x04 30#define REG_Delta_X_H 0x04
31#define REG_Delta_Y_L 0x05 31#define REG_Delta_Y_L 0x05
32#define REG_Delta_Y_H 0x06 32#define REG_Delta_Y_H 0x06
33#define REG_SQUAL 0x07 33#define REG_SQUAL 0x07
34#define REG_Raw_Data_Sum 0x08 34#define REG_Raw_Data_Sum 0x08
35#define REG_Maximum_Raw_data 0x09 35#define REG_Maximum_Raw_data 0x09
36#define REG_Minimum_Raw_data 0x0A 36#define REG_Minimum_Raw_data 0x0A
37#define REG_Shutter_Lower 0x0B 37#define REG_Shutter_Lower 0x0B
38#define REG_Shutter_Upper 0x0C 38#define REG_Shutter_Upper 0x0C
39#define REG_Control 0x0D 39#define REG_Control 0x0D
40#define REG_Config1 0x0F 40#define REG_Config1 0x0F
41#define REG_Config2 0x10 41#define REG_Config2 0x10
42#define REG_Angle_Tune 0x11 42#define REG_Angle_Tune 0x11
43#define REG_Frame_Capture 0x12 43#define REG_Frame_Capture 0x12
44#define REG_SROM_Enable 0x13 44#define REG_SROM_Enable 0x13
45#define REG_Run_Downshift 0x14 45#define REG_Run_Downshift 0x14
46#define REG_Rest1_Rate_Lower 0x15 46#define REG_Rest1_Rate_Lower 0x15
47#define REG_Rest1_Rate_Upper 0x16 47#define REG_Rest1_Rate_Upper 0x16
48#define REG_Rest1_Downshift 0x17 48#define REG_Rest1_Downshift 0x17
49#define REG_Rest2_Rate_Lower 0x18 49#define REG_Rest2_Rate_Lower 0x18
50#define REG_Rest2_Rate_Upper 0x19 50#define REG_Rest2_Rate_Upper 0x19
51#define REG_Rest2_Downshift 0x1A 51#define REG_Rest2_Downshift 0x1A
52#define REG_Rest3_Rate_Lower 0x1B 52#define REG_Rest3_Rate_Lower 0x1B
53#define REG_Rest3_Rate_Upper 0x1C 53#define REG_Rest3_Rate_Upper 0x1C
54#define REG_Observation 0x24 54#define REG_Observation 0x24
55#define REG_Data_Out_Lower 0x25 55#define REG_Data_Out_Lower 0x25
56#define REG_Data_Out_Upper 0x26 56#define REG_Data_Out_Upper 0x26
57#define REG_Raw_Data_Dump 0x29 57#define REG_Raw_Data_Dump 0x29
58#define REG_SROM_ID 0x2A 58#define REG_SROM_ID 0x2A
59#define REG_Min_SQ_Run 0x2B 59#define REG_Min_SQ_Run 0x2B
60#define REG_Raw_Data_Threshold 0x2C 60#define REG_Raw_Data_Threshold 0x2C
61#define REG_Config5 0x2F 61#define REG_Config5 0x2F
62#define REG_Power_Up_Reset 0x3A 62#define REG_Power_Up_Reset 0x3A
63#define REG_Shutdown 0x3B 63#define REG_Shutdown 0x3B
64#define REG_Inverse_Product_ID 0x3F 64#define REG_Inverse_Product_ID 0x3F
65#define REG_LiftCutoff_Tune3 0x41 65#define REG_LiftCutoff_Tune3 0x41
66#define REG_Angle_Snap 0x42 66#define REG_Angle_Snap 0x42
67#define REG_LiftCutoff_Tune1 0x4A 67#define REG_LiftCutoff_Tune1 0x4A
68#define REG_Motion_Burst 0x50 68#define REG_Motion_Burst 0x50
69#define REG_LiftCutoff_Tune_Timeout 0x58 69#define REG_LiftCutoff_Tune_Timeout 0x58
70#define REG_LiftCutoff_Tune_Min_Length 0x5A 70#define REG_LiftCutoff_Tune_Min_Length 0x5A
71#define REG_SROM_Load_Burst 0x62 71#define REG_SROM_Load_Burst 0x62
72#define REG_Lift_Config 0x63 72#define REG_Lift_Config 0x63
73#define REG_Raw_Data_Burst 0x64 73#define REG_Raw_Data_Burst 0x64
74#define REG_LiftCutoff_Tune2 0x65 74#define REG_LiftCutoff_Tune2 0x65
75 75
76bool _inBurst = false; 76bool _inBurst = false;
77 77
diff --git a/drivers/sensors/pmw3360.h b/drivers/sensors/pmw3360.h
index 124c62cf0..7429a6ba0 100644
--- a/drivers/sensors/pmw3360.h
+++ b/drivers/sensors/pmw3360.h
@@ -66,20 +66,17 @@ typedef struct {
66 int8_t mdy; 66 int8_t mdy;
67} report_pmw_t; 67} report_pmw_t;
68 68
69 69bool spi_start_adv(void);
70 70void spi_stop_adv(void);
71bool spi_start_adv(void);
72void spi_stop_adv(void);
73spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data); 71spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data);
74uint8_t spi_read_adv(uint8_t reg_addr); 72uint8_t spi_read_adv(uint8_t reg_addr);
75bool pmw_spi_init(void); 73bool pmw_spi_init(void);
76void pmw_set_cpi(uint16_t cpi); 74void pmw_set_cpi(uint16_t cpi);
77uint16_t pmw_get_cpi(void); 75uint16_t pmw_get_cpi(void);
78void pmw_upload_firmware(void); 76void pmw_upload_firmware(void);
79bool pmw_check_signature(void); 77bool pmw_check_signature(void);
80report_pmw_t pmw_read_burst(void); 78report_pmw_t pmw_read_burst(void);
81 79
82
83#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0) 80#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
84#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI) 81#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI)
85#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) 82#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
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);