aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/adafruit_ble.cpp699
-rw-r--r--drivers/bluetooth/adafruit_ble.h59
-rw-r--r--drivers/bluetooth/outputselect.c79
-rw-r--r--drivers/bluetooth/outputselect.h34
-rw-r--r--drivers/bluetooth/ringbuffer.hpp66
-rw-r--r--drivers/led/apa102.c2
-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
15 files changed, 938 insertions, 926 deletions
diff --git a/drivers/bluetooth/adafruit_ble.cpp b/drivers/bluetooth/adafruit_ble.cpp
new file mode 100644
index 000000000..34a780e9a
--- /dev/null
+++ b/drivers/bluetooth/adafruit_ble.cpp
@@ -0,0 +1,699 @@
1#include "adafruit_ble.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <alloca.h>
6#include "debug.h"
7#include "timer.h"
8#include "action_util.h"
9#include "ringbuffer.hpp"
10#include <string.h>
11#include "spi_master.h"
12#include "wait.h"
13#include "analog.h"
14#include "progmem.h"
15
16// These are the pin assignments for the 32u4 boards.
17// You may define them to something else in your config.h
18// if yours is wired up differently.
19#ifndef ADAFRUIT_BLE_RST_PIN
20# define ADAFRUIT_BLE_RST_PIN D4
21#endif
22
23#ifndef ADAFRUIT_BLE_CS_PIN
24# define ADAFRUIT_BLE_CS_PIN B4
25#endif
26
27#ifndef ADAFRUIT_BLE_IRQ_PIN
28# define ADAFRUIT_BLE_IRQ_PIN E6
29#endif
30
31#ifndef ADAFRUIT_BLE_SCK_DIVISOR
32# define ADAFRUIT_BLE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
33#endif
34
35#define SAMPLE_BATTERY
36#define ConnectionUpdateInterval 1000 /* milliseconds */
37
38#ifndef BATTERY_LEVEL_PIN
39# define BATTERY_LEVEL_PIN B5
40#endif
41
42static struct {
43 bool is_connected;
44 bool initialized;
45 bool configured;
46
47#define ProbedEvents 1
48#define UsingEvents 2
49 bool event_flags;
50
51#ifdef SAMPLE_BATTERY
52 uint16_t last_battery_update;
53 uint32_t vbat;
54#endif
55 uint16_t last_connection_update;
56} state;
57
58// Commands are encoded using SDEP and sent via SPI
59// https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md
60
61#define SdepMaxPayload 16
62struct sdep_msg {
63 uint8_t type;
64 uint8_t cmd_low;
65 uint8_t cmd_high;
66 struct __attribute__((packed)) {
67 uint8_t len : 7;
68 uint8_t more : 1;
69 };
70 uint8_t payload[SdepMaxPayload];
71} __attribute__((packed));
72
73// The recv latency is relatively high, so when we're hammering keys quickly,
74// we want to avoid waiting for the responses in the matrix loop. We maintain
75// a short queue for that. Since there is quite a lot of space overhead for
76// the AT command representation wrapped up in SDEP, we queue the minimal
77// information here.
78
79enum queue_type {
80 QTKeyReport, // 1-byte modifier + 6-byte key report
81 QTConsumer, // 16-bit key code
82#ifdef MOUSE_ENABLE
83 QTMouseMove, // 4-byte mouse report
84#endif
85};
86
87struct queue_item {
88 enum queue_type queue_type;
89 uint16_t added;
90 union __attribute__((packed)) {
91 struct __attribute__((packed)) {
92 uint8_t modifier;
93 uint8_t keys[6];
94 } key;
95
96 uint16_t consumer;
97 struct __attribute__((packed)) {
98 int8_t x, y, scroll, pan;
99 uint8_t buttons;
100 } mousemove;
101 };
102};
103
104// Items that we wish to send
105static RingBuffer<queue_item, 40> send_buf;
106// Pending response; while pending, we can't send any more requests.
107// This records the time at which we sent the command for which we
108// are expecting a response.
109static RingBuffer<uint16_t, 2> resp_buf;
110
111static bool process_queue_item(struct queue_item *item, uint16_t timeout);
112
113enum sdep_type {
114 SdepCommand = 0x10,
115 SdepResponse = 0x20,
116 SdepAlert = 0x40,
117 SdepError = 0x80,
118 SdepSlaveNotReady = 0xFE, // Try again later
119 SdepSlaveOverflow = 0xFF, // You read more data than is available
120};
121
122enum ble_cmd {
123 BleInitialize = 0xBEEF,
124 BleAtWrapper = 0x0A00,
125 BleUartTx = 0x0A01,
126 BleUartRx = 0x0A02,
127};
128
129enum ble_system_event_bits {
130 BleSystemConnected = 0,
131 BleSystemDisconnected = 1,
132 BleSystemUartRx = 8,
133 BleSystemMidiRx = 10,
134};
135
136#define SdepTimeout 150 /* milliseconds */
137#define SdepShortTimeout 10 /* milliseconds */
138#define SdepBackOff 25 /* microseconds */
139#define BatteryUpdateInterval 10000 /* milliseconds */
140
141static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
142static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
143
144// Send a single SDEP packet
145static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
146 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
147 uint16_t timerStart = timer_read();
148 bool success = false;
149 bool ready = false;
150
151 do {
152 ready = spi_write(msg->type) != SdepSlaveNotReady;
153 if (ready) {
154 break;
155 }
156
157 // Release it and let it initialize
158 spi_stop();
159 wait_us(SdepBackOff);
160 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
161 } while (timer_elapsed(timerStart) < timeout);
162
163 if (ready) {
164 // Slave is ready; send the rest of the packet
165 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
166 success = true;
167 }
168
169 spi_stop();
170
171 return success;
172}
173
174static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, const uint8_t *payload, uint8_t len, bool moredata) {
175 msg->type = SdepCommand;
176 msg->cmd_low = command & 0xFF;
177 msg->cmd_high = command >> 8;
178 msg->len = len;
179 msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0;
180
181 static_assert(sizeof(*msg) == 20, "msg is correctly packed");
182
183 memcpy(msg->payload, payload, len);
184}
185
186// Read a single SDEP packet
187static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
188 bool success = false;
189 uint16_t timerStart = timer_read();
190 bool ready = false;
191
192 do {
193 ready = readPin(ADAFRUIT_BLE_IRQ_PIN);
194 if (ready) {
195 break;
196 }
197 wait_us(1);
198 } while (timer_elapsed(timerStart) < timeout);
199
200 if (ready) {
201 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
202
203 do {
204 // Read the command type, waiting for the data to be ready
205 msg->type = spi_read();
206 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
207 // Release it and let it initialize
208 spi_stop();
209 wait_us(SdepBackOff);
210 spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
211 continue;
212 }
213
214 // Read the rest of the header
215 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
216
217 // and get the payload if there is any
218 if (msg->len <= SdepMaxPayload) {
219 spi_receive(msg->payload, msg->len);
220 }
221 success = true;
222 break;
223 } while (timer_elapsed(timerStart) < timeout);
224
225 spi_stop();
226 }
227 return success;
228}
229
230static void resp_buf_read_one(bool greedy) {
231 uint16_t last_send;
232 if (!resp_buf.peek(last_send)) {
233 return;
234 }
235
236 if (readPin(ADAFRUIT_BLE_IRQ_PIN)) {
237 struct sdep_msg msg;
238
239 again:
240 if (sdep_recv_pkt(&msg, SdepTimeout)) {
241 if (!msg.more) {
242 // We got it; consume this entry
243 resp_buf.get(last_send);
244 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
245 }
246
247 if (greedy && resp_buf.peek(last_send) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
248 goto again;
249 }
250 }
251
252 } else if (timer_elapsed(last_send) > SdepTimeout * 2) {
253 dprintf("waiting_for_result: timeout, resp_buf size %d\n", (int)resp_buf.size());
254
255 // Timed out: consume this entry
256 resp_buf.get(last_send);
257 }
258}
259
260static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
261 struct queue_item item;
262
263 // Don't send anything more until we get an ACK
264 if (!resp_buf.empty()) {
265 return;
266 }
267
268 if (!send_buf.peek(item)) {
269 return;
270 }
271 if (process_queue_item(&item, timeout)) {
272 // commit that peek
273 send_buf.get(item);
274 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
275 } else {
276 dprint("failed to send, will retry\n");
277 wait_ms(SdepTimeout);
278 resp_buf_read_one(true);
279 }
280}
281
282static void resp_buf_wait(const char *cmd) {
283 bool didPrint = false;
284 while (!resp_buf.empty()) {
285 if (!didPrint) {
286 dprintf("wait on buf for %s\n", cmd);
287 didPrint = true;
288 }
289 resp_buf_read_one(true);
290 }
291}
292
293static bool ble_init(void) {
294 state.initialized = false;
295 state.configured = false;
296 state.is_connected = false;
297
298 setPinInput(ADAFRUIT_BLE_IRQ_PIN);
299
300 spi_init();
301
302 // Perform a hardware reset
303 setPinOutput(ADAFRUIT_BLE_RST_PIN);
304 writePinHigh(ADAFRUIT_BLE_RST_PIN);
305 writePinLow(ADAFRUIT_BLE_RST_PIN);
306 wait_ms(10);
307 writePinHigh(ADAFRUIT_BLE_RST_PIN);
308
309 wait_ms(1000); // Give it a second to initialize
310
311 state.initialized = true;
312 return state.initialized;
313}
314
315static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }
316
317static bool read_response(char *resp, uint16_t resplen, bool verbose) {
318 char *dest = resp;
319 char *end = dest + resplen;
320
321 while (true) {
322 struct sdep_msg msg;
323
324 if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) {
325 dprint("sdep_recv_pkt failed\n");
326 return false;
327 }
328
329 if (msg.type != SdepResponse) {
330 *resp = 0;
331 return false;
332 }
333
334 uint8_t len = min(msg.len, end - dest);
335 if (len > 0) {
336 memcpy(dest, msg.payload, len);
337 dest += len;
338 }
339
340 if (!msg.more) {
341 // No more data is expected!
342 break;
343 }
344 }
345
346 // Ensure the response is NUL terminated
347 *dest = 0;
348
349 // "Parse" the result text; we want to snip off the trailing OK or ERROR line
350 // Rewind past the possible trailing CRLF so that we can strip it
351 --dest;
352 while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) {
353 *dest = 0;
354 --dest;
355 }
356
357 // Look back for start of preceeding line
358 char *last_line = strrchr(resp, '\n');
359 if (last_line) {
360 ++last_line;
361 } else {
362 last_line = resp;
363 }
364
365 bool success = false;
366 static const char kOK[] PROGMEM = "OK";
367
368 success = !strcmp_P(last_line, kOK);
369
370 if (verbose || !success) {
371 dprintf("result: %s\n", resp);
372 }
373 return success;
374}
375
376static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout) {
377 const char * end = cmd + strlen(cmd);
378 struct sdep_msg msg;
379
380 if (verbose) {
381 dprintf("ble send: %s\n", cmd);
382 }
383
384 if (resp) {
385 // They want to decode the response, so we need to flush and wait
386 // for all pending I/O to finish before we start this one, so
387 // that we don't confuse the results
388 resp_buf_wait(cmd);
389 *resp = 0;
390 }
391
392 // Fragment the command into a series of SDEP packets
393 while (end - cmd > SdepMaxPayload) {
394 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true);
395 if (!sdep_send_pkt(&msg, timeout)) {
396 return false;
397 }
398 cmd += SdepMaxPayload;
399 }
400
401 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false);
402 if (!sdep_send_pkt(&msg, timeout)) {
403 return false;
404 }
405
406 if (resp == NULL) {
407 uint16_t now = timer_read();
408 while (!resp_buf.enqueue(now)) {
409 resp_buf_read_one(false);
410 }
411 uint16_t later = timer_read();
412 if (TIMER_DIFF_16(later, now) > 0) {
413 dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now));
414 }
415 return true;
416 }
417
418 return read_response(resp, resplen, verbose);
419}
420
421bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
422 char *cmdbuf = (char *)alloca(strlen_P(cmd) + 1);
423 strcpy_P(cmdbuf, cmd);
424 return at_command(cmdbuf, resp, resplen, verbose);
425}
426
427bool adafruit_ble_is_connected(void) { return state.is_connected; }
428
429bool adafruit_ble_enable_keyboard(void) {
430 char resbuf[128];
431
432 if (!state.initialized && !ble_init()) {
433 return false;
434 }
435
436 state.configured = false;
437
438 // Disable command echo
439 static const char kEcho[] PROGMEM = "ATE=0";
440 // Make the advertised name match the keyboard
441 static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT);
442 // Turn on keyboard support
443 static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1";
444
445 // Adjust intervals to improve latency. This causes the "central"
446 // system (computer/tablet) to poll us every 10-30 ms. We can't
447 // set a smaller value than 10ms, and 30ms seems to be the natural
448 // processing time on my macbook. Keeping it constrained to that
449 // feels reasonable to type to.
450 static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,";
451
452 // Reset the device so that it picks up the above changes
453 static const char kATZ[] PROGMEM = "ATZ";
454
455 // Turn down the power level a bit
456 static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12";
457 static PGM_P const configure_commands[] PROGMEM = {
458 kEcho, kGapIntervals, kGapDevName, kHidEnOn, kPower, kATZ,
459 };
460
461 uint8_t i;
462 for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); ++i) {
463 PGM_P cmd;
464 memcpy_P(&cmd, configure_commands + i, sizeof(cmd));
465
466 if (!at_command_P(cmd, resbuf, sizeof(resbuf))) {
467 dprintf("failed BLE command: %S: %s\n", cmd, resbuf);
468 goto fail;
469 }
470 }
471
472 state.configured = true;
473
474 // Check connection status in a little while; allow the ATZ time
475 // to kick in.
476 state.last_connection_update = timer_read();
477fail:
478 return state.configured;
479}
480
481static void set_connected(bool connected) {
482 if (connected != state.is_connected) {
483 if (connected) {
484 dprint("BLE connected\n");
485 } else {
486 dprint("BLE disconnected\n");
487 }
488 state.is_connected = connected;
489
490 // TODO: if modifiers are down on the USB interface and
491 // we cut over to BLE or vice versa, they will remain stuck.
492 // This feels like a good point to do something like clearing
493 // the keyboard and/or generating a fake all keys up message.
494 // However, I've noticed that it takes a couple of seconds
495 // for macOS to to start recognizing key presses after BLE
496 // is in the connected state, so I worry that doing that
497 // here may not be good enough.
498 }
499}
500
501void adafruit_ble_task(void) {
502 char resbuf[48];
503
504 if (!state.configured && !adafruit_ble_enable_keyboard()) {
505 return;
506 }
507 resp_buf_read_one(true);
508 send_buf_send_one(SdepShortTimeout);
509
510 if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
511 // Must be an event update
512 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
513 uint32_t mask = strtoul(resbuf, NULL, 16);
514
515 if (mask & BleSystemConnected) {
516 set_connected(true);
517 } else if (mask & BleSystemDisconnected) {
518 set_connected(false);
519 }
520 }
521 }
522
523 if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) {
524 bool shouldPoll = true;
525 if (!(state.event_flags & ProbedEvents)) {
526 // Request notifications about connection status changes.
527 // This only works in SPIFRIEND firmware > 0.6.7, which is why
528 // we check for this conditionally here.
529 // Note that at the time of writing, HID reports only work correctly
530 // with Apple products on firmware version 0.6.7!
531 // https://forums.adafruit.com/viewtopic.php?f=8&t=104052
532 if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) {
533 at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf));
534 state.event_flags |= UsingEvents;
535 }
536 state.event_flags |= ProbedEvents;
537
538 // leave shouldPoll == true so that we check at least once
539 // before relying solely on events
540 } else {
541 shouldPoll = false;
542 }
543
544 static const char kGetConn[] PROGMEM = "AT+GAPGETCONN";
545 state.last_connection_update = timer_read();
546
547 if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) {
548 set_connected(atoi(resbuf));
549 }
550 }
551
552#ifdef SAMPLE_BATTERY
553 if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && resp_buf.empty()) {
554 state.last_battery_update = timer_read();
555
556 state.vbat = analogReadPin(BATTERY_LEVEL_PIN);
557 }
558#endif
559}
560
561static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
562 char cmdbuf[48];
563 char fmtbuf[64];
564
565 // Arrange to re-check connection after keys have settled
566 state.last_connection_update = timer_read();
567
568#if 1
569 if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) {
570 dprintf("send latency %dms\n", TIMER_DIFF_16(state.last_connection_update, item->added));
571 }
572#endif
573
574 switch (item->queue_type) {
575 case QTKeyReport:
576 strcpy_P(fmtbuf, PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x"));
577 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->key.modifier, item->key.keys[0], item->key.keys[1], item->key.keys[2], item->key.keys[3], item->key.keys[4], item->key.keys[5]);
578 return at_command(cmdbuf, NULL, 0, true, timeout);
579
580 case QTConsumer:
581 strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x"));
582 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer);
583 return at_command(cmdbuf, NULL, 0, true, timeout);
584
585#ifdef MOUSE_ENABLE
586 case QTMouseMove:
587 strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d"));
588 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, item->mousemove.y, item->mousemove.scroll, item->mousemove.pan);
589 if (!at_command(cmdbuf, NULL, 0, true, timeout)) {
590 return false;
591 }
592 strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON="));
593 if (item->mousemove.buttons & MOUSE_BTN1) {
594 strcat(cmdbuf, "L");
595 }
596 if (item->mousemove.buttons & MOUSE_BTN2) {
597 strcat(cmdbuf, "R");
598 }
599 if (item->mousemove.buttons & MOUSE_BTN3) {
600 strcat(cmdbuf, "M");
601 }
602 if (item->mousemove.buttons == 0) {
603 strcat(cmdbuf, "0");
604 }
605 return at_command(cmdbuf, NULL, 0, true, timeout);
606#endif
607 default:
608 return true;
609 }
610}
611
612void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
613 struct queue_item item;
614 bool didWait = false;
615
616 item.queue_type = QTKeyReport;
617 item.key.modifier = hid_modifier_mask;
618 item.added = timer_read();
619
620 while (nkeys >= 0) {
621 item.key.keys[0] = keys[0];
622 item.key.keys[1] = nkeys >= 1 ? keys[1] : 0;
623 item.key.keys[2] = nkeys >= 2 ? keys[2] : 0;
624 item.key.keys[3] = nkeys >= 3 ? keys[3] : 0;
625 item.key.keys[4] = nkeys >= 4 ? keys[4] : 0;
626 item.key.keys[5] = nkeys >= 5 ? keys[5] : 0;
627
628 if (!send_buf.enqueue(item)) {
629 if (!didWait) {
630 dprint("wait for buf space\n");
631 didWait = true;
632 }
633 send_buf_send_one();
634 continue;
635 }
636
637 if (nkeys <= 6) {
638 return;
639 }
640
641 nkeys -= 6;
642 keys += 6;
643 }
644}
645
646void adafruit_ble_send_consumer_key(uint16_t usage) {
647 struct queue_item item;
648
649 item.queue_type = QTConsumer;
650 item.consumer = usage;
651
652 while (!send_buf.enqueue(item)) {
653 send_buf_send_one();
654 }
655}
656
657#ifdef MOUSE_ENABLE
658void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
659 struct queue_item item;
660
661 item.queue_type = QTMouseMove;
662 item.mousemove.x = x;
663 item.mousemove.y = y;
664 item.mousemove.scroll = scroll;
665 item.mousemove.pan = pan;
666 item.mousemove.buttons = buttons;
667
668 while (!send_buf.enqueue(item)) {
669 send_buf_send_one();
670 }
671}
672#endif
673
674uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
675
676bool adafruit_ble_set_mode_leds(bool on) {
677 if (!state.configured) {
678 return false;
679 }
680
681 // The "mode" led is the red blinky one
682 at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0);
683
684 // Pin 19 is the blue "connected" LED; turn that off too.
685 // When turning LEDs back on, don't turn that LED on if we're
686 // not connected, as that would be confusing.
687 at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") : PSTR("AT+HWGPIO=19,0"), NULL, 0);
688 return true;
689}
690
691// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
692bool adafruit_ble_set_power_level(int8_t level) {
693 char cmd[46];
694 if (!state.configured) {
695 return false;
696 }
697 snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level);
698 return at_command(cmd, NULL, 0, false);
699}
diff --git a/drivers/bluetooth/adafruit_ble.h b/drivers/bluetooth/adafruit_ble.h
new file mode 100644
index 000000000..b43e0771d
--- /dev/null
+++ b/drivers/bluetooth/adafruit_ble.h
@@ -0,0 +1,59 @@
1/* Bluetooth Low Energy Protocol for QMK.
2 * Author: Wez Furlong, 2016
3 * Supports the Adafruit BLE board built around the nRF51822 chip.
4 */
5
6#pragma once
7
8#include <stdbool.h>
9#include <stdint.h>
10#include <string.h>
11
12#include "config_common.h"
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18/* Instruct the module to enable HID keyboard support and reset */
19extern bool adafruit_ble_enable_keyboard(void);
20
21/* Query to see if the BLE module is connected */
22extern bool adafruit_ble_query_is_connected(void);
23
24/* Returns true if we believe that the BLE module is connected.
25 * This uses our cached understanding that is maintained by
26 * calling ble_task() periodically. */
27extern bool adafruit_ble_is_connected(void);
28
29/* Call this periodically to process BLE-originated things */
30extern void adafruit_ble_task(void);
31
32/* Generates keypress events for a set of keys.
33 * The hid modifier mask specifies the state of the modifier keys for
34 * this set of keys.
35 * Also sends a key release indicator, so that the keys do not remain
36 * held down. */
37extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
38
39/* Send a consumer usage.
40 * (milliseconds) */
41extern void adafruit_ble_send_consumer_key(uint16_t usage);
42
43#ifdef MOUSE_ENABLE
44/* Send a mouse/wheel movement report.
45 * The parameters are signed and indicate positive or negative direction
46 * change. */
47extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
48#endif
49
50/* Compute battery voltage by reading an analog pin.
51 * Returns the integer number of millivolts */
52extern uint32_t adafruit_ble_read_battery_voltage(void);
53
54extern bool adafruit_ble_set_mode_leds(bool on);
55extern bool adafruit_ble_set_power_level(int8_t level);
56
57#ifdef __cplusplus
58}
59#endif
diff --git a/drivers/bluetooth/outputselect.c b/drivers/bluetooth/outputselect.c
new file mode 100644
index 000000000..f758c6528
--- /dev/null
+++ b/drivers/bluetooth/outputselect.c
@@ -0,0 +1,79 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#include "outputselect.h"
16
17#if defined(PROTOCOL_LUFA)
18# include "lufa.h"
19#endif
20
21#ifdef MODULE_ADAFRUIT_BLE
22# include "adafruit_ble.h"
23#endif
24
25uint8_t desired_output = OUTPUT_DEFAULT;
26
27/** \brief Set Output
28 *
29 * FIXME: Needs doc
30 */
31void set_output(uint8_t output) {
32 set_output_user(output);
33 desired_output = output;
34}
35
36/** \brief Set Output User
37 *
38 * FIXME: Needs doc
39 */
40__attribute__((weak)) void set_output_user(uint8_t output) {}
41
42static bool is_usb_configured(void) {
43#if defined(PROTOCOL_LUFA)
44 return USB_DeviceState == DEVICE_STATE_Configured;
45#endif
46}
47
48/** \brief Auto Detect Output
49 *
50 * FIXME: Needs doc
51 */
52uint8_t auto_detect_output(void) {
53 if (is_usb_configured()) {
54 return OUTPUT_USB;
55 }
56
57#ifdef MODULE_ADAFRUIT_BLE
58 if (adafruit_ble_is_connected()) {
59 return OUTPUT_BLUETOOTH;
60 }
61#endif
62
63#ifdef BLUETOOTH_ENABLE
64 return OUTPUT_BLUETOOTH; // should check if BT is connected here
65#endif
66
67 return OUTPUT_NONE;
68}
69
70/** \brief Where To Send
71 *
72 * FIXME: Needs doc
73 */
74uint8_t where_to_send(void) {
75 if (desired_output == OUTPUT_AUTO) {
76 return auto_detect_output();
77 }
78 return desired_output;
79}
diff --git a/drivers/bluetooth/outputselect.h b/drivers/bluetooth/outputselect.h
new file mode 100644
index 000000000..c4548e112
--- /dev/null
+++ b/drivers/bluetooth/outputselect.h
@@ -0,0 +1,34 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#pragma once
16
17#include <stdint.h>
18
19enum outputs {
20 OUTPUT_AUTO,
21
22 OUTPUT_NONE,
23 OUTPUT_USB,
24 OUTPUT_BLUETOOTH
25};
26
27#ifndef OUTPUT_DEFAULT
28# define OUTPUT_DEFAULT OUTPUT_AUTO
29#endif
30
31void set_output(uint8_t output);
32void set_output_user(uint8_t output);
33uint8_t auto_detect_output(void);
34uint8_t where_to_send(void);
diff --git a/drivers/bluetooth/ringbuffer.hpp b/drivers/bluetooth/ringbuffer.hpp
new file mode 100644
index 000000000..70a3c4881
--- /dev/null
+++ b/drivers/bluetooth/ringbuffer.hpp
@@ -0,0 +1,66 @@
1#pragma once
2// A simple ringbuffer holding Size elements of type T
3template <typename T, uint8_t Size>
4class RingBuffer {
5 protected:
6 T buf_[Size];
7 uint8_t head_{0}, tail_{0};
8 public:
9 inline uint8_t nextPosition(uint8_t position) {
10 return (position + 1) % Size;
11 }
12
13 inline uint8_t prevPosition(uint8_t position) {
14 if (position == 0) {
15 return Size - 1;
16 }
17 return position - 1;
18 }
19
20 inline bool enqueue(const T &item) {
21 static_assert(Size > 1, "RingBuffer size must be > 1");
22 uint8_t next = nextPosition(head_);
23 if (next == tail_) {
24 // Full
25 return false;
26 }
27
28 buf_[head_] = item;
29 head_ = next;
30 return true;
31 }
32
33 inline bool get(T &dest, bool commit = true) {
34 auto tail = tail_;
35 if (tail == head_) {
36 // No more data
37 return false;
38 }
39
40 dest = buf_[tail];
41 tail = nextPosition(tail);
42
43 if (commit) {
44 tail_ = tail;
45 }
46 return true;
47 }
48
49 inline bool empty() const { return head_ == tail_; }
50
51 inline uint8_t size() const {
52 int diff = head_ - tail_;
53 if (diff >= 0) {
54 return diff;
55 }
56 return Size + diff;
57 }
58
59 inline T& front() {
60 return buf_[tail_];
61 }
62
63 inline bool peek(T &item) {
64 return get(item, false);
65 }
66};
diff --git a/drivers/led/apa102.c b/drivers/led/apa102.c
index 7396dc3c5..19e0bfc18 100644
--- a/drivers/led/apa102.c
+++ b/drivers/led/apa102.c
@@ -25,7 +25,7 @@
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)
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/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 */