diff options
Diffstat (limited to 'drivers')
39 files changed, 553 insertions, 165 deletions
| diff --git a/drivers/bluetooth/bluefruit_le.cpp b/drivers/bluetooth/bluefruit_le.cpp index 19310767cf..39c14ddd13 100644 --- a/drivers/bluetooth/bluefruit_le.cpp +++ b/drivers/bluetooth/bluefruit_le.cpp @@ -5,7 +5,7 @@  #include <alloca.h>  #include "debug.h"  #include "timer.h" -#include "action_util.h" +#include "gpio.h"  #include "ringbuffer.hpp"  #include <string.h>  #include "spi_master.h" @@ -79,9 +79,7 @@ struct sdep_msg {  enum queue_type {      QTKeyReport, // 1-byte modifier + 6-byte key report      QTConsumer,  // 16-bit key code -#ifdef MOUSE_ENABLE      QTMouseMove, // 4-byte mouse report -#endif  };  struct queue_item { @@ -290,7 +288,7 @@ static void resp_buf_wait(const char *cmd) {      }  } -static bool ble_init(void) { +void bluefruit_le_init(void) {      state.initialized  = false;      state.configured   = false;      state.is_connected = false; @@ -309,7 +307,6 @@ static bool ble_init(void) {      wait_ms(1000); // Give it a second to initialize      state.initialized = true; -    return state.initialized;  }  static inline uint8_t min(uint8_t a, uint8_t b) { @@ -433,7 +430,7 @@ bool bluefruit_le_is_connected(void) {  bool bluefruit_le_enable_keyboard(void) {      char resbuf[128]; -    if (!state.initialized && !ble_init()) { +    if (!state.initialized) {          return false;      } @@ -442,7 +439,7 @@ bool bluefruit_le_enable_keyboard(void) {      // Disable command echo      static const char kEcho[] PROGMEM = "ATE=0";      // Make the advertised name match the keyboard -    static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT); +    static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" PRODUCT;      // Turn on keyboard support      static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1"; @@ -581,10 +578,12 @@ static bool process_queue_item(struct queue_item *item, uint16_t timeout) {              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]);              return at_command(cmdbuf, NULL, 0, true, timeout); +#ifdef EXTRAKEY_ENABLE          case QTConsumer:              strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x"));              snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer);              return at_command(cmdbuf, NULL, 0, true, timeout); +#endif  #ifdef MOUSE_ENABLE          case QTMouseMove: @@ -613,41 +612,24 @@ static bool process_queue_item(struct queue_item *item, uint16_t timeout) {      }  } -void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) { +void bluefruit_le_send_keyboard(report_keyboard_t *report) {      struct queue_item item; -    bool              didWait = false;      item.queue_type   = QTKeyReport; -    item.key.modifier = hid_modifier_mask; -    item.added        = timer_read(); - -    while (nkeys >= 0) { -        item.key.keys[0] = keys[0]; -        item.key.keys[1] = nkeys >= 1 ? keys[1] : 0; -        item.key.keys[2] = nkeys >= 2 ? keys[2] : 0; -        item.key.keys[3] = nkeys >= 3 ? keys[3] : 0; -        item.key.keys[4] = nkeys >= 4 ? keys[4] : 0; -        item.key.keys[5] = nkeys >= 5 ? keys[5] : 0; - -        if (!send_buf.enqueue(item)) { -            if (!didWait) { -                dprint("wait for buf space\n"); -                didWait = true; -            } -            send_buf_send_one(); -            continue; -        } +    item.key.modifier = report->mods; +    item.key.keys[0]  = report->keys[0]; +    item.key.keys[1]  = report->keys[1]; +    item.key.keys[2]  = report->keys[2]; +    item.key.keys[3]  = report->keys[3]; +    item.key.keys[4]  = report->keys[4]; +    item.key.keys[5]  = report->keys[5]; -        if (nkeys <= 6) { -            return; -        } - -        nkeys -= 6; -        keys += 6; +    while (!send_buf.enqueue(item)) { +        send_buf_send_one();      }  } -void bluefruit_le_send_consumer_key(uint16_t usage) { +void bluefruit_le_send_consumer(uint16_t usage) {      struct queue_item item;      item.queue_type = QTConsumer; @@ -658,22 +640,20 @@ void bluefruit_le_send_consumer_key(uint16_t usage) {      }  } -#ifdef MOUSE_ENABLE -void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) { +void bluefruit_le_send_mouse(report_mouse_t *report) {      struct queue_item item;      item.queue_type        = QTMouseMove; -    item.mousemove.x       = x; -    item.mousemove.y       = y; -    item.mousemove.scroll  = scroll; -    item.mousemove.pan     = pan; -    item.mousemove.buttons = buttons; +    item.mousemove.x       = report->x; +    item.mousemove.y       = report->y; +    item.mousemove.scroll  = report->v; +    item.mousemove.pan     = report->h; +    item.mousemove.buttons = report->buttons;      while (!send_buf.enqueue(item)) {          send_buf_send_one();      }  } -#endif  uint32_t bluefruit_le_read_battery_voltage(void) {      return state.vbat; diff --git a/drivers/bluetooth/bluefruit_le.h b/drivers/bluetooth/bluefruit_le.h index de301c6167..a3de03c35c 100644 --- a/drivers/bluetooth/bluefruit_le.h +++ b/drivers/bluetooth/bluefruit_le.h @@ -7,9 +7,7 @@  #include <stdbool.h>  #include <stdint.h> -#include <string.h> - -#include "config_common.h" +#include "report.h"  #ifdef __cplusplus  extern "C" { @@ -26,6 +24,8 @@ extern bool bluefruit_le_query_is_connected(void);   * calling ble_task() periodically. */  extern bool bluefruit_le_is_connected(void); +extern void bluefruit_le_init(void); +  /* Call this periodically to process BLE-originated things */  extern void bluefruit_le_task(void); @@ -34,18 +34,16 @@ extern void bluefruit_le_task(void);   * this set of keys.   * Also sends a key release indicator, so that the keys do not remain   * held down. */ -extern void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys); +extern void bluefruit_le_send_keyboard(report_keyboard_t *report);  /* Send a consumer usage.   * (milliseconds) */ -extern void bluefruit_le_send_consumer_key(uint16_t usage); +extern void bluefruit_le_send_consumer(uint16_t usage); -#ifdef MOUSE_ENABLE  /* Send a mouse/wheel movement report.   * The parameters are signed and indicate positive or negative direction   * change. */ -extern void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons); -#endif +extern void bluefruit_le_send_mouse(report_mouse_t *report);  /* Compute battery voltage by reading an analog pin.   * Returns the integer number of millivolts */ diff --git a/drivers/bluetooth/bluetooth.c b/drivers/bluetooth/bluetooth.c new file mode 100644 index 0000000000..d5382401e7 --- /dev/null +++ b/drivers/bluetooth/bluetooth.c @@ -0,0 +1,62 @@ +/* + * Copyright 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "bluetooth.h" + +#if defined(BLUETOOTH_BLUEFRUIT_LE) +#    include "bluefruit_le.h" +#elif defined(BLUETOOTH_RN42) +#    include "rn42.h" +#endif + +void bluetooth_init(void) { +#if defined(BLUETOOTH_BLUEFRUIT_LE) +    bluefruit_le_init(); +#elif defined(BLUETOOTH_RN42) +    rn42_init(); +#endif +} + +void bluetooth_task(void) { +#if defined(BLUETOOTH_BLUEFRUIT_LE) +    bluefruit_le_task(); +#endif +} + +void bluetooth_send_keyboard(report_keyboard_t *report) { +#if defined(BLUETOOTH_BLUEFRUIT_LE) +    bluefruit_le_send_keyboard(report); +#elif defined(BLUETOOTH_RN42) +    rn42_send_keyboard(report); +#endif +} + +void bluetooth_send_mouse(report_mouse_t *report) { +#if defined(BLUETOOTH_BLUEFRUIT_LE) +    bluefruit_le_send_mouse(report); +#elif defined(BLUETOOTH_RN42) +    rn42_send_mouse(report); +#endif +} + +void bluetooth_send_consumer(uint16_t usage) { +#if defined(BLUETOOTH_BLUEFRUIT_LE) +    bluefruit_le_send_consumer(usage); +#elif defined(BLUETOOTH_RN42) +    rn42_send_consumer(usage); +#endif +} diff --git a/drivers/bluetooth/bluetooth.h b/drivers/bluetooth/bluetooth.h new file mode 100644 index 0000000000..2e4d0df538 --- /dev/null +++ b/drivers/bluetooth/bluetooth.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdint.h> +#include "report.h" + +/** + * \brief Initialize the Bluetooth system. + */ +void bluetooth_init(void); + +/** + * \brief Perform housekeeping tasks. + */ +void bluetooth_task(void); + +/** + * \brief Send a keyboard report. + * + * \param report The keyboard report to send. + */ +void bluetooth_send_keyboard(report_keyboard_t *report); + +/** + * \brief Send a mouse report. + * + * \param report The mouse report to send. + */ +void bluetooth_send_mouse(report_mouse_t *report); + +/** + * \brief Send a consumer usage. + * + * \param usage The consumer usage to send. + */ +void bluetooth_send_consumer(uint16_t usage); diff --git a/drivers/bluetooth/rn42.c b/drivers/bluetooth/rn42.c index 5d497cda20..0eb1733723 100644 --- a/drivers/bluetooth/rn42.c +++ b/drivers/bluetooth/rn42.c @@ -14,6 +14,8 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +#include "rn42.h" +  #include "report.h"  #include "uart.h" @@ -69,33 +71,35 @@ void rn42_send_keyboard(report_keyboard_t *report) {      uart_write(0xFD);      uart_write(0x09);      uart_write(0x01); +      uart_write(report->mods);      uart_write(0x00); -    for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { -        uart_write(report->keys[i]); -    } +    uart_write(report->keys[0]); +    uart_write(report->keys[1]); +    uart_write(report->keys[2]); +    uart_write(report->keys[3]); +    uart_write(report->keys[4]); +    uart_write(report->keys[5]);  }  void rn42_send_mouse(report_mouse_t *report) {      uart_write(0xFD); -    uart_write(0x00); -    uart_write(0x03); +    uart_write(0x05); +    uart_write(0x02); +      uart_write(report->buttons);      uart_write(report->x);      uart_write(report->y); -    uart_write(report->v); // should try sending the wheel v here -    uart_write(report->h); // should try sending the wheel h here -    uart_write(0x00); +    uart_write(report->v);  } -void rn42_send_consumer(uint16_t data) { -    static uint16_t last_data = 0; -    if (data == last_data) return; -    last_data       = data; -    uint16_t bitmap = rn42_consumer_usage_to_bitmap(data); +void rn42_send_consumer(uint16_t usage) { +    uint16_t bitmap = rn42_consumer_usage_to_bitmap(usage); +      uart_write(0xFD);      uart_write(0x03);      uart_write(0x03); +      uart_write(bitmap & 0xFF); -    uart_write((bitmap >> 8) & 0xFF); +    uart_write(bitmap >> 8);  } diff --git a/drivers/bluetooth/rn42.h b/drivers/bluetooth/rn42.h index 4747759111..89b716bfcd 100644 --- a/drivers/bluetooth/rn42.h +++ b/drivers/bluetooth/rn42.h @@ -14,6 +14,8 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +#include <stdint.h> +  #include "report.h"  void rn42_init(void); @@ -22,4 +24,4 @@ void rn42_send_keyboard(report_keyboard_t *report);  void rn42_send_mouse(report_mouse_t *report); -void rn42_send_consumer(uint16_t data); +void rn42_send_consumer(uint16_t usage); diff --git a/drivers/haptic/solenoid.c b/drivers/haptic/solenoid.c index 637a77da3d..4e43903255 100644 --- a/drivers/haptic/solenoid.c +++ b/drivers/haptic/solenoid.c @@ -20,11 +20,12 @@  #include "haptic.h"  #include "gpio.h"  #include "usb_device_state.h" +#include "util.h"  #include <stdlib.h>  uint8_t      solenoid_dwell  = SOLENOID_DEFAULT_DWELL;  static pin_t solenoid_pads[] = SOLENOID_PINS; -#define NUMBER_OF_SOLENOIDS (sizeof(solenoid_pads) / sizeof(pin_t)) +#define NUMBER_OF_SOLENOIDS ARRAY_SIZE(solenoid_pads)  bool     solenoid_on[NUMBER_OF_SOLENOIDS]      = {false};  bool     solenoid_buzzing[NUMBER_OF_SOLENOIDS] = {false};  uint16_t solenoid_start[NUMBER_OF_SOLENOIDS]   = {0}; @@ -147,7 +148,7 @@ void solenoid_check(void) {  void solenoid_setup(void) {  #ifdef SOLENOID_PINS_ACTIVE_STATE      bool    state_temp[] = SOLENOID_PINS_ACTIVE_STATE; -    uint8_t bound_check  = (sizeof(state_temp) / sizeof(bool)); +    uint8_t bound_check  = ARRAY_SIZE(state_temp);  #endif      for (uint8_t i = 0; i < NUMBER_OF_SOLENOIDS; i++) { diff --git a/drivers/led/aw20216.c b/drivers/led/aw20216.c index 55083936ef..cbb0b60774 100644 --- a/drivers/led/aw20216.c +++ b/drivers/led/aw20216.c @@ -133,7 +133,7 @@ void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (uint8_t i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          AW20216_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/aw20216.h b/drivers/led/aw20216.h index 0a17050fed..c6e71b4b4e 100644 --- a/drivers/led/aw20216.h +++ b/drivers/led/aw20216.h @@ -28,7 +28,7 @@ typedef struct aw_led {      uint8_t b;  } aw_led; -extern const aw_led PROGMEM g_aw_leds[DRIVER_LED_TOTAL]; +extern const aw_led PROGMEM g_aw_leds[RGB_MATRIX_LED_COUNT];  void AW20216_init(pin_t cs_pin, pin_t en_pin);  void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); diff --git a/drivers/led/ckled2001-simple.c b/drivers/led/ckled2001-simple.c index da4bf20b99..6c4ffd398e 100644 --- a/drivers/led/ckled2001-simple.c +++ b/drivers/led/ckled2001-simple.c @@ -148,7 +148,7 @@ void CKLED2001_init(uint8_t addr) {  void CKLED2001_set_value(int index, uint8_t value) {      ckled2001_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < LED_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.v]          = value; @@ -157,7 +157,7 @@ void CKLED2001_set_value(int index, uint8_t value) {  }  void CKLED2001_set_value_all(uint8_t value) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {          CKLED2001_set_value(i, value);      }  } diff --git a/drivers/led/ckled2001-simple.h b/drivers/led/ckled2001-simple.h index 731da2e1cd..a56cad3461 100644 --- a/drivers/led/ckled2001-simple.h +++ b/drivers/led/ckled2001-simple.h @@ -25,7 +25,7 @@ typedef struct ckled2001_led {      uint8_t v;  } __attribute__((packed)) ckled2001_led; -extern const ckled2001_led PROGMEM g_ckled2001_leds[DRIVER_LED_TOTAL]; +extern const ckled2001_led PROGMEM g_ckled2001_leds[LED_MATRIX_LED_COUNT];  void CKLED2001_init(uint8_t addr);  bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/ckled2001.c b/drivers/led/ckled2001.c index b7e7db06cc..1651628175 100644 --- a/drivers/led/ckled2001.c +++ b/drivers/led/ckled2001.c @@ -148,7 +148,7 @@ void CKLED2001_init(uint8_t addr) {  void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      ckled2001_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.r]          = red; @@ -159,7 +159,7 @@ void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void CKLED2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          CKLED2001_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/ckled2001.h b/drivers/led/ckled2001.h index 7d5ad34f95..aa70a0623f 100644 --- a/drivers/led/ckled2001.h +++ b/drivers/led/ckled2001.h @@ -27,7 +27,7 @@ typedef struct ckled2001_led {      uint8_t b;  } __attribute__((packed)) ckled2001_led; -extern const ckled2001_led PROGMEM g_ckled2001_leds[DRIVER_LED_TOTAL]; +extern const ckled2001_led PROGMEM g_ckled2001_leds[RGB_MATRIX_LED_COUNT];  void CKLED2001_init(uint8_t addr);  bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3731-simple.c b/drivers/led/issi/is31fl3731-simple.c index 3abe9ea337..84060f9426 100644 --- a/drivers/led/issi/is31fl3731-simple.c +++ b/drivers/led/issi/is31fl3731-simple.c @@ -194,7 +194,7 @@ void IS31FL3731_init(uint8_t addr) {  void IS31FL3731_set_value(int index, uint8_t value) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < LED_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          // Subtract 0x24 to get the second index of g_pwm_buffer @@ -204,7 +204,7 @@ void IS31FL3731_set_value(int index, uint8_t value) {  }  void IS31FL3731_set_value_all(uint8_t value) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {          IS31FL3731_set_value(i, value);      }  } diff --git a/drivers/led/issi/is31fl3731-simple.h b/drivers/led/issi/is31fl3731-simple.h index ded94b0470..1ddadd5209 100644 --- a/drivers/led/issi/is31fl3731-simple.h +++ b/drivers/led/issi/is31fl3731-simple.h @@ -27,7 +27,7 @@ typedef struct is31_led {      uint8_t v;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT];  void IS31FL3731_init(uint8_t addr);  void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3731.c b/drivers/led/issi/is31fl3731.c index 9c6c29f081..fed5354145 100644 --- a/drivers/led/issi/is31fl3731.c +++ b/drivers/led/issi/is31fl3731.c @@ -182,7 +182,7 @@ void IS31FL3731_init(uint8_t addr) {  void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          // Subtract 0x24 to get the second index of g_pwm_buffer @@ -194,7 +194,7 @@ void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL3731_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/issi/is31fl3731.h b/drivers/led/issi/is31fl3731.h index 6647119eba..6791289c9e 100644 --- a/drivers/led/issi/is31fl3731.h +++ b/drivers/led/issi/is31fl3731.h @@ -28,7 +28,7 @@ typedef struct is31_led {      uint8_t b;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];  void IS31FL3731_init(uint8_t addr);  void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3733-simple.c b/drivers/led/issi/is31fl3733-simple.c index 2f41a7b1a9..1e0994d780 100644 --- a/drivers/led/issi/is31fl3733-simple.c +++ b/drivers/led/issi/is31fl3733-simple.c @@ -195,7 +195,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {  }  void IS31FL3733_set_value(int index, uint8_t value) { -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < LED_MATRIX_LED_COUNT) {          is31_led led = g_is31_leds[index];          g_pwm_buffer[led.driver][led.v]          = value; @@ -204,7 +204,7 @@ void IS31FL3733_set_value(int index, uint8_t value) {  }  void IS31FL3733_set_value_all(uint8_t value) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {          IS31FL3733_set_value(i, value);      }  } diff --git a/drivers/led/issi/is31fl3733-simple.h b/drivers/led/issi/is31fl3733-simple.h index f5253e3101..f0ea3adca0 100644 --- a/drivers/led/issi/is31fl3733-simple.h +++ b/drivers/led/issi/is31fl3733-simple.h @@ -29,7 +29,7 @@ typedef struct is31_led {      uint8_t v;  } __attribute__((packed)) is31_led; -extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led __flash g_is31_leds[LED_MATRIX_LED_COUNT];  void IS31FL3733_init(uint8_t addr, uint8_t sync);  bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3733.c b/drivers/led/issi/is31fl3733.c index add998f256..379eaa0ae3 100644 --- a/drivers/led/issi/is31fl3733.c +++ b/drivers/led/issi/is31fl3733.c @@ -186,7 +186,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {  void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.r]          = red; @@ -197,7 +197,7 @@ void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL3733_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/issi/is31fl3733.h b/drivers/led/issi/is31fl3733.h index 7653dd17c0..29441846ac 100644 --- a/drivers/led/issi/is31fl3733.h +++ b/drivers/led/issi/is31fl3733.h @@ -30,7 +30,7 @@ typedef struct is31_led {      uint8_t b;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];  void IS31FL3733_init(uint8_t addr, uint8_t sync);  bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3736.c b/drivers/led/issi/is31fl3736.c index e9943614d2..82e7ee3d18 100644 --- a/drivers/led/issi/is31fl3736.c +++ b/drivers/led/issi/is31fl3736.c @@ -168,7 +168,7 @@ void IS31FL3736_init(uint8_t addr) {  void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.r] = red; @@ -179,7 +179,7 @@ void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL3736_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/issi/is31fl3736.h b/drivers/led/issi/is31fl3736.h index f126034615..ccb19afbcc 100644 --- a/drivers/led/issi/is31fl3736.h +++ b/drivers/led/issi/is31fl3736.h @@ -28,8 +28,8 @@  #    define DRIVER_COUNT 2  #endif -#ifndef DRIVER_LED_TOTAL -#    define DRIVER_LED_TOTAL 96 +#ifndef RGB_MATRIX_LED_COUNT +#    define RGB_MATRIX_LED_COUNT 96  #endif  typedef struct is31_led { @@ -39,7 +39,7 @@ typedef struct is31_led {      uint8_t b;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];  void IS31FL3736_init(uint8_t addr);  void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c index 932530ac0a..45a20018c5 100644 --- a/drivers/led/issi/is31fl3737.c +++ b/drivers/led/issi/is31fl3737.c @@ -175,7 +175,7 @@ void IS31FL3737_init(uint8_t addr) {  void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.r]          = red; @@ -186,7 +186,7 @@ void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL3737_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/issi/is31fl3737.h b/drivers/led/issi/is31fl3737.h index ddb70a9df5..fb0c33420c 100644 --- a/drivers/led/issi/is31fl3737.h +++ b/drivers/led/issi/is31fl3737.h @@ -30,7 +30,7 @@ typedef struct is31_led {      uint8_t b;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];  void IS31FL3737_init(uint8_t addr);  void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31fl3741.c b/drivers/led/issi/is31fl3741.c index ba6b6761a3..c2cdd4c46f 100644 --- a/drivers/led/issi/is31fl3741.c +++ b/drivers/led/issi/is31fl3741.c @@ -179,7 +179,7 @@ void IS31FL3741_init(uint8_t addr) {  void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {      is31_led led; -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));          g_pwm_buffer[led.driver][led.r]          = red; @@ -190,7 +190,7 @@ void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL3741_set_color(i, red, green, blue);      }  } diff --git a/drivers/led/issi/is31fl3741.h b/drivers/led/issi/is31fl3741.h index 3bdb23bd2d..b0089ea5ba 100644 --- a/drivers/led/issi/is31fl3741.h +++ b/drivers/led/issi/is31fl3741.h @@ -30,7 +30,7 @@ typedef struct is31_led {      uint32_t b : 10;  } __attribute__((packed)) is31_led; -extern const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];  void IS31FL3741_init(uint8_t addr);  void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data); diff --git a/drivers/led/issi/is31flcommon.c b/drivers/led/issi/is31flcommon.c index 9f4b2123ff..106890a8bf 100644 --- a/drivers/led/issi/is31flcommon.c +++ b/drivers/led/issi/is31flcommon.c @@ -135,14 +135,17 @@ void IS31FL_common_update_pwm_register(uint8_t addr, uint8_t index) {  void IS31FL_set_manual_scaling_buffer(void) {      for (int i = 0; i < ISSI_MANUAL_SCALING; i++) {          is31_led scale = g_is31_scaling[i]; -        if (scale.driver >= 0 && scale.driver < DRIVER_LED_TOTAL) { +#    ifdef RGB_MATRIX_ENABLE +        if (scale.driver >= 0 && scale.driver < RGB_MATRIX_LED_COUNT) {              is31_led led = g_is31_leds[scale.driver]; -#    ifdef RGB_MATRIX_ENABLE              g_scaling_buffer[led.driver][led.r] = scale.r;              g_scaling_buffer[led.driver][led.g] = scale.g;              g_scaling_buffer[led.driver][led.b] = scale.b;  #    elif defined(LED_MATRIX_ENABLE) +        if (scale.driver >= 0 && scale.driver < LED_MATRIX_LED_COUNT) { +            is31_led led = g_is31_leds[scale.driver]; +              g_scaling_buffer[led.driver][led.v] = scale.v;  #    endif              g_scaling_buffer_update_required[led.driver] = true; @@ -165,7 +168,7 @@ void IS31FL_common_update_scaling_register(uint8_t addr, uint8_t index) {  #ifdef RGB_MATRIX_ENABLE  // Colour is set by adjusting PWM register  void IS31FL_RGB_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < RGB_MATRIX_LED_COUNT) {          is31_led led = g_is31_leds[index];          g_pwm_buffer[led.driver][led.r]          = red; @@ -176,7 +179,7 @@ void IS31FL_RGB_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {  }  void IS31FL_RGB_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {          IS31FL_RGB_set_color(i, red, green, blue);      }  } @@ -215,7 +218,7 @@ void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value) {  }  void IS31FL_simple_set_brightness(int index, uint8_t value) { -    if (index >= 0 && index < DRIVER_LED_TOTAL) { +    if (index >= 0 && index < LED_MATRIX_LED_COUNT) {          is31_led led = g_is31_leds[index];          g_pwm_buffer[led.driver][led.v] = value;          g_pwm_buffer_update_required[led.driver] = true; @@ -223,7 +226,7 @@ void IS31FL_simple_set_brightness(int index, uint8_t value) {  }  void IS31FL_simple_set_brigntness_all(uint8_t value) { -    for (int i = 0; i < DRIVER_LED_TOTAL; i++) { +    for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {          IS31FL_simple_set_brightness(i, value);      }  } diff --git a/drivers/led/issi/is31flcommon.h b/drivers/led/issi/is31flcommon.h index 77e9665e32..18432ffc31 100644 --- a/drivers/led/issi/is31flcommon.h +++ b/drivers/led/issi/is31flcommon.h @@ -43,11 +43,15 @@ typedef struct is31_led {      uint8_t b;  } __attribute__((packed)) is31_led; +extern const is31_led __flash g_is31_leds[RGB_MATRIX_LED_COUNT]; +  #elif defined(LED_MATRIX_ENABLE)  typedef struct is31_led {      uint8_t driver;      uint8_t v;  } __attribute__((packed)) is31_led; + +extern const is31_led __flash g_is31_leds[LED_MATRIX_LED_COUNT];  #endif  #ifdef ISSI_MANUAL_SCALING @@ -55,8 +59,6 @@ extern const is31_led __flash g_is31_scaling[];  void                          IS31FL_set_manual_scaling_buffer(void);  #endif -extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL]; -  void IS31FL_write_single_register(uint8_t addr, uint8_t reg, uint8_t data);  bool IS31FL_write_multi_registers(uint8_t addr, uint8_t *source_buffer, uint8_t buffer_size, uint8_t transfer_size, uint8_t start_reg_addr);  void IS31FL_unlock_register(uint8_t addr, uint8_t page); diff --git a/drivers/painter/generic/qp_rgb565_surface.c b/drivers/painter/generic/qp_rgb565_surface.c new file mode 100644 index 0000000000..c4de336535 --- /dev/null +++ b/drivers/painter/generic/qp_rgb565_surface.c @@ -0,0 +1,277 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include "color.h" +#include "qp_rgb565_surface.h" +#include "qp_draw.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common + +// Device definition +typedef struct rgb565_surface_painter_device_t { +    struct painter_driver_t base; // must be first, so it can be cast to/from the painter_device_t* type + +    // The target buffer +    uint16_t *buffer; + +    // Manually manage the viewport for streaming pixel data to the display +    uint16_t viewport_l; +    uint16_t viewport_t; +    uint16_t viewport_r; +    uint16_t viewport_b; + +    // Current write location to the display when streaming pixel data +    uint16_t pixdata_x; +    uint16_t pixdata_y; + +    // Maintain a dirty region so we can stream only what we need +    bool     is_dirty; +    uint16_t dirty_l; +    uint16_t dirty_t; +    uint16_t dirty_r; +    uint16_t dirty_b; + +} rgb565_surface_painter_device_t; + +// Driver storage +rgb565_surface_painter_device_t surface_drivers[RGB565_SURFACE_NUM_DEVICES] = {0}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helpers + +static inline void increment_pixdata_location(rgb565_surface_painter_device_t *surface) { +    // Increment the X-position +    surface->pixdata_x++; + +    // If the x-coord has gone past the right-side edge, loop it back around and increment the y-coord +    if (surface->pixdata_x > surface->viewport_r) { +        surface->pixdata_x = surface->viewport_l; +        surface->pixdata_y++; +    } + +    // If the y-coord has gone past the bottom, loop it back to the top +    if (surface->pixdata_y > surface->viewport_b) { +        surface->pixdata_y = surface->viewport_t; +    } +} + +static inline void setpixel(rgb565_surface_painter_device_t *surface, uint16_t x, uint16_t y, uint16_t rgb565) { +    // Skip messing with the dirty info if the original value already matches +    if (surface->buffer[y * surface->base.panel_width + x] != rgb565) { +        // Maintain dirty region +        if (surface->dirty_l > x) { +            surface->dirty_l = x; +        } +        if (surface->dirty_r < x) { +            surface->dirty_r = x; +        } +        if (surface->dirty_t > y) { +            surface->dirty_t = y; +        } +        if (surface->dirty_b < y) { +            surface->dirty_b = y; +        } + +        // Always dirty after a setpixel +        surface->is_dirty = true; + +        // Update the pixel data in the buffer +        surface->buffer[y * surface->base.panel_width + x] = rgb565; +    } +} + +static inline void append_pixel(rgb565_surface_painter_device_t *surface, uint16_t rgb565) { +    setpixel(surface, surface->pixdata_x, surface->pixdata_y, rgb565); +    increment_pixdata_location(surface); +} + +static inline void stream_pixdata(rgb565_surface_painter_device_t *surface, const uint16_t *data, uint32_t native_pixel_count) { +    for (uint32_t pixel_counter = 0; pixel_counter < native_pixel_count; ++pixel_counter) { +        append_pixel(surface, data[pixel_counter]); +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Driver vtable + +static bool qp_rgb565_surface_init(painter_device_t device, painter_rotation_t rotation) { +    struct painter_driver_t *        driver  = (struct painter_driver_t *)device; +    rgb565_surface_painter_device_t *surface = (rgb565_surface_painter_device_t *)driver; +    memset(surface->buffer, 0, driver->panel_width * driver->panel_height * driver->native_bits_per_pixel / 8); +    return true; +} + +static bool qp_rgb565_surface_power(painter_device_t device, bool power_on) { +    // No-op. +    return true; +} + +static bool qp_rgb565_surface_clear(painter_device_t device) { +    struct painter_driver_t *driver = (struct painter_driver_t *)device; +    driver->driver_vtable->init(device, driver->rotation); // Re-init the surface +    return true; +} + +static bool qp_rgb565_surface_flush(painter_device_t device) { +    struct painter_driver_t *        driver  = (struct painter_driver_t *)device; +    rgb565_surface_painter_device_t *surface = (rgb565_surface_painter_device_t *)driver; +    surface->dirty_l = surface->dirty_t = UINT16_MAX; +    surface->dirty_r = surface->dirty_b = 0; +    surface->is_dirty                   = false; +    return true; +} + +static bool qp_rgb565_surface_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { +    struct painter_driver_t *        driver  = (struct painter_driver_t *)device; +    rgb565_surface_painter_device_t *surface = (rgb565_surface_painter_device_t *)driver; + +    // Set the viewport locations +    surface->viewport_l = left; +    surface->viewport_t = top; +    surface->viewport_r = right; +    surface->viewport_b = bottom; + +    // Reset the write location to the top left +    surface->pixdata_x = left; +    surface->pixdata_y = top; +    return true; +} + +// Stream pixel data to the current write position in GRAM +static bool qp_rgb565_surface_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) { +    struct painter_driver_t *        driver  = (struct painter_driver_t *)device; +    rgb565_surface_painter_device_t *surface = (rgb565_surface_painter_device_t *)driver; +    stream_pixdata(surface, (const uint16_t *)pixel_data, native_pixel_count); +    return true; +} + +// Pixel colour conversion +static bool qp_rgb565_surface_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { +    for (int16_t i = 0; i < palette_size; ++i) { +        RGB      rgb      = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v}); +        uint16_t rgb565   = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3); +        palette[i].rgb565 = __builtin_bswap16(rgb565); +    } +    return true; +} + +// Append pixels to the target location, keyed by the pixel index +static bool qp_rgb565_surface_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { +    uint16_t *buf = (uint16_t *)target_buffer; +    for (uint32_t i = 0; i < pixel_count; ++i) { +        buf[pixel_offset + i] = palette[palette_indices[i]].rgb565; +    } +    return true; +} + +const struct painter_driver_vtable_t rgb565_surface_driver_vtable = { +    .init            = qp_rgb565_surface_init, +    .power           = qp_rgb565_surface_power, +    .clear           = qp_rgb565_surface_clear, +    .flush           = qp_rgb565_surface_flush, +    .pixdata         = qp_rgb565_surface_pixdata, +    .viewport        = qp_rgb565_surface_viewport, +    .palette_convert = qp_rgb565_surface_palette_convert_rgb565_swapped, +    .append_pixels   = qp_rgb565_surface_append_pixels_rgb565, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Comms vtable + +static bool qp_rgb565_surface_comms_init(painter_device_t device) { +    // No-op. +    return true; +} +static bool qp_rgb565_surface_comms_start(painter_device_t device) { +    // No-op. +    return true; +} +static void qp_rgb565_surface_comms_stop(painter_device_t device) { +    // No-op. +} +uint32_t qp_rgb565_surface_comms_send(painter_device_t device, const void *data, uint32_t byte_count) { +    // No-op. +    return byte_count; +} + +struct painter_comms_vtable_t rgb565_surface_driver_comms_vtable = { +    // These are all effective no-op's because they're not actually needed. +    .comms_init  = qp_rgb565_surface_comms_init, +    .comms_start = qp_rgb565_surface_comms_start, +    .comms_stop  = qp_rgb565_surface_comms_stop, +    .comms_send  = qp_rgb565_surface_comms_send}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Factory function for creating a handle to an rgb565 surface + +painter_device_t qp_rgb565_make_surface(uint16_t panel_width, uint16_t panel_height, void *buffer) { +    for (uint32_t i = 0; i < RGB565_SURFACE_NUM_DEVICES; ++i) { +        rgb565_surface_painter_device_t *driver = &surface_drivers[i]; +        if (!driver->base.driver_vtable) { +            driver->base.driver_vtable         = &rgb565_surface_driver_vtable; +            driver->base.comms_vtable          = &rgb565_surface_driver_comms_vtable; +            driver->base.native_bits_per_pixel = 16; // RGB565 +            driver->base.panel_width           = panel_width; +            driver->base.panel_height          = panel_height; +            driver->base.rotation              = QP_ROTATION_0; +            driver->base.offset_x              = 0; +            driver->base.offset_y              = 0; +            driver->buffer                     = (uint16_t *)buffer; +            return (painter_device_t)driver; +        } +    } +    return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Drawing routine to copy out the dirty region and send it to another device + +bool qp_rgb565_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y) { +    struct painter_driver_t *        surface_driver = (struct painter_driver_t *)surface; +    rgb565_surface_painter_device_t *surface_handle = (rgb565_surface_painter_device_t *)surface_driver; + +    // If we're not dirty... we're done. +    if (!surface_handle->is_dirty) { +        return true; +    } + +    // Set the target drawing area +    bool ok = qp_viewport(display, x + surface_handle->dirty_l, y + surface_handle->dirty_t, x + surface_handle->dirty_r, y + surface_handle->dirty_b); +    if (!ok) { +        return false; +    } + +    // Housekeeping of the amount of pixels to transfer +    uint32_t  total_pixel_count = QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE / sizeof(uint16_t); +    uint32_t  pixel_counter     = 0; +    uint16_t *target_buffer     = (uint16_t *)qp_internal_global_pixdata_buffer; + +    // Fill the global pixdata area so that we can start transferring to the panel +    for (uint16_t y = surface_handle->dirty_t; y <= surface_handle->dirty_b; ++y) { +        for (uint16_t x = surface_handle->dirty_l; x <= surface_handle->dirty_r; ++x) { +            // Update the target buffer +            target_buffer[pixel_counter++] = surface_handle->buffer[y * surface_handle->base.panel_width + x]; + +            // If we've accumulated enough data, send it +            if (pixel_counter == total_pixel_count) { +                ok = qp_pixdata(display, qp_internal_global_pixdata_buffer, pixel_counter); +                if (!ok) { +                    return false; +                } +                // Reset the counter +                pixel_counter = 0; +            } +        } +    } + +    // If there's any leftover data, send it +    if (pixel_counter > 0) { +        ok = qp_pixdata(display, qp_internal_global_pixdata_buffer, pixel_counter); +        if (!ok) { +            return false; +        } +    } + +    // Clear the dirty info for the surface +    return qp_flush(surface); +} diff --git a/drivers/painter/generic/qp_rgb565_surface.h b/drivers/painter/generic/qp_rgb565_surface.h new file mode 100644 index 0000000000..19e919bb91 --- /dev/null +++ b/drivers/painter/generic/qp_rgb565_surface.h @@ -0,0 +1,42 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include "qp_internal.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantum Painter RGB565 surface configurables (add to your keyboard's config.h) + +#ifndef RGB565_SURFACE_NUM_DEVICES +/** + * @def This controls the maximum number of surface devices that Quantum Painter can use at any one time. + *      Increasing this number allows for multiple framebuffers to be used. Each requires its own RAM allocation. + */ +#    define RGB565_SURFACE_NUM_DEVICES 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +#ifdef QUANTUM_PAINTER_RGB565_SURFACE_ENABLE +/** + * Factory method for an RGB565 surface (aka framebuffer). + * + * @param panel_width[in] the width of the display panel + * @param panel_height[in] the height of the display panel + * @param buffer[in] pointer to a preallocated buffer of size `(sizeof(uint16_t) * panel_width * panel_height)` + * @return the device handle used with all drawing routines in Quantum Painter + */ +painter_device_t qp_rgb565_make_surface(uint16_t panel_width, uint16_t panel_height, void *buffer); + +/** + * Helper method to draw the dirty contents of the framebuffer to the target device. + * + * After successful completion, the dirty area is reset. + * + * @param surface[in] the surface to copy from + * @param display[in] the display to copy into + * @param x[in] the x-location of the original position of the framebuffer + * @param y[in] the y-location of the original position of the framebuffer + * @return whether the draw operation completed successfully + */ +bool qp_rgb565_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y); +#endif // QUANTUM_PAINTER_RGB565_SURFACE_ENABLE diff --git a/drivers/painter/tft_panel/qp_tft_panel.c b/drivers/painter/tft_panel/qp_tft_panel.c index ad83b6c792..e7c744ab34 100644 --- a/drivers/painter/tft_panel/qp_tft_panel.c +++ b/drivers/painter/tft_panel/qp_tft_panel.c @@ -7,8 +7,6 @@  #include "qp_draw.h"  #include "qp_tft_panel.h" -#define BYTE_SWAP(x) (((((uint16_t)(x)) >> 8) & 0x00FF) | ((((uint16_t)(x)) << 8) & 0xFF00)) -  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  // Quantum Painter API implementations @@ -94,7 +92,7 @@ bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_      for (int16_t i = 0; i < palette_size; ++i) {          RGB      rgb      = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});          uint16_t rgb565   = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3); -        palette[i].rgb565 = BYTE_SWAP(rgb565); +        palette[i].rgb565 = __builtin_bswap16(rgb565);      }      return true;  } diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c index 8bd4eb736e..4aed5fe67a 100644 --- a/drivers/sensors/cirque_pinnacle.c +++ b/drivers/sensors/cirque_pinnacle.c @@ -4,8 +4,6 @@  // refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/documentation  #include "cirque_pinnacle.h" -#include "print.h" -#include "debug.h"  #include "wait.h"  #include "timer.h" @@ -27,12 +25,6 @@ void cirque_pinnacle_enable_feed(bool feedEnable);  void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count);  void RAP_Write(uint8_t address, uint8_t data); -#ifdef CONSOLE_ENABLE -void print_byte(uint8_t byte) { -    xprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); -} -#endif -  #if CIRQUE_PINNACLE_POSITION_MODE  /*  Logical Scaling Functions */  // Clips raw coordinates to "reachable" window of sensor diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h index fa06e047f2..8717b32991 100644 --- a/drivers/sensors/cirque_pinnacle.h +++ b/drivers/sensors/cirque_pinnacle.h @@ -5,6 +5,7 @@  #include "cirque_pinnacle_regdefs.h"  #include <stdint.h>  #include <stdbool.h> +#include "pointing_device_internal.h"  #ifndef CIRQUE_PINNACLE_TIMEOUT  #    define CIRQUE_PINNACLE_TIMEOUT 20 // I2C timeout in milliseconds diff --git a/drivers/sensors/cirque_pinnacle_gestures.c b/drivers/sensors/cirque_pinnacle_gestures.c index a73b745e59..ae3eca71c2 100644 --- a/drivers/sensors/cirque_pinnacle_gestures.c +++ b/drivers/sensors/cirque_pinnacle_gestures.c @@ -37,14 +37,6 @@ static report_mouse_t trackpad_tap(report_mouse_t mouse_report, pinnacle_data_t          if (!touchData.zValue) {              if (timer_elapsed(tap.timer) < CIRQUE_PINNACLE_TAPPING_TERM && tap.timer != 0) {                  mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); -                pointing_device_set_report(mouse_report); -                pointing_device_send(); -#    if TAP_CODE_DELAY > 0 -                wait_ms(TAP_CODE_DELAY); -#    endif -                mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1); -                pointing_device_set_report(mouse_report); -                pointing_device_send();              }          }          tap.timer = timer_read(); diff --git a/drivers/sensors/cirque_pinnacle_i2c.c b/drivers/sensors/cirque_pinnacle_i2c.c index b328dd9a7a..3c11e5f079 100644 --- a/drivers/sensors/cirque_pinnacle_i2c.c +++ b/drivers/sensors/cirque_pinnacle_i2c.c @@ -1,8 +1,6 @@  // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license  #include "cirque_pinnacle.h"  #include "i2c_master.h" -#include "print.h" -#include "debug.h"  #include "stdio.h"  // Masks for Cirque Register Access Protocol (RAP) @@ -18,9 +16,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {      if (touchpad_init) {          i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT);          if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) { -#ifdef CONSOLE_ENABLE -            dprintf("error cirque_pinnacle i2c_readReg\n"); -#endif +            pd_dprintf("error cirque_pinnacle i2c_readReg\n");              touchpad_init = false;          }          i2c_stop(); @@ -33,9 +29,7 @@ void RAP_Write(uint8_t address, uint8_t data) {      if (touchpad_init) {          if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) { -#ifdef CONSOLE_ENABLE -            dprintf("error cirque_pinnacle i2c_writeReg\n"); -#endif +            pd_dprintf("error cirque_pinnacle i2c_writeReg\n");              touchpad_init = false;          }          i2c_stop(); diff --git a/drivers/sensors/cirque_pinnacle_spi.c b/drivers/sensors/cirque_pinnacle_spi.c index bd980fc863..5cb39aebb0 100644 --- a/drivers/sensors/cirque_pinnacle_spi.c +++ b/drivers/sensors/cirque_pinnacle_spi.c @@ -1,8 +1,6 @@  // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license  #include "cirque_pinnacle.h"  #include "spi_master.h" -#include "print.h" -#include "debug.h"  // Masks for Cirque Register Access Protocol (RAP)  #define WRITE_MASK 0x80 @@ -24,9 +22,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {                  data[i] = spi_write(FILLER_BYTE); // write filler, receive data on the third filler send              }          } else { -#ifdef CONSOLE_ENABLE -            dprintf("error cirque_pinnacle spi_start read\n"); -#endif +            pd_dprintf("error cirque_pinnacle spi_start read\n");              touchpad_init = false;          }          spi_stop(); @@ -42,9 +38,7 @@ void RAP_Write(uint8_t address, uint8_t data) {              spi_write(cmdByte);              spi_write(data);          } else { -#ifdef CONSOLE_ENABLE -            dprintf("error cirque_pinnacle spi_start write\n"); -#endif +            pd_dprintf("error cirque_pinnacle spi_start write\n");              touchpad_init = false;          }          spi_stop(); diff --git a/drivers/sensors/pimoroni_trackball.c b/drivers/sensors/pimoroni_trackball.c index 88a351316b..326e59744f 100644 --- a/drivers/sensors/pimoroni_trackball.c +++ b/drivers/sensors/pimoroni_trackball.c @@ -14,10 +14,10 @@   * You should have received a copy of the GNU General Public License   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ + +#include "pointing_device_internal.h"  #include "pimoroni_trackball.h"  #include "i2c_master.h" -#include "print.h" -#include "debug.h"  #include "timer.h"  // clang-format off @@ -58,20 +58,17 @@ void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {      uint8_t                              data[4] = {r, g, b, w};      __attribute__((unused)) i2c_status_t status  = i2c_writeReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LED_RED, data, sizeof(data), PIMORONI_TRACKBALL_TIMEOUT); -#ifdef CONSOLE_ENABLE -    if (debug_mouse) dprintf("Trackball RGBW i2c_status_t: %d\n", status); -#endif +    pd_dprintf("Trackball RGBW i2c_status_t: %d\n", status);  }  i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) {      i2c_status_t status = i2c_readReg(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), PIMORONI_TRACKBALL_TIMEOUT); -#ifdef CONSOLE_ENABLE -    if (debug_mouse) { -        static uint16_t d_timer; -        if (timer_elapsed(d_timer) > PIMORONI_TRACKBALL_DEBUG_INTERVAL) { -            dprintf("Trackball READ i2c_status_t: %d L: %d R: %d Up: %d D: %d SW: %d\n", status, data->left, data->right, data->up, data->down, data->click); -            d_timer = timer_read(); -        } + +#ifdef POINTING_DEVICE_DEBUG +    static uint16_t d_timer; +    if (timer_elapsed(d_timer) > PIMORONI_TRACKBALL_DEBUG_INTERVAL) { +        pd_dprintf("Trackball READ i2c_status_t: %d L: %d R: %d Up: %d D: %d SW: %d\n", status, data->left, data->right, data->up, data->down, data->click); +        d_timer = timer_read();      }  #endif diff --git a/drivers/sensors/pmw33xx_common.c b/drivers/sensors/pmw33xx_common.c index 13164cb150..b8d4e532ca 100644 --- a/drivers/sensors/pmw33xx_common.c +++ b/drivers/sensors/pmw33xx_common.c @@ -7,9 +7,8 @@  // Copyright 2020 Ploopy Corporation  // SPDX-License-Identifier: GPL-2.0-or-later -#include "debug.h" +#include "pointing_device_internal.h"  #include "pmw33xx_common.h" -#include "print.h"  #include "string.h"  #include "wait.h"  #include "spi_master.h" @@ -18,10 +17,10 @@  extern const uint8_t pmw33xx_firmware_data[PMW33XX_FIRMWARE_LENGTH] PROGMEM;  extern const uint8_t pmw33xx_firmware_signature[3] PROGMEM; -static const pin_t cs_pins[]                                 = PMW33XX_CS_PINS; -static bool        in_burst[sizeof(cs_pins) / sizeof(pin_t)] = {0}; +static const pin_t cs_pins[]                     = PMW33XX_CS_PINS; +static bool        in_burst[ARRAY_SIZE(cs_pins)] = {0}; -const size_t pmw33xx_number_of_sensors = sizeof(cs_pins) / sizeof(pin_t); +const size_t pmw33xx_number_of_sensors = ARRAY_SIZE(cs_pins);  bool __attribute__((cold)) pmw33xx_upload_firmware(uint8_t sensor);  bool __attribute__((cold)) pmw33xx_check_signature(uint8_t sensor); @@ -154,7 +153,7 @@ bool pmw33xx_init(uint8_t sensor) {      pmw33xx_read(sensor, REG_Delta_Y_H);      if (!pmw33xx_upload_firmware(sensor)) { -        dprintf("PMW33XX (%d): firmware upload failed!\n", sensor); +        pd_dprintf("PMW33XX (%d): firmware upload failed!\n", sensor);          return false;      } @@ -170,7 +169,7 @@ bool pmw33xx_init(uint8_t sensor) {      pmw33xx_write(sensor, REG_Lift_Config, PMW33XX_LIFTOFF_DISTANCE);      if (!pmw33xx_check_signature(sensor)) { -        dprintf("PMW33XX (%d): firmware signature verification failed!\n", sensor); +        pd_dprintf("PMW33XX (%d): firmware signature verification failed!\n", sensor);          return false;      } @@ -185,7 +184,7 @@ pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor) {      }      if (!in_burst[sensor]) { -        dprintf("PMW33XX (%d): burst\n", sensor); +        pd_dprintf("PMW33XX (%d): burst\n", sensor);          if (!pmw33xx_write(sensor, REG_Motion_Burst, 0x00)) {              return report;          } @@ -208,9 +207,7 @@ pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor) {      spi_stop(); -    if (debug_config.mouse) { -        dprintf("PMW33XX (%d): motion: 0x%x dx: %i dy: %i\n", sensor, report.motion.w, report.delta_x, report.delta_y); -    } +    pd_dprintf("PMW33XX (%d): motion: 0x%x dx: %i dy: %i\n", sensor, report.motion.w, report.delta_x, report.delta_y);      report.delta_x *= -1;      report.delta_y *= -1; | 
