Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Devices/simulator/Source/Simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "SimulatorProfile.h"
#include "drivers/sdl_bridge.h"

#include <tactility/log.h>

#include <csignal>
#include <pthread.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -37,6 +39,8 @@ int main(int, char** argv) {
sigdelset(&all_signals_except_sigint, SIGINT);
pthread_sigmask(SIG_SETMASK, &all_signals_except_sigint, nullptr);

log_set_direct_write_for_current_thread();

// FreeRTOS and app_main() run on a separate thread: macOS requires SDL/Cocoa window creation,
// event pumping and rendering to happen on the real OS main thread, which sdl_bridge_run_main_loop()
// below takes over. freertosMain() never returns, so this thread is detached rather than joined.
Expand Down
15 changes: 8 additions & 7 deletions Devices/simulator/Source/SimulatorProfile.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "SimulatorProfile.h"

#include "lv_conf.h"

#include <tactility/log.h>

#include <cerrno>
Expand All @@ -26,13 +28,12 @@ constexpr auto* DISPLAY_SETTINGS_PATH = "data/tactility/user/app/tactility.displ
constexpr auto* ORIENTATION_KEY = "orientation=";

static const Profile PROFILES[PROFILE_COUNT] = {
{ "Default", 640, 320, false, false, false, true, true },
{ "CL-32", 384, 168, false, true, true, true, false },
{ "LilyGO T-Deck", 320, 240, false, false, false, true, true },
{ "LilyGO T-Lora Pager", 480, 222, false, false, false, true, false },
{ "M5Stack Cardputer", 240, 135, false, true, false, true, false },
// Half the res on each axis to compensate for DPI differences
{ "M5Stack Tab5", 640, 360, true, false, false, true, true },
{ "Default", 640, 320, LV_DPI_DEF, false, false, false, true, true },
{ "CL-32", 384, 168, 139, false, true, true, true, false },
{ "LilyGO T-Deck", 320, 240, 143, false, false, false, true, true },
{ "LilyGO T-Lora Pager", 480, 222, 150, false, false, false, true, false },
{ "M5Stack Cardputer", 240, 135, 139, false, true, false, true, false },
{ "M5Stack Tab5", 1280, 720, 250, true, false, false, true, true },
};

static size_t activeProfileIndex = 0;
Expand Down
3 changes: 2 additions & 1 deletion Devices/simulator/Source/SimulatorProfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ struct Profile {
const char* name;
uint16_t width;
uint16_t height;
uint16_t dpi; // lvgl.dpi from device.properties (if set), otherwise display.dpi
/** The default rotation: the display is taller than wide. The width and height values may be given in either order. */
bool portrait;
/** Compact UI density */
bool compact;
/** Greyscale display, which makes the monochrome theme apply */
bool mono;
bool keyboard;
bool pointer;
bool touch;
};

constexpr size_t PROFILE_COUNT = 6;
Expand Down
5 changes: 3 additions & 2 deletions Devices/simulator/Source/SimulatorProfileApp.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "SimulatorProfile.h"

