diff --git a/Tactility/Include/Tactility/hal/display/KernelDisplayDriver.h b/Tactility/Include/Tactility/hal/display/KernelDisplayDriver.h new file mode 100644 index 000000000..757653690 --- /dev/null +++ b/Tactility/Include/Tactility/hal/display/KernelDisplayDriver.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#include + +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; +}; + +} diff --git a/Tactility/Include/Tactility/hal/touch/KernelTouchDriver.h b/Tactility/Include/Tactility/hal/touch/KernelTouchDriver.h new file mode 100644 index 000000000..ab410467e --- /dev/null +++ b/Tactility/Include/Tactility/hal/touch/KernelTouchDriver.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#include + +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; +}; + +} diff --git a/Tactility/Include/Tactility/hal/touch/TouchDriver.h b/Tactility/Include/Tactility/hal/touch/TouchDriver.h index 4db3b2c7f..58aa2515f 100644 --- a/Tactility/Include/Tactility/hal/touch/TouchDriver.h +++ b/Tactility/Include/Tactility/hal/touch/TouchDriver.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace tt::hal::touch { class TouchDriver { diff --git a/Tactility/Source/hal/display/KernelDisplayDriver.cpp b/Tactility/Source/hal/display/KernelDisplayDriver.cpp new file mode 100644 index 000000000..5808efbf7 --- /dev/null +++ b/Tactility/Source/hal/display/KernelDisplayDriver.cpp @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include + +#include +#include +#include + +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(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; +} + +} diff --git a/Tactility/Source/hal/touch/KernelTouchDriver.cpp b/Tactility/Source/hal/touch/KernelTouchDriver.cpp new file mode 100644 index 000000000..03bf938da --- /dev/null +++ b/Tactility/Source/hal/touch/KernelTouchDriver.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include + +#include + +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); +} + +} diff --git a/TactilityKernel/include/tactility/drivers/display.h b/TactilityKernel/include/tactility/drivers/display.h index 982e679ef..d34dfd10c 100644 --- a/TactilityKernel/include/tactility/drivers/display.h +++ b/TactilityKernel/include/tactility/drivers/display.h @@ -5,7 +5,201 @@ extern "C" { #endif +#include + #include +#include + +/** + * @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; diff --git a/TactilityKernel/include/tactility/drivers/touch.h b/TactilityKernel/include/tactility/drivers/touch.h index 071aff778..fea8b1a7e 100644 --- a/TactilityKernel/include/tactility/drivers/touch.h +++ b/TactilityKernel/include/tactility/drivers/touch.h @@ -5,7 +5,144 @@ extern "C" { #endif +#include + #include +#include +#include + +/** + * @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; diff --git a/TactilityKernel/source/drivers/display.cpp b/TactilityKernel/source/drivers/display.cpp index 3b49e4963..bc1a12e31 100644 --- a/TactilityKernel/source/drivers/display.cpp +++ b/TactilityKernel/source/drivers/display.cpp @@ -1,8 +1,81 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include + +#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" }; diff --git a/TactilityKernel/source/drivers/touch.cpp b/TactilityKernel/source/drivers/touch.cpp index f324ebb8f..7cf0376d9 100644 --- a/TactilityKernel/source/drivers/touch.cpp +++ b/TactilityKernel/source/drivers/touch.cpp @@ -1,8 +1,61 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include + +#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" };