aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c_master.h15
-rw-r--r--drivers/oled/glcdfont.c264
-rw-r--r--drivers/painter/comms/qp_comms_spi.c2
-rw-r--r--drivers/painter/generic/qp_surface.h10
-rw-r--r--drivers/painter/generic/qp_surface_internal.h1
-rw-r--r--drivers/painter/generic/qp_surface_rgb565.c2
-rw-r--r--drivers/painter/generic/qp_surface_rgb888.c143
-rw-r--r--drivers/painter/ili9xxx/qp_ili9486.c2
-rw-r--r--drivers/painter/tft_panel/qp_tft_panel.c7
-rw-r--r--drivers/sensors/paw3222.c174
-rw-r--r--drivers/sensors/paw3222.h47
11 files changed, 647 insertions, 20 deletions
diff --git a/drivers/i2c_master.h b/drivers/i2c_master.h
index dbe1cd42fa..5f6094bc81 100644
--- a/drivers/i2c_master.h
+++ b/drivers/i2c_master.h
@@ -73,6 +73,21 @@ i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t lengt
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
/**
+ * \brief Send multiple bytes and then receive multiple bytes from the selected I2C device.
+ *
+ * \param address The 7-bit I2C address of the device.
+ * \param tx_data A pointer to the data to transmit.
+ * \param tx_length The number of bytes to write. Take care not to overrun the length of `tx_data`.
+ * \param rx_data A pointer to a buffer to read into.
+ * \param rx_length The number of bytes to read. Take care not to overrun the length of `rx_data`.
+ * \param timeout The time in milliseconds to wait for a response from the target device.
+ *
+ * \return `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
+ */
+
+i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout);
+
+/**
* \brief Write to a register with an 8-bit address on the I2C device.
*
* \param devaddr The 7-bit I2C address of the device.
diff --git a/drivers/oled/glcdfont.c b/drivers/oled/glcdfont.c
index 0e201d71ee..4099389691 100644
--- a/drivers/oled/glcdfont.c
+++ b/drivers/oled/glcdfont.c
@@ -1,16 +1,256 @@
-#include "progmem.h"
+// Copyright 2025 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later WITH BSD-2-Clause
-// Helidox 8x6 font with QMK Firmware Logo
-// Online editor: http://teripom.x0.com/
+#include "progmem.h"
+/**
+ * QMK 6x8 Font for LCD and OLED displays
+ *
+ * Derived from the first half of the Adafruit GFX Library font:
+ * https://github.com/adafruit/Adafruit-GFX-Library
+ *
+ * The first 128 characters match that of code page 437, the character set used by the original IBM PC, which includes all printable ASCII characters.
+ * Each byte represents a column of 8 pixels, with the least significant bit being the top of the glyph.
+ *
+ * A large 21x3 character QMK Firmware logo is encoded from 0x80-0x94, 0xA0-0xB4, and 0xC0-0xD4.
+ * 2x2 character OS logos for Apple, Windows, Linux and Android are encoded from 0x95-0x9C and 0xB5-0xBC.
+ */
static const unsigned char font[] PROGMEM = {
- 0x07, 0x08, 0x7F, 0x08, 0x07, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
- 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
- 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
- 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
- 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
- 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xF0, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0x3F, 0xF8, 0xF8, 0xFF, 0x38, 0xFF, 0xF8, 0xF8, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF8, 0xFC, 0x3E,
- 0x1E, 0x06, 0x01, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B, 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE, 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x49, 0x49, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xDF, 0xBF, 0xBF, 0x00, 0xBF, 0xBF, 0xDF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x60, 0x60, 0xE0, 0xBF, 0x1F, 0x00, 0x7F, 0x7F, 0x07, 0x1E, 0x38, 0x1E, 0x07, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x0E, 0x1F, 0x3B, 0x71, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x0C, 0x0C, 0x0C, 0x00, 0x7E, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x7E, 0x7E, 0x03, 0x03, 0x7F, 0x7E, 0x00, 0x0F,
- 0x3E, 0x70, 0x3C, 0x06, 0x3C, 0x70, 0x3E, 0x0F, 0x00, 0x32, 0x7B, 0x49, 0x49, 0x3F, 0x7E, 0x00, 0x7F, 0x7E, 0x03, 0x03, 0x00, 0x1E, 0x3F, 0x69, 0x69, 0x6F, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3C, 0x78, 0x70, 0x60, 0x00, 0x00, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20, 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00, 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F, 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x07, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x7E, 0x0F, 0x0F, 0x7F, 0x0F, 0x7F, 0x0F, 0x0F, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x08, 0x7F, 0x08, 0x07, 0x00, // 0x00 NUL / Ψ
+ 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00, // 0x01 SOH / ☺︎
+ 0xC1, 0x94, 0xB0, 0x94, 0xC1, 0x00, // 0x02 STX / ☻
+ 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, // 0x03 ETX / ♥︎
+ 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, // 0x04 EOT / ♦︎
+ 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00, // 0x05 ENQ / ♣︎
+ 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, // 0x06 ACK / ♠︎
+ 0x00, 0x18, 0x3C, 0x18, 0x00, 0x00, // 0x07 BEL / •
+ 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, // 0x08 BS / ◘
+ 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, // 0x09 HT / ○
+ 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00, // 0x0A LF / ◙
+ 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00, // 0x0B VT / ♂︎
+ 0x26, 0x29, 0x79, 0x29, 0x26, 0x00, // 0x0C FF / ♀︎
+ 0x40, 0x7F, 0x05, 0x05, 0x07, 0x00, // 0x0D CR / ♪
+ 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00, // 0x0E SO / ♫
+ 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00, // 0x0F SI / ☼
+
+ 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00, // 0x10 DLE / ►
+ 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00, // 0x11 DC1 / ◄
+ 0x14, 0x22, 0x7F, 0x22, 0x14, 0x00, // 0x12 DC2 / ↕︎
+ 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00, // 0x13 DC3 / ‼︎
+ 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, // 0x14 DC4 / ¶
+ 0x00, 0x66, 0x89, 0x95, 0x6A, 0x00, // 0x15 NAK / §
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, // 0x16 SYN / ▬
+ 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00, // 0x17 ETB / ↨
+ 0x08, 0x04, 0x7E, 0x04, 0x08, 0x00, // 0x18 CAN / ↑
+ 0x10, 0x20, 0x7E, 0x20, 0x10, 0x00, // 0x19 EM / ↓
+ 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, // 0x1A SUB / →
+ 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, // 0x1B ESC / ←
+ 0x1E, 0x10, 0x10, 0x10, 0x10, 0x00, // 0x1C FS / ∟
+ 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00, // 0x1D GS / ↔︎
+ 0x30, 0x38, 0x3E, 0x38, 0x30, 0x00, // 0x1E RS / ▲
+ 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, // 0x1F US / ▼
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space
+ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, // 0x21 !
+ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, // 0x22 "
+ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, // 0x23 #
+ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, // 0x24 $
+ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, // 0x25 %
+ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, // 0x26 &
+ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, // 0x27 '
+ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, // 0x28 (
+ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, // 0x29 )
+ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, // 0x2A *
+ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, // 0x2B +
+ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, // 0x2C ,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x2D -
+ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // 0x2E .
+ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, // 0x2F /
+
+ 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, // 0x30 0
+ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, // 0x31 1
+ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, // 0x32 2
+ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, // 0x33 3
+ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, // 0x34 4
+ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, // 0x35 5
+ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, // 0x36 6
+ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, // 0x37 7
+ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, // 0x38 8
+ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, // 0x39 9
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, // 0x3A :
+ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, // 0x3B ;
+ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // 0x3C <
+ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, // 0x3D =
+ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, // 0x3E >
+ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, // 0x3F ?
+
+ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, // 0x40 @
+ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, // 0x41 A
+ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, // 0x42 B
+ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, // 0x43 C
+ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, // 0x44 D
+ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, // 0x45 E
+ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, // 0x46 F
+ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, // 0x47 G
+ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, // 0x48 H
+ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, // 0x49 I
+ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, // 0x4A J
+ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, // 0x4B K
+ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, // 0x4C L
+ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, // 0x4D M
+ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, // 0x4E N
+ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, // 0x4F O
+
+ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, // 0x50 P
+ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, // 0x51 Q
+ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, // 0x52 R
+ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, // 0x53 S
+ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, // 0x54 T
+ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, // 0x55 U
+ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, // 0x56 V
+ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, // 0x57 W
+ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, // 0x58 X
+ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, // 0x59 Y
+ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, // 0x5A Z
+ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, // 0x5B [
+ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, // 0x5C Backslash
+ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0x5D ]
+ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, // 0x5E ^
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, // 0x5F _
+
+ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, // 0x60 `
+ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, // 0x61 a
+ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, // 0x62 b
+ 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, // 0x63 c
+ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, // 0x64 d
+ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, // 0x65 e
+ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, // 0x66 f
+ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, // 0x67 g
+ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, // 0x68 h
+ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, // 0x69 i
+ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, // 0x6A j
+ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, // 0x6B k
+ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, // 0x6C l
+ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, // 0x6D m
+ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, // 0x6E n
+ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, // 0x6F o
+
+ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, // 0x70 p
+ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, // 0x71 q
+ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, // 0x72 r
+ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, // 0x73 s
+ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, // 0x74 t
+ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, // 0x75 u
+ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, // 0x76 v
+ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, // 0x77 w
+ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // 0x78 x
+ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, // 0x79 y
+ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, // 0x7A z
+ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, // 0x7B {
+ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, // 0x7C |
+ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, // 0x7D }
+ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, // 0x7E ~
+ 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00, // 0x7F DEL / ⌂
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 QMK Logo Top 1
+ 0x00, 0x00, 0x80, 0x80, 0xE0, 0xF0, // 0x81 QMK Logo Top 2
+ 0xF0, 0xFC, 0x70, 0xFC, 0xF0, 0x7C, // 0x82 QMK Logo Top 3
+ 0xF0, 0xFC, 0x70, 0xFC, 0xF0, 0xF0, // 0x83 QMK Logo Top 4
+ 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, // 0x84 QMK Logo Top 5
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x85 QMK Logo Top 6
+ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, // 0x86 QMK Logo Top 7
+ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, // 0x87 QMK Logo Top 8
+ 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, // 0x88 QMK Logo Top 9
+ 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, // 0x89 QMK Logo Top 10
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, // 0x8A QMK Logo Top 11
+ 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, // 0x8B QMK Logo Top 12
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8C QMK Logo Top 13
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8D QMK Logo Top 14
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8E QMK Logo Top 15
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x8F QMK Logo Top 16
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 QMK Logo Top 17
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x91 QMK Logo Top 18
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x92 QMK Logo Top 19
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x93 QMK Logo Top 20
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x94 QMK Logo Top 21
+ 0x00, 0xC0, 0xF0, 0xF8, 0xFC, 0x3E, // 0x95 Apple Logo TL
+ 0x1E, 0x06, 0x01, 0x00, 0x00, 0x00, // 0x96 Apple Logo TR
+ 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0x97 Windows Logo TL
+ 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0x98 Windows Logo TR
+ 0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B, // 0x99 Linux Logo TL
+ 0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00, // 0x9A Linux Logo TR
+ 0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE, // 0x9B Android Logo TL
+ 0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00, // 0x9C Android Logo TR
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x9D
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x9E
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x9F
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 QMK Logo Middle 1
+ 0x00, 0x00, 0xAA, 0xAA, 0xFF, 0xFF, // 0xA1 QMK Logo Middle 2
+ 0xFF, 0xFF, 0xE0, 0xDF, 0xDF, 0x00, // 0xA2 QMK Logo Middle 3
+ 0xDF, 0xDF, 0xE0, 0xFF, 0xFF, 0xFF, // 0xA3 QMK Logo Middle 4
+ 0xFF, 0xAA, 0xAA, 0x00, 0x00, 0x00, // 0xA4 QMK Logo Middle 5
+ 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, // 0xA5 QMK Logo Middle 6
+ 0xC1, 0xC1, 0xC1, 0x7F, 0x3E, 0x00, // 0xA6 QMK Logo Middle 7
+ 0xFF, 0xFF, 0x0F, 0x3C, 0x78, 0x3C, // 0xA7 QMK Logo Middle 8
+ 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, // 0xA8 QMK Logo Middle 9
+ 0x1C, 0x3E, 0x77, 0xE3, 0xC1, 0x00, // 0xA9 QMK Logo Middle 10
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 0xAA QMK Logo Middle 11
+ 0x19, 0x19, 0x19, 0x00, 0xFD, 0xFD, // 0xAB QMK Logo Middle 12
+ 0x00, 0xFE, 0xFC, 0x06, 0x06, 0x00, // 0xAC QMK Logo Middle 13
+ 0xFE, 0xFC, 0x06, 0x06, 0xFC, 0xFC, // 0xAD QMK Logo Middle 14
+ 0x06, 0x06, 0xFE, 0xFC, 0x00, 0x1E, // 0xAE QMK Logo Middle 15
+ 0x7C, 0xE0, 0x78, 0x0C, 0x78, 0xE0, // 0xAF QMK Logo Middle 16
+
+ 0x7C, 0x1E, 0x00, 0x64, 0xF6, 0x92, // 0xB0 QMK Logo Middle 17
+ 0x92, 0x7E, 0xFC, 0x00, 0xFE, 0xFC, // 0xB1 QMK Logo Middle 18
+ 0x06, 0x06, 0x00, 0x3C, 0x7E, 0xD2, // 0xB2 QMK Logo Middle 19
+ 0xD2, 0xDE, 0x4C, 0x00, 0x00, 0x00, // 0xB3 QMK Logo Middle 20
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB4 QMK Logo Middle 21
+ 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x3C, // 0xB5 Apple Logo BL
+ 0x78, 0x70, 0x60, 0x00, 0x00, 0x00, // 0xB6 Apple Logo BR
+ 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0xB7 Windows Logo BL
+ 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0xB8 Windows Logo BR
+ 0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20, // 0xB9 Linux Logo BL
+ 0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00, // 0xBA Linux Logo BR
+ 0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F, // 0xBB Android Logo BL
+ 0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00, // 0xBC Android Logo BR
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xBD
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xBE
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xBF
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 QMK Logo Bottom 1
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, // 0xC1 QMK Logo Bottom 2
+ 0x07, 0x1F, 0x07, 0x1F, 0x07, 0x1F, // 0xC2 QMK Logo Bottom 3
+ 0x07, 0x1F, 0x07, 0x1F, 0x07, 0x07, // 0xC3 QMK Logo Bottom 4
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC4 QMK Logo Bottom 5
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC5 QMK Logo Bottom 6
+ 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, // 0xC6 QMK Logo Bottom 7
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC7 QMK Logo Bottom 8
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 QMK Logo Bottom 9
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC9 QMK Logo Bottom 10
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCA QMK Logo Bottom 11
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCB QMK Logo Bottom 12
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCC QMK Logo Bottom 13
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCD QMK Logo Bottom 14
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCE QMK Logo Bottom 15
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xCF QMK Logo Bottom 16
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 QMK Logo Bottom 17
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD1 QMK Logo Bottom 18
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD2 QMK Logo Bottom 19
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD3 QMK Logo Bottom 10
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD4 QMK Logo Bottom 21
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD5
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD6
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD7
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD9
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xDA
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xDB
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xDC
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xDD
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xDE
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0xDF
};
diff --git a/drivers/painter/comms/qp_comms_spi.c b/drivers/painter/comms/qp_comms_spi.c
index 1ef4ea3bae..6227d7d656 100644
--- a/drivers/painter/comms/qp_comms_spi.c
+++ b/drivers/painter/comms/qp_comms_spi.c
@@ -36,7 +36,7 @@ uint32_t qp_comms_spi_send_data(painter_device_t device, const void *data, uint3
const uint32_t max_msg_length = 1024;
while (bytes_remaining > 0) {
- uint32_t bytes_this_loop = QP_MIN(bytes_remaining, max_msg_length);
+ uint32_t bytes_this_loop = MIN(bytes_remaining, max_msg_length);
spi_transmit(p, bytes_this_loop);
p += bytes_this_loop;
bytes_remaining -= bytes_this_loop;
diff --git a/drivers/painter/generic/qp_surface.h b/drivers/painter/generic/qp_surface.h
index a291793649..f602a8770b 100644
--- a/drivers/painter/generic/qp_surface.h
+++ b/drivers/painter/generic/qp_surface.h
@@ -51,6 +51,16 @@ painter_device_t qp_make_rgb565_surface(uint16_t panel_width, uint16_t panel_hei
painter_device_t qp_make_mono1bpp_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
/**
+ * Factory method for an RGB888 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 uint8_t buffer of size `SURFACE_REQUIRED_BUFFER_BYTE_SIZE(panel_width, panel_height, 16)`
+ * @return the device handle used with all drawing routines in Quantum Painter
+ */
+painter_device_t qp_make_rgb888_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
+
+/**
* Helper method to draw the contents of the framebuffer to the target device.
*
* After successful completion, the dirty area is reset.
diff --git a/drivers/painter/generic/qp_surface_internal.h b/drivers/painter/generic/qp_surface_internal.h
index 89cab11b0d..0b4d32fa34 100644
--- a/drivers/painter/generic/qp_surface_internal.h
+++ b/drivers/painter/generic/qp_surface_internal.h
@@ -45,6 +45,7 @@ typedef struct surface_painter_device_t {
void *buffer;
uint8_t *u8buffer;
uint16_t *u16buffer;
+ rgb_t *rgbbuffer;
};
// Manually manage the viewport for streaming pixel data to the display
diff --git a/drivers/painter/generic/qp_surface_rgb565.c b/drivers/painter/generic/qp_surface_rgb565.c
index b81b0c43bc..8da63b14b3 100644
--- a/drivers/painter/generic/qp_surface_rgb565.c
+++ b/drivers/painter/generic/qp_surface_rgb565.c
@@ -52,7 +52,7 @@ static bool qp_surface_pixdata_rgb565(painter_device_t device, const void *pixel
// Pixel colour conversion
static bool qp_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_t rgb = hsv_to_rgb_nocie((hsv_t){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
+ rgb_t rgb = hsv_to_rgb_nocie(palette[i].hsv888);
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);
}
diff --git a/drivers/painter/generic/qp_surface_rgb888.c b/drivers/painter/generic/qp_surface_rgb888.c
new file mode 100644
index 0000000000..2c04136c36
--- /dev/null
+++ b/drivers/painter/generic/qp_surface_rgb888.c
@@ -0,0 +1,143 @@
+// Copyright 2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef QUANTUM_PAINTER_SURFACE_ENABLE
+
+# include "color.h"
+# include "qp_draw.h"
+# include "qp_surface_internal.h"
+# include "qp_comms_dummy.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Surface driver impl: rgb888
+
+static inline void setpixel_rgb888(surface_painter_device_t *surface, uint16_t x, uint16_t y, rgb_t rgb888) {
+ uint16_t w = surface->base.panel_width;
+ uint16_t h = surface->base.panel_height;
+
+ // Drop out if it's off-screen
+ if (x >= w || y >= h) {
+ return;
+ }
+
+ // Skip messing with the dirty info if the original value already matches
+ if (memcmp(&surface->rgbbuffer[y * w + x], &rgb888, sizeof(rgb_t)) != 0) {
+ // Update the dirty region
+ qp_surface_update_dirty(&surface->dirty, x, y);
+
+ // Update the pixel data in the buffer
+ surface->rgbbuffer[y * w + x] = rgb888;
+ }
+}
+
+static inline void append_pixel_rgb888(surface_painter_device_t *surface, rgb_t rgb888) {
+ setpixel_rgb888(surface, surface->viewport.pixdata_x, surface->viewport.pixdata_y, rgb888);
+ qp_surface_increment_pixdata_location(&surface->viewport);
+}
+
+static inline void stream_pixdata_rgb888(surface_painter_device_t *surface, const rgb_t *data, uint32_t native_pixel_count) {
+ for (uint32_t pixel_counter = 0; pixel_counter < native_pixel_count; ++pixel_counter) {
+ append_pixel_rgb888(surface, data[pixel_counter]);
+ }
+}
+
+// Stream pixel data to the current write position in GRAM
+static bool qp_surface_pixdata_rgb888(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) {
+ painter_driver_t *driver = (painter_driver_t *)device;
+ surface_painter_device_t *surface = (surface_painter_device_t *)driver;
+ stream_pixdata_rgb888(surface, (const rgb_t *)pixel_data, native_pixel_count);
+ return true;
+}
+
+// Pixel colour conversion
+static bool qp_surface_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
+ for (int16_t i = 0; i < palette_size; ++i) {
+ palette[i].rgb888 = hsv_to_rgb_nocie(palette[i].hsv888);
+ }
+ return true;
+}
+
+// Append pixels to the target location, keyed by the pixel index
+static bool qp_surface_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {
+ rgb_t *buf = (rgb_t *)target_buffer;
+ for (uint32_t i = 0; i < pixel_count; ++i) {
+ buf[pixel_offset + i] = palette[palette_indices[i]].rgb888;
+ }
+ return true;
+}
+
+static bool rgb888_target_pixdata_transfer(painter_driver_t *surface_driver, painter_driver_t *target_driver, uint16_t x, uint16_t y, bool entire_surface) {
+ surface_painter_device_t *surface_handle = (surface_painter_device_t *)surface_driver;
+
+ uint16_t l = entire_surface ? 0 : surface_handle->dirty.l;
+ uint16_t t = entire_surface ? 0 : surface_handle->dirty.t;
+ uint16_t r = entire_surface ? (surface_handle->base.panel_width - 1) : surface_handle->dirty.r;
+ uint16_t b = entire_surface ? (surface_handle->base.panel_height - 1) : surface_handle->dirty.b;
+
+ // Set the target drawing area
+ bool ok = qp_viewport((painter_device_t)target_driver, x + l, y + t, x + r, y + b);
+ if (!ok) {
+ qp_dprintf("rgb888_target_pixdata_transfer: fail (could not set target viewport)\n");
+ return false;
+ }
+
+ // Housekeeping of the amount of pixels to transfer
+ uint32_t total_pixel_count = (8 * QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE) / surface_driver->native_bits_per_pixel;
+ uint32_t pixel_counter = 0;
+ rgb_t *target_buffer = (rgb_t *)qp_internal_global_pixdata_buffer;
+
+ // Fill the global pixdata area so that we can start transferring to the panel
+ for (uint16_t y = t; y <= b; ++y) {
+ for (uint16_t x = l; x <= r; ++x) {
+ // Update the target buffer
+ target_buffer[pixel_counter++] = surface_handle->rgbbuffer[y * surface_handle->base.panel_width + x];
+
+ // If we've accumulated enough data, send it
+ if (pixel_counter == total_pixel_count) {
+ ok = qp_pixdata((painter_device_t)target_driver, qp_internal_global_pixdata_buffer, pixel_counter);
+ if (!ok) {
+ qp_dprintf("rgb888_target_pixdata_transfer: fail (could not stream pixdata to target)\n");
+ return false;
+ }
+ // Reset the counter
+ pixel_counter = 0;
+ }
+ }
+ }
+
+ // If there's any leftover data, send it
+ if (pixel_counter > 0) {
+ ok = qp_pixdata((painter_device_t)target_driver, qp_internal_global_pixdata_buffer, pixel_counter);
+ if (!ok) {
+ qp_dprintf("rgb888_target_pixdata_transfer: fail (could not stream pixdata to target)\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool qp_surface_append_pixdata_rgb888(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) {
+ target_buffer[pixdata_offset] = pixdata_byte;
+ return true;
+}
+
+const surface_painter_driver_vtable_t rgb888_surface_driver_vtable = {
+ .base =
+ {
+ .init = qp_surface_init,
+ .power = qp_surface_power,
+ .clear = qp_surface_clear,
+ .flush = qp_surface_flush,
+ .pixdata = qp_surface_pixdata_rgb888,
+ .viewport = qp_surface_viewport,
+ .palette_convert = qp_surface_palette_convert_rgb888,
+ .append_pixels = qp_surface_append_pixels_rgb888,
+ .append_pixdata = qp_surface_append_pixdata_rgb888,
+ },
+ .target_pixdata_transfer = rgb888_target_pixdata_transfer,
+};
+
+SURFACE_FACTORY_FUNCTION_IMPL(qp_make_rgb888_surface, rgb888_surface_driver_vtable, 24);
+
+#endif // QUANTUM_PAINTER_SURFACE_ENABLE
diff --git a/drivers/painter/ili9xxx/qp_ili9486.c b/drivers/painter/ili9xxx/qp_ili9486.c
index d1e5e12288..27fcd49873 100644
--- a/drivers/painter/ili9xxx/qp_ili9486.c
+++ b/drivers/painter/ili9xxx/qp_ili9486.c
@@ -92,7 +92,7 @@ static uint32_t qp_comms_spi_send_data_odd_cs_pulse(painter_device_t device, con
gpio_write_pin_high(comms_config->dc_pin);
while (bytes_remaining > 0) {
- uint32_t bytes_this_loop = QP_MIN(bytes_remaining, max_msg_length);
+ uint32_t bytes_this_loop = MIN(bytes_remaining, max_msg_length);
bool odd_bytes = bytes_this_loop & 1;
// send data
diff --git a/drivers/painter/tft_panel/qp_tft_panel.c b/drivers/painter/tft_panel/qp_tft_panel.c
index af9e3e6465..3de0d62c72 100644
--- a/drivers/painter/tft_panel/qp_tft_panel.c
+++ b/drivers/painter/tft_panel/qp_tft_panel.c
@@ -90,7 +90,7 @@ bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint3
bool qp_tft_panel_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_t rgb = hsv_to_rgb_nocie((hsv_t){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
+ rgb_t rgb = hsv_to_rgb_nocie(palette[i].hsv888);
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);
}
@@ -99,10 +99,7 @@ bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_
bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
for (int16_t i = 0; i < palette_size; ++i) {
- rgb_t rgb = hsv_to_rgb_nocie((hsv_t){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
- palette[i].rgb888.r = rgb.r;
- palette[i].rgb888.g = rgb.g;
- palette[i].rgb888.b = rgb.b;
+ palette[i].rgb888 = hsv_to_rgb_nocie(palette[i].hsv888);
}
return true;
}
diff --git a/drivers/sensors/paw3222.c b/drivers/sensors/paw3222.c
new file mode 100644
index 0000000000..57f89a12d6
--- /dev/null
+++ b/drivers/sensors/paw3222.c
@@ -0,0 +1,174 @@
+/* Copyright 2024 Colin Lam (Ploopy Corporation)
+ *
+ * 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 "paw3222.h"
+#include "wait.h"
+#include "gpio.h"
+#include "spi_master.h"
+#include "pointing_device_internal.h"
+
+#define MSB1 0x80
+#define MSB0 0x7F
+
+const pointing_device_driver_t paw3222_pointing_device_driver = {
+ .init = paw3222_init,
+ .get_report = paw3222_get_report,
+ .set_cpi = paw3222_set_cpi,
+ .get_cpi = paw3222_get_cpi,
+};
+
+// Convert a 12-bit twos complement binary-represented number into a
+// signed 12-bit integer.
+static int16_t convert_twoscomp_12(uint16_t data) {
+ if ((data & 0x800) == 0x800)
+ return -2048 + (data & 0x7FF);
+ else
+ return data;
+}
+
+void paw3222_write(uint8_t reg_addr, uint8_t data) {
+ spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
+ wait_us(1); // Tncs_lead
+ spi_write(reg_addr | MSB1);
+ spi_write(data);
+ wait_us(1); // Tncs_lag
+ spi_stop();
+}
+
+uint8_t paw3222_read(uint8_t reg_addr) {
+ spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
+ wait_us(1); // Tncs_lead
+ spi_write(reg_addr & MSB0);
+ wait_us(10); // Tprep_rd
+ uint8_t data = spi_read();
+ wait_us(1); // Tncs_lag
+ spi_stop();
+
+ return data;
+}
+
+bool paw3222_init(void) {
+ gpio_set_pin_output(PAW3222_CS_PIN);
+
+ // CS must be kept low at power-up stage for at least 1ms
+ gpio_write_pin_low(PAW3222_CS_PIN);
+ wait_ms(10);
+ gpio_write_pin_high(PAW3222_CS_PIN);
+
+ spi_init();
+
+ // reboot
+ paw3222_write(0x06, 0x80);
+ wait_ms(50);
+
+ if (!paw3222_check_signature()) {
+ return false;
+ }
+
+ // initialize
+ paw3222_write(0x09, 0x5A);
+ paw3222_write(0x0D, 0x23);
+ paw3222_write(0x0E, 0x24);
+ paw3222_write(0x19, 0x1C);
+ paw3222_write(0x05, 0xA1);
+ paw3222_write(0x2B, 0x6D);
+ paw3222_write(0x30, 0x2E);
+ paw3222_write(0x5C, 0xDF);
+ paw3222_write(0x7F, 0x01);
+ paw3222_write(0x06, 0x14);
+ paw3222_write(0x31, 0x25);
+ paw3222_write(0x34, 0xC4);
+ paw3222_write(0x36, 0xCC);
+ paw3222_write(0x37, 0x42);
+ paw3222_write(0x38, 0x01);
+ paw3222_write(0x3A, 0x76);
+ paw3222_write(0x3B, 0x34);
+ paw3222_write(0x42, 0x39);
+ paw3222_write(0x43, 0xF2);
+ paw3222_write(0x44, 0x39);
+ paw3222_write(0x45, 0xF0);
+ paw3222_write(0x46, 0x12);
+ paw3222_write(0x47, 0x39);
+ paw3222_write(0x48, 0xE3);
+ paw3222_write(0x49, 0x48);
+ paw3222_write(0x4A, 0xD3);
+ paw3222_write(0x4B, 0x98);
+ paw3222_write(0x64, 0x46);
+ paw3222_write(0x71, 0x28);
+ paw3222_write(0x72, 0x28);
+ paw3222_write(0x7F, 0x00);
+ paw3222_write(0x09, 0x00);
+
+ // read a burst, then discard
+ paw3222_read_burst();
+
+ return true;
+}
+
+report_paw3222_t paw3222_read_burst(void) {
+ report_paw3222_t report = {0};
+
+ uint8_t motion = paw3222_read(0x02);
+ if ((motion & MSB1) == MSB1) {
+ // Motion detected
+ uint16_t dx = (uint16_t)paw3222_read(0x03);
+ uint16_t dy = (uint16_t)paw3222_read(0x04);
+ uint16_t dxy_hi = (uint16_t)paw3222_read(0x12);
+
+ dx = dx | ((dxy_hi & 0xF0) << 4);
+ dy = dy | ((dxy_hi & 0x0F) << 8);
+
+ report.dx = convert_twoscomp_12(dx);
+ report.dy = convert_twoscomp_12(dy);
+ }
+
+ return report;
+}
+
+void paw3222_set_cpi(uint16_t cpi) {
+ uint16_t cpival = (cpi) < (480) ? (480) : ((cpi) > (4020) ? (4020) : (cpi));
+ uint8_t cpival_x = (cpival + (30 / 2)) / 30;
+ uint8_t cpival_y = (cpival + (29 / 2)) / 29;
+
+ paw3222_write(0x09, 0x5A);
+ paw3222_write(0x0D, cpival_x);
+ paw3222_write(0x0E, cpival_y);
+ paw3222_write(0x09, 0x00);
+}
+
+uint16_t paw3222_get_cpi(void) {
+ uint8_t cpival = paw3222_read(0x0D);
+ return (uint16_t)(cpival * 30);
+}
+
+report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
+ report_paw3222_t data = paw3222_read_burst();
+
+ if (data.dx != 0 || data.dy != 0) {
+ pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
+ mouse_report.x = CONSTRAIN_HID_XY(data.dx);
+ mouse_report.y = CONSTRAIN_HID_XY(data.dy);
+ }
+
+ return mouse_report;
+}
+
+bool paw3222_check_signature(void) {
+ uint8_t checkval_1 = paw3222_read(0x00);
+ uint8_t checkval_2 = paw3222_read(0x01);
+
+ return (checkval_1 == 0x30 && checkval_2 == 0x02);
+}
diff --git a/drivers/sensors/paw3222.h b/drivers/sensors/paw3222.h
new file mode 100644
index 0000000000..8dbf6a38bb
--- /dev/null
+++ b/drivers/sensors/paw3222.h
@@ -0,0 +1,47 @@
+/* Copyright 2024 Colin Lam (Ploopy Corporation)
+ *
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include "pointing_device.h"
+
+#ifndef PAW3222_CS_PIN
+# ifdef POINTING_DEVICE_CS_PIN
+# define PAW3222_CS_PIN POINTING_DEVICE_CS_PIN
+# else
+# error "No chip select pin defined -- missing POINTING_DEVICE_CS_PIN or PAW3222_CS_PIN define"
+# endif
+#endif
+
+#ifndef PAW3222_SPI_DIVISOR
+# error "No PAW3222 SPI divisor defined -- missing PAW3222_SPI_DIVISOR"
+#endif
+
+typedef struct {
+ int16_t dx;
+ int16_t dy;
+} report_paw3222_t;
+
+extern const pointing_device_driver_t paw3222_pointing_device_driver;
+
+bool paw3222_init(void);
+report_paw3222_t paw3222_read_burst(void);
+void paw3222_set_cpi(uint16_t cpi);
+uint16_t paw3222_get_cpi(void);
+report_mouse_t paw3222_get_report(report_mouse_t mouse_report);
+bool paw3222_check_signature(void);