Display and touch kernel drivers

This commit is contained in:
Ken Van Hoeylandt 2026-07-10 00:31:24 +02:00
parent 16a61a087c
commit 32022c7e67
9 changed files with 590 additions and 0 deletions

View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <Tactility/hal/display/DisplayDriver.h>
#include <tactility/device.h>
namespace tt::hal::display {
/** Wraps a TactilityKernel Device of type DISPLAY_TYPE as a DisplayDriver. */
class KernelDisplayDriver final : public DisplayDriver {
::Device* device;
public:
explicit KernelDisplayDriver(::Device* device);
ColorFormat getColorFormat() const override;
uint16_t getPixelWidth() const override;
uint16_t getPixelHeight() const override;
bool drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) override;
uint8_t getFrameBuffers(void* outBuffers[2]) const override;
};
}

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <Tactility/hal/touch/TouchDriver.h>
#include <tactility/device.h>
namespace tt::hal::touch {
/** Wraps a TactilityKernel Device of type TOUCH_TYPE as a TouchDriver. */
class KernelTouchDriver final : public TouchDriver {
::Device* device;
public:
explicit KernelTouchDriver(::Device* device);
bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) override;
};
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <cstdint>
namespace tt::hal::touch {
class TouchDriver {

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
#include <Tactility/hal/display/KernelDisplayDriver.h>
#include <tactility/drivers/display.h>
#include <algorithm>
#include <cassert>
#include <utility>
namespace tt::hal::display {
static ColorFormat toColorFormat(DisplayColorFormat format) {
switch (format) {
case DISPLAY_COLOR_FORMAT_MONOCHROME:
return ColorFormat::Monochrome;
case DISPLAY_COLOR_FORMAT_BGR565:
return ColorFormat::BGR565;
case DISPLAY_COLOR_FORMAT_BGR565_SWAPPED:
return ColorFormat::BGR565Swapped;
case DISPLAY_COLOR_FORMAT_RGB565:
return ColorFormat::RGB565;
case DISPLAY_COLOR_FORMAT_RGB565_SWAPPED:
return ColorFormat::RGB565Swapped;
case DISPLAY_COLOR_FORMAT_RGB888:
return ColorFormat::RGB888;
default:
std::unreachable();
}
}
KernelDisplayDriver::KernelDisplayDriver(::Device* device) : device(device) {
assert(device_get_type(device) == &DISPLAY_TYPE);
}
ColorFormat KernelDisplayDriver::getColorFormat() const {
return toColorFormat(display_get_color_format(device));
}
uint16_t KernelDisplayDriver::getPixelWidth() const {
return display_get_resolution_x(device);
}
uint16_t KernelDisplayDriver::getPixelHeight() const {
return display_get_resolution_y(device);
}
bool KernelDisplayDriver::drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) {
return display_draw_bitmap(device, xStart, yStart, xEnd, yEnd, pixelData) == ERROR_NONE;
}
uint8_t KernelDisplayDriver::getFrameBuffers(void* outBuffers[2]) const {
uint8_t count = std::min<uint8_t>(display_get_frame_buffer_count(device), 2);
for (uint8_t i = 0; i < count; i++) {
display_get_frame_buffer(device, i, &outBuffers[i]);
}
return count;
}
}

View File

@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
#include <Tactility/hal/touch/KernelTouchDriver.h>
#include <tactility/drivers/touch.h>
#include <cassert>
namespace tt::hal::touch {
// Bus reads are expected to complete quickly; bound the wait so a stalled controller can't block the LVGL indev poll.
static constexpr TickType_t READ_TIMEOUT = pdMS_TO_TICKS(10);
KernelTouchDriver::KernelTouchDriver(::Device* device) : device(device) {
assert(device_get_type(device) == &TOUCH_TYPE);
}
bool KernelTouchDriver::getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) {
if (touch_read_data(device, READ_TIMEOUT) != ERROR_NONE) {
return false;
}
return touch_get_touched_points(device, x, y, strength, pointCount, maxPointCount);
}
}

View File

