Files
tactility/Devices/simulator/Source/module.cpp
T
2026-09-23 19:13:39 -04:00

143 lines
4.6 KiB
C++

#include "drivers/sdl_display.h"
#include "drivers/sdl_audio.h"
#include <tactility/device.h>
#include <tactility/device_listener.h>
#include <tactility/driver.h>
#include <tactility/error.h>
#include <tactility/log.h>
#include <tactility/module.h>
#include <cstring>
constexpr auto* TAG = "Simulator";
extern "C" {
extern Driver sdl_display_driver;
extern Driver sdl_pointer_driver;
extern Driver sdl_keyboard_driver;
extern Driver sdl_audio_driver;
static Driver* const simulator_drivers[] = {
&sdl_display_driver,
&sdl_pointer_driver,
&sdl_keyboard_driver,
&sdl_audio_driver,
nullptr
};
}
// These devices have no real bus to attach to (SDL has no notion of one), but every non-root
// device is still expected to have a parent (see Device::parent) - they're parented to root once
// it's available below.
// Display resolution is overridable at runtime via SIM_DISPLAY_W/H env vars
// so the sim can match real hardware (e.g. ES3C35P 3.5" = 320x480 portrait,
// ES3C28P 2.8" = 320x240 landscape). Defaults to 640x480.
static uint16_t sim_display_width(void) {
const char* w = getenv("SIM_DISPLAY_W");
if (w != nullptr) {
long v = atol(w);
if (v >= 120 && v <= 2048) return (uint16_t)v;
}
return 480;
}
static uint16_t sim_display_height(void) {
const char* h = getenv("SIM_DISPLAY_H");
if (h != nullptr) {
long v = atol(h);
if (v >= 120 && v <= 2048) return (uint16_t)v;
}
return 320;
}
static SdlDisplayConfig sdl_display_config = { 480, 320 };
static Device sdl_display_device {};
static Device sdl_pointer_device {};
static Device sdl_keyboard_device {};
static Device sdl_speaker_device {};
static Device sdl_microphone_device {};
static const SdlAudioConfig sdl_speaker_config { AUDIO_CODEC_DIR_OUTPUT };
static const SdlAudioConfig sdl_microphone_config { AUDIO_CODEC_DIR_INPUT };
static bool construct_add_start(Device* device, Device* parent, const char* name, const void* config, const char* compatible) {
device->address = 0;
device->name = name;
device->config = config;
device->parent = nullptr;
device->internal = nullptr;
error_t error = device_construct(device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to construct %s: %s", name, error_to_string(error));
return false;
}
device_set_parent(device, parent);
Driver* driver = driver_find_compatible(compatible);
if (driver == nullptr) {
LOG_E(TAG, "No driver registered for %s", compatible);
device_destruct(device);
return false;
}
device_set_driver(device, driver);
if (device_add(device) != ERROR_NONE) {
LOG_E(TAG, "Failed to add %s", name);
device_destruct(device);
return false;
}
if (device_start(device) != ERROR_NONE) {
LOG_E(TAG, "Failed to start %s", name);
device_remove(device);
device_destruct(device);
return false;
}
return true;
}
// Root is only constructed/added/started after all dts_modules (including this one) have already
// started (see kernel_init()), so it can't be looked up by name from this module's own start() -
// wait for its DEVICE_EVENT_STARTED instead, same as e.g. m5stack-tab5's display/keyboard detection.
static void on_root_started(Device* device, DeviceEvent event, void* context) {
if (event != DEVICE_EVENT_STARTED || strcmp(device->name, "/") != 0) {
return;
}
sdl_display_config.horizontal_resolution = sim_display_width();
sdl_display_config.vertical_resolution = sim_display_height();
LOG_I(TAG, "Sim display %dx%d (SIM_DISPLAY_W/H override, default 480x320 landscape)",
sdl_display_config.horizontal_resolution, sdl_display_config.vertical_resolution);
construct_add_start(&sdl_display_device, device, "display0", &sdl_display_config, "tactility,sdl-display");
construct_add_start(&sdl_pointer_device, device, "pointer0", nullptr, "tactility,sdl-pointer");
construct_add_start(&sdl_keyboard_device, device, "keyboard0", nullptr, "tactility,sdl-keyboard");
construct_add_start(&sdl_speaker_device, device, "speaker0", &sdl_speaker_config, "tactility,sdl-audio");
construct_add_start(&sdl_microphone_device, device, "microphone0", &sdl_microphone_config, "tactility,sdl-audio");
}
extern "C" {
static error_t start() {
device_listener_add(on_root_started, nullptr);
return ERROR_NONE;
}
static error_t stop() {
device_listener_remove(on_root_started);
return ERROR_NONE;
}
Module simulator_module = {
.name = "simulator",
.start = start,
.stop = stop,
.drivers = simulator_drivers
};
}