Remove old HAL components and refactored GPS-related code (#583)
- Added generic GPS/GNSS support with device detection, configuration, and persistent settings. - Improved device and module lifecycle management. - Added flexible filesystem locking support for displays and storage. - Improved display-idle and keyboard backlight handling. - Updated architecture, driver, module, testing, and licensing documentation. - Removed old HAL device and related code.
This commit is contained in:
committed by
GitHub
parent
29e80cfd65
commit
2a2558b29a
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include "sdl_display.h"
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/display.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
constexpr auto* TAG = "SdlDisplay";
|
||||
#define GET_CONFIG(device) (static_cast<const SdlDisplayConfig*>((device)->config))
|
||||
|
||||
struct SdlDisplayInternal {
|
||||
SDL_Window* window;
|
||||
SDL_Renderer* renderer;
|
||||
SDL_Texture* texture;
|
||||
};
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
static error_t start(Device* device) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
auto* internal = static_cast<SdlDisplayInternal*>(malloc(sizeof(SdlDisplayInternal)));
|
||||
if (internal == nullptr) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
LOG_E(TAG, "SDL_InitSubSystem failed: %s", SDL_GetError());
|
||||
free(internal);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
internal->window = SDL_CreateWindow(
|
||||
"Tactility",
|
||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
config->horizontal_resolution, config->vertical_resolution,
|
||||
SDL_WINDOW_SHOWN
|
||||
);
|
||||
internal->renderer = internal->window != nullptr
|
||||
? SDL_CreateRenderer(internal->window, -1, SDL_RENDERER_ACCELERATED)
|
||||
: nullptr;
|
||||
internal->texture = internal->renderer != nullptr
|
||||
? SDL_CreateTexture(internal->renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING,
|
||||
config->horizontal_resolution, config->vertical_resolution)
|
||||
: nullptr;
|
||||
|
||||
if (internal->window == nullptr || internal->renderer == nullptr || internal->texture == nullptr) {
|
||||
LOG_E(TAG, "Failed to create SDL window: %s", SDL_GetError());
|
||||
if (internal->texture != nullptr) SDL_DestroyTexture(internal->texture);
|
||||
if (internal->renderer != nullptr) SDL_DestroyRenderer(internal->renderer);
|
||||
if (internal->window != nullptr) SDL_DestroyWindow(internal->window);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
free(internal);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
device_set_driver_data(device, internal);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
auto* internal = static_cast<SdlDisplayInternal*>(device_get_driver_data(device));
|
||||
|
||||
SDL_DestroyTexture(internal->texture);
|
||||
SDL_DestroyRenderer(internal->renderer);
|
||||
SDL_DestroyWindow(internal->window);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
|
||||
free(internal);
|
||||
device_set_driver_data(device, nullptr);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region DisplayApi
|
||||
|
||||
static error_t sdl_display_reset(Device*) { return ERROR_NONE; }
|
||||
static error_t sdl_display_init(Device*) { return ERROR_NONE; }
|
||||
|
||||
static error_t sdl_display_draw_bitmap(Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) {
|
||||
auto* internal = static_cast<SdlDisplayInternal*>(device_get_driver_data(device));
|
||||
|
||||
SDL_Rect rect = { x_start, y_start, x_end - x_start, y_end - y_start };
|
||||
// RGB565 = 2 bytes/pixel.
|
||||
if (SDL_UpdateTexture(internal->texture, &rect, color_data, (x_end - x_start) * 2) != 0) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
SDL_RenderClear(internal->renderer);
|
||||
SDL_RenderCopy(internal->renderer, internal->texture, nullptr, nullptr);
|
||||
SDL_RenderPresent(internal->renderer);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static enum DisplayColorFormat sdl_display_get_color_format(Device*) {
|
||||
return DISPLAY_COLOR_FORMAT_RGB565;
|
||||
}
|
||||
|
||||
static uint16_t sdl_display_get_resolution_x(Device* device) {
|
||||
return GET_CONFIG(device)->horizontal_resolution;
|
||||
}
|
||||
|
||||
static uint16_t sdl_display_get_resolution_y(Device* device) {
|
||||
return GET_CONFIG(device)->vertical_resolution;
|
||||
}
|
||||
|
||||
static void sdl_display_get_frame_buffer(Device*, uint8_t, void** out_buffer) {
|
||||
*out_buffer = nullptr;
|
||||
}
|
||||
|
||||
static uint8_t sdl_display_get_frame_buffer_count(Device*) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static const DisplayApi sdl_display_api = {
|
||||
.capabilities = 0,
|
||||
.reset = sdl_display_reset,
|
||||
.init = sdl_display_init,
|
||||
.draw_bitmap = sdl_display_draw_bitmap,
|
||||
.mirror = nullptr,
|
||||
.swap_xy = nullptr,
|
||||
.get_swap_xy = nullptr,
|
||||
.get_mirror_x = nullptr,
|
||||
.get_mirror_y = nullptr,
|
||||
.set_gap = nullptr,
|
||||
.get_gap_x = nullptr,
|
||||
.get_gap_y = nullptr,
|
||||
.invert_color = nullptr,
|
||||
.disp_on_off = nullptr,
|
||||
.disp_sleep = nullptr,
|
||||
.get_color_format = sdl_display_get_color_format,
|
||||
.get_resolution_x = sdl_display_get_resolution_x,
|
||||
.get_resolution_y = sdl_display_get_resolution_y,
|
||||
.get_frame_buffer = sdl_display_get_frame_buffer,
|
||||
.get_frame_buffer_count = sdl_display_get_frame_buffer_count,
|
||||
.get_backlight = nullptr,
|
||||
.has_capability = nullptr,
|
||||
};
|
||||
|
||||
extern Module simulator_module;
|
||||
|
||||
Driver sdl_display_driver = {
|
||||
.name = "sdl-display",
|
||||
.compatible = (const char*[]) { "tactility,sdl-display", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = &sdl_display_api,
|
||||
.device_type = &DISPLAY_TYPE,
|
||||
.owner = &simulator_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct SdlDisplayConfig {
|
||||
uint16_t horizontal_resolution;
|
||||
uint16_t vertical_resolution;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include "sdl_input.h"
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t KEY_QUEUE_CAPACITY = 32;
|
||||
|
||||
SdlPointerState pointer_state = { 0, 0, false };
|
||||
|
||||
uint32_t key_queue[KEY_QUEUE_CAPACITY];
|
||||
size_t key_queue_head = 0;
|
||||
size_t key_queue_count = 0;
|
||||
|
||||
bool text_input_started = false;
|
||||
|
||||
void push_key(uint32_t key) {
|
||||
if (key == 0 || key_queue_count >= KEY_QUEUE_CAPACITY) {
|
||||
return;
|
||||
}
|
||||
key_queue[(key_queue_head + key_queue_count) % KEY_QUEUE_CAPACITY] = key;
|
||||
key_queue_count++;
|
||||
}
|
||||
|
||||
// Mirrors LVGL's own lv_sdl_keyboard.c keycode_to_ctrl_key(): maps navigation/control keys to
|
||||
// LV_KEY_* constants. Printable characters arrive separately via SDL_TEXTINPUT.
|
||||
uint32_t keycode_to_key(SDL_Keycode sdl_key) {
|
||||
switch (sdl_key) {
|
||||
case SDLK_RIGHT: return LV_KEY_RIGHT;
|
||||
case SDLK_LEFT: return LV_KEY_LEFT;
|
||||
case SDLK_UP: return LV_KEY_UP;
|
||||
case SDLK_DOWN: return LV_KEY_DOWN;
|
||||
case SDLK_ESCAPE: return LV_KEY_ESC;
|
||||
case SDLK_BACKSPACE: return LV_KEY_BACKSPACE;
|
||||
case SDLK_DELETE: return LV_KEY_DEL;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER: return LV_KEY_ENTER;
|
||||
case SDLK_TAB: return LV_KEY_NEXT;
|
||||
case SDLK_HOME: return LV_KEY_HOME;
|
||||
case SDLK_END: return LV_KEY_END;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sdl_input_pump() {
|
||||
if (!text_input_started) {
|
||||
SDL_StartTextInput();
|
||||
text_input_started = true;
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
pointer_state.x = event.motion.x;
|
||||
pointer_state.y = event.motion.y;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||
pointer_state.x = event.button.x;
|
||||
pointer_state.y = event.button.y;
|
||||
pointer_state.pressed = true;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||
pointer_state.pressed = false;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
push_key(keycode_to_key(event.key.keysym.sym));
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
// ASCII only (first byte of event.text.text) - sufficient for a simulator keyboard.
|
||||
push_key(static_cast<uint8_t>(event.text.text[0]));
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
exit(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_input_get_pointer_state(SdlPointerState* out_state) {
|
||||
*out_state = pointer_state;
|
||||
}
|
||||
|
||||
bool sdl_input_pop_key(uint32_t* out_key) {
|
||||
if (key_queue_count == 0) {
|
||||
return false;
|
||||
}
|
||||
*out_key = key_queue[key_queue_head];
|
||||
key_queue_head = (key_queue_head + 1) % KEY_QUEUE_CAPACITY;
|
||||
key_queue_count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdl_input_has_queued_key() {
|
||||
return key_queue_count > 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Latest pointer (mouse) state as tracked by sdl_input_pump().
|
||||
*/
|
||||
struct SdlPointerState {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
bool pressed;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Drains all pending SDL events exactly once, updating the pointer state and key queue
|
||||
* below. Safe to call from both the sdl-pointer and sdl-keyboard drivers' polling functions:
|
||||
* SDL_PollEvent() drains a single global queue, so whichever driver is polled first on a given
|
||||
* LVGL indev tick pumps events for both.
|
||||
*/
|
||||
void sdl_input_pump(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the pointer state as of the most recent sdl_input_pump() call.
|
||||
*/
|
||||
void sdl_input_get_pointer_state(struct SdlPointerState* out_state);
|
||||
|
||||
/**
|
||||
* @brief Pops the next queued key event (produced by SDL_KEYDOWN/SDL_TEXTINPUT during
|
||||
* sdl_input_pump()).
|
||||
* @retval false when no key event is pending
|
||||
*/
|
||||
bool sdl_input_pop_key(uint32_t* out_key);
|
||||
|
||||
/**
|
||||
* @brief Returns true if another key event is queued after the one just popped.
|
||||
*/
|
||||
bool sdl_input_has_queued_key(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include "sdl_input.h"
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/keyboard.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
static error_t start(Device*) { return ERROR_NONE; }
|
||||
static error_t stop(Device*) { return ERROR_NONE; }
|
||||
|
||||
// endregion
|
||||
|
||||
// region KeyboardApi
|
||||
|
||||
static error_t sdl_keyboard_read_key(Device*, KeyboardKeyData* data) {
|
||||
sdl_input_pump();
|
||||
|
||||
uint32_t key = 0;
|
||||
if (sdl_input_pop_key(&key)) {
|
||||
data->key = key;
|
||||
data->pressed = true;
|
||||
data->continue_reading = sdl_input_has_queued_key();
|
||||
} else {
|
||||
data->key = 0;
|
||||
data->pressed = false;
|
||||
data->continue_reading = false;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static const KeyboardApi sdl_keyboard_api = {
|
||||
.read_key = sdl_keyboard_read_key,
|
||||
.get_backlight = nullptr,
|
||||
};
|
||||
|
||||
extern Module simulator_module;
|
||||
|
||||
Driver sdl_keyboard_driver = {
|
||||
.name = "sdl-keyboard",
|
||||
.compatible = (const char*[]) { "tactility,sdl-keyboard", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = &sdl_keyboard_api,
|
||||
.device_type = &KEYBOARD_TYPE,
|
||||
.owner = &simulator_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include "sdl_input.h"
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/pointer.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
static error_t start(Device*) { return ERROR_NONE; }
|
||||
static error_t stop(Device*) { return ERROR_NONE; }
|
||||
|
||||
// endregion
|
||||
|
||||
// region PointerApi
|
||||
|
||||
static error_t sdl_pointer_read_data(Device*, TickType_t) {
|
||||
sdl_input_pump();
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static bool sdl_pointer_get_touched_points(Device*, uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* point_count, uint8_t max_point_count) {
|
||||
SdlPointerState state;
|
||||
sdl_input_get_pointer_state(&state);
|
||||
|
||||
if (!state.pressed || max_point_count == 0) {
|
||||
*point_count = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
x[0] = static_cast<uint16_t>(state.x);
|
||||
y[0] = static_cast<uint16_t>(state.y);
|
||||
if (strength != nullptr) {
|
||||
strength[0] = 0xFFFF;
|
||||
}
|
||||
*point_count = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static const PointerApi sdl_pointer_api = {
|
||||
.enter_sleep = nullptr,
|
||||
.exit_sleep = nullptr,
|
||||
.read_data = sdl_pointer_read_data,
|
||||
.get_touched_points = sdl_pointer_get_touched_points,
|
||||
.set_swap_xy = nullptr,
|
||||
.get_swap_xy = nullptr,
|
||||
.set_mirror_x = nullptr,
|
||||
.get_mirror_x = nullptr,
|
||||
.set_mirror_y = nullptr,
|
||||
.get_mirror_y = nullptr,
|
||||
};
|
||||
|
||||
extern Module simulator_module;
|
||||
|
||||
Driver sdl_pointer_driver = {
|
||||
.name = "sdl-pointer",
|
||||
.compatible = (const char*[]) { "tactility,sdl-pointer", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = &sdl_pointer_api,
|
||||
.device_type = &POINTER_TYPE,
|
||||
.owner = &simulator_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
Reference in New Issue
Block a user