@ -5,7 +5,201 @@
extern "C" {
#endif
#include <stdint.h>
#include <tactility/device.h>
#include <tactility/error.h>
/**
* @brief Pixel color formats supported by display panel drivers.
*/
enum DisplayColorFormat {
DISPLAY_COLOR_FORMAT_MONOCHROME = 0x0, // 1 bpp
DISPLAY_COLOR_FORMAT_BGR565 = 0x1,
DISPLAY_COLOR_FORMAT_BGR565_SWAPPED = 0x2,
DISPLAY_COLOR_FORMAT_RGB565 = 0x3,
DISPLAY_COLOR_FORMAT_RGB565_SWAPPED = 0x4,
DISPLAY_COLOR_FORMAT_RGB888 = 0x5,
};
/**
* @brief API for display panel drivers.
*/
struct DisplayApi {
/**
* @brief Performs a hardware reset of the panel (e.g. toggling a reset GPIO).
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*reset)(struct Device* device);
/**
* @brief Sends the panel's initialization command sequence. Call after reset().
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*init)(struct Device* device);
/**
* @brief Draws pixel data into the given rectangle.
* @param[in] device the display device
* @param[in] x_start left edge (inclusive)
* @param[in] y_start top edge (inclusive)
* @param[in] x_end right edge (exclusive)
* @param[in] y_end bottom edge (exclusive)
* @param[in] color_data pixel data in the panel's configured color format
* @retval ERROR_NONE when the operation was successful
*/
error_t (*draw_bitmap)(struct Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data);
/**
* @brief Mirrors the image along the X and/or Y axis.
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*mirror)(struct Device* device, bool x_axis, bool y_axis);
/**
* @brief Swaps the X and Y axes (rotates the coordinate system).
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*swap_xy)(struct Device* device, bool swap_axes);
/**
* @brief Sets a coordinate offset applied to all draw operations.
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*set_gap)(struct Device* device, int32_t x_gap, int32_t y_gap);
/**
* @brief Inverts the panel's color output.
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*invert_color)(struct Device* device, bool invert_color_data);
/**
* @brief Turns the panel's display output on or off.
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*disp_on_off)(struct Device* device, bool on_off);
/**
* @brief Puts the panel into or out of its low-power sleep mode.
* @param[in] device the display device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*disp_sleep)(struct Device* device, bool sleep);
/**
* @brief Gets the panel's pixel color format.
* @param[in] device the display device
* @return the color format
*/
enum DisplayColorFormat (*get_color_format)(struct Device* device);
/**
* @brief Gets the panel's horizontal resolution in pixels.
* @param[in] device the display device
* @return the horizontal resolution
*/
uint16_t (*get_resolution_x)(struct Device* device);
/**
* @brief Gets the panel's vertical resolution in pixels.
* @param[in] device the display device
* @return the vertical resolution
*/
uint16_t (*get_resolution_y)(struct Device* device);
/**
* @brief Gets a pointer to one of the panel's frame buffers, for panels that expose direct frame buffer access.
* @param[in] device the display device
* @param[in] index the frame buffer index (see get_frame_buffer_count())
* @param[out] out_buffer the buffer pointer
*/
void (*get_frame_buffer)(struct Device* device, uint8_t index, void** out_buffer);
/**
* @brief Gets the number of frame buffers exposed by the panel via get_frame_buffer(). 0 when unsupported.
* @param[in] device the display device
* @return the frame buffer count
*/
uint8_t (*get_frame_buffer_count)(struct Device* device);
};
/**
* @brief Performs a hardware reset of the panel using the specified display.
*/
error_t display_reset(struct Device* device);
/**
* @brief Sends the panel's initialization command sequence using the specified display.
*/
error_t display_init(struct Device* device);
/**
* @brief Draws pixel data into the given rectangle using the specified display.
*/
error_t display_draw_bitmap(struct Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data);
/**
* @brief Mirrors the image along the X and/or Y axis using the specified display.
*/
error_t display_mirror(struct Device* device, bool x_axis, bool y_axis);
/**
* @brief Swaps the X and Y axes using the specified display.
*/
error_t display_swap_xy(struct Device* device, bool swap_axes);
/**
* @brief Sets a coordinate offset applied to all draw operations using the specified display.
*/
error_t display_set_gap(struct Device* device, int32_t x_gap, int32_t y_gap);
/**
* @brief Inverts the panel's color output using the specified display.
*/
error_t display_invert_color(struct Device* device, bool invert_color_data);
/**
* @brief Turns the panel's display output on or off using the specified display.
*/
error_t display_disp_on_off(struct Device* device, bool on_off);
/**
* @brief Puts the panel into or out of its low-power sleep mode using the specified display.
*/
error_t display_disp_sleep(struct Device* device, bool sleep);
/**
* @brief Gets the pixel color format using the specified display.
*/
enum DisplayColorFormat display_get_color_format(struct Device* device);
/**
* @brief Gets the horizontal resolution in pixels using the specified display.
*/
uint16_t display_get_resolution_x(struct Device* device);
/**
* @brief Gets the vertical resolution in pixels using the specified display.
*/
uint16_t display_get_resolution_y(struct Device* device);
/**
* @brief Gets a pointer to one of the panel's frame buffers using the specified display.
*/
void display_get_frame_buffer(struct Device* device, uint8_t index, void** out_buffer);
/**
* @brief Gets the number of frame buffers exposed by the panel using the specified display.
*/
uint8_t display_get_frame_buffer_count(struct Device* device);
extern const struct DeviceType DISPLAY_TYPE;

View File

@ -5,7 +5,144 @@
extern "C" {
#endif
#include <stdint.h>
#include <tactility/device.h>
#include <tactility/error.h>
#include <tactility/freertos/freertos.h>
/**
* @brief API for touch controller drivers.
*/
struct TouchApi {
/**
* @brief Puts the touch controller into its low-power sleep mode.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*enter_sleep)(struct Device* device);
/**
* @brief Wakes the touch controller from sleep mode.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*exit_sleep)(struct Device* device);
/**
* @brief Performs a blocking read of the latest touch data from the controller into its internal state.
* Call this before get_touched_points().
* @param[in] device the touch device
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE when the read operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*read_data)(struct Device* device, TickType_t timeout);
/**
* @brief Retrieves the coordinates most recently read by read_data().
* @param[in] device the touch device
* @param[out] x array of X coordinates
* @param[out] y array of Y coordinates
* @param[out] strength optional array of touch strengths (nullable)
* @param[out] point_count the number of points currently touched
* @param[in] max_point_count the maximum number of points the arrays can hold
* @return true when touched and coordinates are available
*/
bool (*get_touched_points)(struct Device* device, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count);
/**
* @brief Sets whether the X and Y axes should be swapped.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*set_swap_xy)(struct Device* device, bool swap);
/**
* @brief Gets whether the X and Y axes are swapped.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*get_swap_xy)(struct Device* device, bool* swap);
/**
* @brief Sets whether the X axis should be mirrored.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*set_mirror_x)(struct Device* device, bool mirror);
/**
* @brief Gets whether the X axis is mirrored.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*get_mirror_x)(struct Device* device, bool* mirror);
/**
* @brief Sets whether the Y axis should be mirrored.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*set_mirror_y)(struct Device* device, bool mirror);
/**
* @brief Gets whether the Y axis is mirrored.
* @param[in] device the touch device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*get_mirror_y)(struct Device* device, bool* mirror);
};
/**
* @brief Puts the touch controller into its low-power sleep mode using the specified touch device.
*/
error_t touch_enter_sleep(struct Device* device);
/**
* @brief Wakes the touch controller from sleep mode using the specified touch device.
*/
error_t touch_exit_sleep(struct Device* device);
/**
* @brief Performs a blocking read of the latest touch data using the specified touch device.
*/
error_t touch_read_data(struct Device* device, TickType_t timeout);
/**
* @brief Retrieves the coordinates most recently read using the specified touch device.
*/
bool touch_get_touched_points(struct Device* device, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count);
/**
* @brief Sets whether the X and Y axes should be swapped using the specified touch device.
*/
error_t touch_set_swap_xy(struct Device* device, bool swap);
/**
* @brief Gets whether the X and Y axes are swapped using the specified touch device.
*/
error_t touch_get_swap_xy(struct Device* device, bool* swap);
/**
* @brief Sets whether the X axis should be mirrored using the specified touch device.
*/
error_t touch_set_mirror_x(struct Device* device, bool mirror);
/**
* @brief Gets whether the X axis is mirrored using the specified touch device.
*/
error_t touch_get_mirror_x(struct Device* device, bool* mirror);
/**
* @brief Sets whether the Y axis should be mirrored using the specified touch device.
*/
error_t touch_set_mirror_y(struct Device* device, bool mirror);
/**
* @brief Gets whether the Y axis is mirrored using the specified touch device.
*/
error_t touch_get_mirror_y(struct Device* device, bool* mirror);
extern const struct DeviceType TOUCH_TYPE;

View File

@ -1,8 +1,81 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/display.h>
#include <tactility/device.h>
#define DISPLAY_DRIVER_API(driver) ((struct DisplayApi*)driver->api)
extern "C" {
error_t display_reset(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->reset(device);
}
error_t display_init(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->init(device);
}
error_t display_draw_bitmap(struct Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->draw_bitmap(device, x_start, y_start, x_end, y_end, color_data);
}
error_t display_mirror(struct Device* device, bool x_axis, bool y_axis) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->mirror(device, x_axis, y_axis);
}
error_t display_swap_xy(struct Device* device, bool swap_axes) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->swap_xy(device, swap_axes);
}
error_t display_set_gap(struct Device* device, int32_t x_gap, int32_t y_gap) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->set_gap(device, x_gap, y_gap);
}
error_t display_invert_color(struct Device* device, bool invert_color_data) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->invert_color(device, invert_color_data);
}
error_t display_disp_on_off(struct Device* device, bool on_off) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->disp_on_off(device, on_off);
}
error_t display_disp_sleep(struct Device* device, bool sleep) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->disp_sleep(device, sleep);
}
enum DisplayColorFormat display_get_color_format(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->get_color_format(device);
}
uint16_t display_get_resolution_x(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->get_resolution_x(device);
}
uint16_t display_get_resolution_y(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->get_resolution_y(device);
}
void display_get_frame_buffer(struct Device* device, uint8_t index, void** out_buffer) {
const auto* driver = device_get_driver(device);
DISPLAY_DRIVER_API(driver)->get_frame_buffer(device, index, out_buffer);
}
uint8_t display_get_frame_buffer_count(struct Device* device) {
const auto* driver = device_get_driver(device);
return DISPLAY_DRIVER_API(driver)->get_frame_buffer_count(device);
}
const struct DeviceType DISPLAY_TYPE {
.name = "display"
};

