This commit is contained in:
Ken Van Hoeylandt 2026-10-13 18:30:51 +02:00
parent 080aa088cf
commit 4e828dd0a6
5 changed files with 23 additions and 17 deletions

View File

@ -7,11 +7,14 @@
## Higher Priority ## Higher Priority
- Create location service, which works with location providers. GPS is a location provider. IP is also a location provider (must have wifi connected) - https://github.com/TactilityProject/Tactility/blob/main/LICENSE.md#overview -> put overview table on top
- Use GPS time to set/update the current time: when enabled, at boot, when wifi is not enabled, start the gps device and wait until a lock is acquired, then get the time and sync it. Then stop the GPS device. - Fix Wi-Fi so it actually connects to something
- Support http/https on posix
- Vi apps are both named "Vi" in the App Hub
- Use GPS time to set/update the current time: when enabled, at boot, when wifi is not enabled, start the gps device and wait until a lock is acquired, then get the time and sync it. Then stop the GPS device.
- lvgl-module's spinner relies on hard-coded spinner asset from Tactility main project, should be sized based on DPI - lvgl-module's spinner relies on hard-coded spinner asset from Tactility main project, should be sized based on DPI
- Cursor is hard-coded, needs size based on DPI - Cursor is hard-coded, needs size based on DPI
- Improve Setup: Show progress of some kind - Improve Setup: Show progress of some kind. Put skip/next buttons closer? And add outline button style (update docs!)
- Files app should have a page indicator like Launcher. - Files app should have a page indicator like Launcher.
- Move Bluetooth code from kernel to Modules/bluetooth-module, and have includes in path bluetooth/ then make a bluetooth_command.cpp like wifi_command.cpp - Move Bluetooth code from kernel to Modules/bluetooth-module, and have includes in path bluetooth/ then make a bluetooth_command.cpp like wifi_command.cpp
- Inspect code for memory improvements: replace `std::*` with `tt::std::*` - Inspect code for memory improvements: replace `std::*` with `tt::std::*`
@ -30,6 +33,8 @@
## Medium Priority ## Medium Priority
- CL-32 display driver performance
- Move more window management code from Tactility/ to window-manager
- Implement signal/raise for terminal apps (for CTRL+C and window resize signals) - Implement signal/raise for terminal apps (for CTRL+C and window resize signals)
- Build the simulator with `-fno-exceptions` to match ESP32. First make app exit() work without C++ unwinding there: - Build the simulator with `-fno-exceptions` to match ESP32. First make app exit() work without C++ unwinding there:
scheduler.cpp's DeferredUnload relies on pthread_exit()'s forced unwind running its destructor. scheduler.cpp's DeferredUnload relies on pthread_exit()'s forced unwind running its destructor.

View File