#include <app/event.h>
#include <app/location.h>
#include <app/manifest.h>
#include <app/scheduler.h>
#include <app/start.h>
Expand Down Expand Up @@ -284,9 +285,9 @@ extern const ::AppManifest profileAppManifest = {
.id = "tactility.simulator",
.name = "Simulator",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
.location = { .type = APP_LOCATION_MEMORY, .location = reinterpret_cast<void*>(appMain) },
.flags = 0,
.stack = {}
.stack = {},
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ static const TouchApi sdl_touch_api = {

extern Module simulator_module;

Driver sdl_pointer_driver = {
.name = "sdl-pointer",
.compatible = (const char*[]) { "tactility,sdl-pointer", nullptr },
Driver sdl_touch_driver = {
.name = "sdl-touch",
.compatible = (const char*[]) { "tactility,sdl-touch", nullptr },
.start_device = start,
.stop_device = stop,
.probe = nullptr,
Expand Down
15 changes: 9 additions & 6 deletions Devices/simulator/Source/module.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "SimulatorProfile.h"
#include "drivers/sdl_display.h"
#include "lv_conf.h"

#include <app/manager.h>

Expand All @@ -20,12 +21,12 @@ constexpr auto* TAG = "Simulator";
extern "C" {

extern Driver sdl_display_driver;
extern Driver sdl_pointer_driver;
extern Driver sdl_touch_driver;
extern Driver sdl_keyboard_driver;

static Driver* const simulator_drivers[] = {
&sdl_display_driver,
&sdl_pointer_driver,
&sdl_touch_driver,
&sdl_keyboard_driver,
nullptr
};
Expand Down Expand Up @@ -88,17 +89,19 @@ static void on_root_started(Device* device, DeviceEvent event, void* context) {
}

const auto& profile = simulator::getProfile(simulator::getActiveProfileIndex());
const uint16_t short_side = std::min(profile.width, profile.height);
const uint16_t long_side = std::max(profile.width, profile.height);
const auto width = static_cast<uint16_t>(profile.width * LV_DPI_DEF / profile.dpi);
const auto height = static_cast<uint16_t>(profile.height * LV_DPI_DEF / profile.dpi);
const uint16_t short_side = std::min(width, height);
const uint16_t long_side = std::max(width, height);
sdl_display_config = {
profile.portrait ? short_side : long_side,
profile.portrait ? long_side : short_side,
profile.mono
};

construct_add_start(&sdl_display_device, device, "display0", &sdl_display_config, "tactility,sdl-display");
if (profile.pointer) {
construct_add_start(&sdl_pointer_device, device, "pointer0", nullptr, "tactility,sdl-pointer");
if (profile.touch) {
construct_add_start(&sdl_pointer_device, device, "touch0", nullptr, "tactility,sdl-touch");
}
if (profile.keyboard) {
construct_add_start(&sdl_keyboard_device, device, "keyboard0", nullptr, "tactility,sdl-keyboard");
Expand Down
5 changes: 5 additions & 0 deletions Devices/simulator/simulator.dts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <bindings/mock_wifi.h>
#include <bindings/mock_radio.h>
#include <bindings/mock_bluetooth.h>
#include <bindings/mock_power_supply.h>

/ {
model = "Simulator";
Expand All @@ -20,4 +21,8 @@
bluetooth0 {
compatible = "mock,bluetooth";
};

power0 {
compatible = "mock,power-supply";
};
};
8 changes: 8 additions & 0 deletions Drivers/mock-drivers-module/bindings/mock,power-supply.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description: Mock power supply with a fixed battery state and toggleable charging

compatible: "mock,power-supply"

properties:
_unused:
type: int
default: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once

#include <tactility/bindings/bindings.h>
#include <mock/mock_power_supply.h>

DEFINE_DEVICETREE(power_supply, struct MockPowerSupplyConfig)
14 changes: 14 additions & 0 deletions Drivers/mock-drivers-module/include/mock/mock_power_supply.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

struct MockPowerSupplyConfig {
int _unused;
};

#ifdef __cplusplus
}
#endif
85 changes: 85 additions & 0 deletions Drivers/mock-drivers-module/source/mock_power_supply.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/power_supply.h>

#include <atomic>

// region PowerSupplyApi

static std::atomic<bool> allowed_to_charge { true };

static bool supports_property(Device*, PowerSupplyProperty property) {
switch (property) {
case POWER_SUPPLY_PROP_IS_CHARGING:
case POWER_SUPPLY_PROP_CURRENT:
case POWER_SUPPLY_PROP_VOLTAGE:
case POWER_SUPPLY_PROP_CAPACITY:
return true;
default:
return false;
}
}

static error_t get_property(Device*, PowerSupplyProperty property, PowerSupplyPropertyValue* out_value) {
const bool charging = allowed_to_charge.load();
switch (property) {
case POWER_SUPPLY_PROP_IS_CHARGING:
out_value->int_value = charging ? 1 : 0;
return ERROR_NONE;
case POWER_SUPPLY_PROP_CURRENT:
out_value->int_value = charging ? 500 : -150;
return ERROR_NONE;
case POWER_SUPPLY_PROP_VOLTAGE:
out_value->int_value = 3950;
return ERROR_NONE;
case POWER_SUPPLY_PROP_CAPACITY:
out_value->int_value = 80;
return ERROR_NONE;
default:
return ERROR_NOT_SUPPORTED;
}
}

static bool supports_charge_control(Device*) { return true; }
static bool is_allowed_to_charge(Device*) { return allowed_to_charge.load(); }

static error_t set_allowed_to_charge(Device*, bool allowed) {
allowed_to_charge.store(allowed);
return ERROR_NONE;
}

static bool supports_quick_charge(Device*) { return false; }
static bool is_quick_charge_enabled(Device*) { return false; }
static error_t set_quick_charge_enabled(Device*, bool) { return ERROR_NOT_SUPPORTED; }
static bool supports_power_off(Device*) { return false; }
static error_t power_off(Device*) { return ERROR_NOT_SUPPORTED; }

// endregion

static const PowerSupplyApi mock_power_supply_api = {
.supports_property = supports_property,
.get_property = get_property,
.supports_charge_control = supports_charge_control,
.is_allowed_to_charge = is_allowed_to_charge,
.set_allowed_to_charge = set_allowed_to_charge,
.supports_quick_charge = supports_quick_charge,
.is_quick_charge_enabled = is_quick_charge_enabled,
.set_quick_charge_enabled = set_quick_charge_enabled,
.supports_power_off = supports_power_off,
.power_off = power_off,
};

extern "C" {

Driver mock_power_supply_driver = {
.name = "mock_power_supply",
.compatible = (const char*[]) { "mock,power-supply", nullptr },
.start_device = nullptr,
.stop_device = nullptr,
.api = (const void*)&mock_power_supply_api,
.device_type = &POWER_SUPPLY_TYPE,
.internal = nullptr
};

} // extern "C"
2 changes: 2 additions & 0 deletions Drivers/mock-drivers-module/source/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ extern "C" {
extern Driver mock_wifi_driver;
extern Driver mock_radio_driver;
extern Driver mock_bluetooth_driver;
extern Driver mock_power_supply_driver;

static Driver* const mock_drivers[] = {
&mock_wifi_driver,
&mock_radio_driver,
&mock_bluetooth_driver,
&mock_power_supply_driver,
nullptr
};

Expand Down
3 changes: 2 additions & 1 deletion Modules/lvgl-module/source/devices/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ error_t lvgl_display_add(struct Device* device, const struct LvglDisplayConfig*
} else {
uint16_t buf_height = config->force_full_frame || config->buffer_height == 0
? vres : config->buffer_height;
buf_size_bytes = (size_t)hres * buf_height * bpp;
// LVGL rounds the size it needs for an area up to LV_DRAW_BUF_ALIGN
buf_size_bytes = LV_ROUND_UP((size_t)hres * buf_height * bpp, LV_DRAW_BUF_ALIGN);

ctx->buf1 = lvgl_display_alloc_buffer(buf_size_bytes, config->prefer_external_ram);
if (ctx->buf1 == NULL) {
Expand Down
7 changes: 3 additions & 4 deletions Platforms/platform-posix/source/freertos.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#if defined(__GLIBC__)
#include <assert.h>
#endif
#include <tactility/freertos/task.h>
#include <tactility/log.h>

#define TAG "freertos"

/**
* Assert implementation as defined in the FreeRTOSConfig.h
*/
void vAssertCalled(unsigned long line, const char* const file) {
LOG_E("Assert triggered at {}:{}", file, line);
// Logging can recurse into this assert when it happens from inside the log queue
fprintf(stderr, "Assert triggered at %s:%lu\n", file, line);
Comment thread
KenVanHoeylandt marked this conversation as resolved.
#if defined(__GLIBC__)
__assert_fail("assert failed", file, line, "");
#else
Expand Down
6 changes: 6 additions & 0 deletions TactilityKernel/include/tactility/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ enum LogLevel {

void log_generic(enum LogLevel level, const char* tag, const char* format, ...);

/**
* Makes logging on the calling thread write directly to the console.
* Must be called by threads that are not FreeRTOS tasks before they log, because the log queue can only be used from tasks.
*/
void log_set_direct_write_for_current_thread(void);

#define LOG_E(tag, ...) log_generic(LOG_LEVEL_ERROR, tag, ##__VA_ARGS__)
#define LOG_W(tag, ...) log_generic(LOG_LEVEL_WARNING, tag, ##__VA_ARGS__)
#define LOG_I(tag, ...) log_generic(LOG_LEVEL_INFO, tag, ##__VA_ARGS__)
Expand Down
18 changes: 18 additions & 0 deletions TactilityKernel/source/log_queue.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/log_queue.h>
#include <tactility/log.h>

#include <tactility/freertos/queue.h>
#include <tactility/freertos/task.h>
Expand All @@ -26,6 +27,10 @@ struct LogQueueMessage {

std::atomic<QueueHandle_t> g_queue { nullptr };

#if !defined(ESP_PLATFORM)
thread_local bool g_direct_write = false;
#endif

// The one and only place a real console write happens for log output - deliberately never
// through app_io_write()'s fd-table redirection (Modules/app-module/source/io.cpp). That
// redirection only ever triggers for a task app_task_main() (Modules/app-module/source/
Expand Down Expand Up @@ -162,11 +167,24 @@ void log_queue_init(void) {
#endif
}

#if !defined(ESP_PLATFORM)
void log_set_direct_write_for_current_thread(void) {
g_direct_write = true;
}
#endif

void log_queue_write(const char* data, size_t length) {
if (data == nullptr || length == 0) {
return;
}

#if !defined(ESP_PLATFORM)
if (g_direct_write) {
write_real(data, length);
return;
}
#endif

QueueHandle_t queue = g_queue.load(std::memory_order_acquire);
if (queue == nullptr) {
write_real(data, length); // pre-init fallback
Expand Down
Loading