View File

@ -1,8 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/touch.h>
#include <tactility/device.h>
#define TOUCH_DRIVER_API(driver) ((struct TouchApi*)driver->api)
extern "C" {
error_t touch_enter_sleep(struct Device* device) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->enter_sleep(device);
}
error_t touch_exit_sleep(struct Device* device) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->exit_sleep(device);
}
error_t touch_read_data(struct Device* device, TickType_t timeout) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->read_data(device, timeout);
}
bool touch_get_touched_points(struct Device* device, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->get_touched_points(device, x, y, strength, point_count, max_point_count);
}
error_t touch_set_swap_xy(struct Device* device, bool swap) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->set_swap_xy(device, swap);
}
error_t touch_get_swap_xy(struct Device* device, bool* swap) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->get_swap_xy(device, swap);
}
error_t touch_set_mirror_x(struct Device* device, bool mirror) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->set_mirror_x(device, mirror);
}
error_t touch_get_mirror_x(struct Device* device, bool* mirror) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->get_mirror_x(device, mirror);
}
error_t touch_set_mirror_y(struct Device* device, bool mirror) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->set_mirror_y(device, mirror);
}
error_t touch_get_mirror_y(struct Device* device, bool* mirror) {
const auto* driver = device_get_driver(device);
return TOUCH_DRIVER_API(driver)->get_mirror_y(device, mirror);
}
const struct DeviceType TOUCH_TYPE {
.name = "touch"
};