@ -21,7 +21,6 @@ namespace {
constexpr uint32_t AWAIT_TIMEOUT_MS = 250; constexpr uint32_t AWAIT_TIMEOUT_MS = 250;
constexpr uint32_t DEVICE_POLL_INTERVAL_MS = 1000; constexpr uint32_t DEVICE_POLL_INTERVAL_MS = 1000;
constexpr uint32_t THREAD_STOP_TIMEOUT_MS = 3000;
constexpr float METERS_PER_SECOND_PER_KNOT = 0.514444f; constexpr float METERS_PER_SECOND_PER_KNOT = 0.514444f;
// Typical user equivalent range error of consumer receivers, which turns dilution of precision into meters // Typical user equivalent range error of consumer receivers, which turns dilution of precision into meters
constexpr float RANGE_ERROR_METERS = 5.0f; constexpr float RANGE_ERROR_METERS = 5.0f;
@ -203,10 +202,8 @@ void* create(LocationHost* host) {
void destroy(void*) { void destroy(void*) {
provider.running = false; provider.running = false;
if (thread_join(provider.thread, millis_to_ticks(THREAD_STOP_TIMEOUT_MS), millis_to_ticks(10)) != ERROR_NONE) { // The provider state can only be reused after the worker exits. It does so within AWAIT_TIMEOUT_MS.
LOG_E(TAG, "Thread did not stop in time"); thread_join(provider.thread, portMAX_DELAY, millis_to_ticks(10));
return;
}
device_listener_remove(onDeviceEvent, nullptr); device_listener_remove(onDeviceEvent, nullptr);
thread_free(provider.thread); thread_free(provider.thread);
provider.thread = nullptr; provider.thread = nullptr;

View File

@ -40,8 +40,6 @@ constexpr uint64_t MIN_INTERVAL_MS = 10 * 1000;
constexpr uint32_t CHECK_INTERVAL_MS = 10 * 1000; constexpr uint32_t CHECK_INTERVAL_MS = 10 * 1000;
constexpr int SOCKET_TIMEOUT_SECONDS = 5; constexpr int SOCKET_TIMEOUT_SECONDS = 5;
constexpr size_t RESPONSE_MAX_LENGTH = 1024; constexpr size_t RESPONSE_MAX_LENGTH = 1024;
// DNS resolution has no timeout of its own
constexpr uint32_t THREAD_STOP_TIMEOUT_MS = 30 * 1000;
// IP geolocation is accurate to roughly city level // IP geolocation is accurate to roughly city level
constexpr float ACCURACY_METERS = 25000.0f; constexpr float ACCURACY_METERS = 25000.0f;
@ -264,10 +262,8 @@ void* create(LocationHost* host) {
void destroy(void*) { void destroy(void*) {
provider.running = false; provider.running = false;
task_event_group_signal(&provider.group, provider.stopBit); task_event_group_signal(&provider.group, provider.stopBit);
if (thread_join(provider.thread, millis_to_ticks(THREAD_STOP_TIMEOUT_MS), millis_to_ticks(10)) != ERROR_NONE) { // The provider state can only be reused after the worker exits. All its blocking calls time out.
LOG_E(TAG, "Thread did not stop in time"); thread_join(provider.thread, portMAX_DELAY, millis_to_ticks(10));
return;
}
thread_free(provider.thread); thread_free(provider.thread);
provider.thread = nullptr; provider.thread = nullptr;
system_event_unsubscribe(&provider.networkSubscription); system_event_unsubscribe(&provider.networkSubscription);
@ -347,7 +343,9 @@ bool ip_api_parse_response(const char* response, IpApiResponse* out) {
char* longitudeEnd; char* longitudeEnd;
out->latitude = strtod(latitude.c_str(), &latitudeEnd); out->latitude = strtod(latitude.c_str(), &latitudeEnd);
out->longitude = strtod(longitude.c_str(), &longitudeEnd); out->longitude = strtod(longitude.c_str(), &longitudeEnd);
if (latitude.empty() || *latitudeEnd != '\0' || longitude.empty() || *longitudeEnd != '\0') { if (latitude.empty() || *latitudeEnd != '\0' || longitude.empty() || *longitudeEnd != '\0' ||
!std::isfinite(out->latitude) || !std::isfinite(out->longitude) ||
std::fabs(out->latitude) > 90.0 || std::fabs(out->longitude) > 180.0) {
return false; return false;
} }
out->success = true; out->success = true;

View File

@ -50,4 +50,8 @@ TEST_CASE("ip_api_parse_response rejects malformed responses") {
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\nX-Rl: 1\r\n", &parsed)); CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\nX-Rl: 1\r\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\nabc\n1.0\n", &parsed)); CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\nabc\n1.0\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nunknown\n", &parsed)); CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nunknown\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\nnan\n1.0\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\n1.0\ninf\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\n90.5\n1.0\n", &parsed));
CHECK_FALSE(ip_api_parse_response("HTTP/1.1 200 OK\r\n\r\nsuccess\n1.0\n-180.5\n", &parsed));
} }

View File

@ -81,8 +81,8 @@ static void thread_main_body(void* context) {
vTaskSetThreadLocalStoragePointer(nullptr, LOCAL_STORAGE_SELF_POINTER_INDEX, nullptr); vTaskSetThreadLocalStoragePointer(nullptr, LOCAL_STORAGE_SELF_POINTER_INDEX, nullptr);
// The thread can be freed once taskHandle is cleared // The thread can be freed once taskHandle is cleared
const bool createdWithCaps = thread->createdWithCaps;
thread->lock(); thread->lock();
const bool createdWithCaps = thread->createdWithCaps;
thread->taskHandle = nullptr; thread->taskHandle = nullptr;
thread->unlock(); thread->unlock();
@ -223,7 +223,9 @@ error_t thread_start(Thread* thread) {
affinity != -1 ? affinity : tskNO_AFFINITY, affinity != -1 ? affinity : tskNO_AFFINITY,
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
); );
thread->createdWithCaps = (result == pdPASS); if (result != pdPASS) {
thread->createdWithCaps = false;
}
} }
#endif #endif
if (result == pdPASS) { if (result == pdPASS) {