mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
Convert code to use Timer instead of Thread (#120)
This commit is contained in:
parent
51c6aaa428
commit
34f99205ca
@ -1,5 +1,7 @@
|
|||||||
# TODOs
|
# TODOs
|
||||||
|
- Release process should bundle all libs and TactilityC headers and generate an SDK project
|
||||||
- Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time.
|
- Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time.
|
||||||
|
We'll need to keep track of all manifest instances, so that the wrapper can look up the relevant manifest for the relevant callbacks.
|
||||||
- T-Deck: Clear screen before turning on blacklight
|
- T-Deck: Clear screen before turning on blacklight
|
||||||
- Single wire audio
|
- Single wire audio
|
||||||
- Audio recording app
|
- Audio recording app
|
||||||
@ -8,11 +10,8 @@
|
|||||||
- Logging to disk/etc.
|
- Logging to disk/etc.
|
||||||
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
||||||
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
||||||
- Loader: Use Timer instead of Thread, and move API to `tt::app::`
|
- Loader: Use main dispatcher instead of Thread, and move API to `tt::app::`
|
||||||
- Gpio: Use Timer instead of Thread
|
|
||||||
- I2cScannerThread: Use Timer instead of Thread
|
|
||||||
- Bug: I2C Scanner is on M5Stack devices is broken
|
- Bug: I2C Scanner is on M5Stack devices is broken
|
||||||
- WiFi AP Connect app: add "Forget" option.
|
|
||||||
- Make firmwares available via release process
|
- Make firmwares available via release process
|
||||||
- Make firmwares available via web serial website
|
- Make firmwares available via web serial website
|
||||||
- Bug: When closing a top level app, there's often an error "can't stop root app"
|
- Bug: When closing a top level app, there's often an error "can't stop root app"
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "GpioHal.h"
|
#include "GpioHal.h"
|
||||||
#include "lvgl/LvglSync.h"
|
#include "lvgl/LvglSync.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
namespace tt::app::gpio {
|
namespace tt::app::gpio {
|
||||||
|
|
||||||
@ -15,9 +16,8 @@ private:
|
|||||||
|
|
||||||
lv_obj_t* lvPins[GPIO_NUM_MAX] = {0 };
|
lv_obj_t* lvPins[GPIO_NUM_MAX] = {0 };
|
||||||
uint8_t pinStates[GPIO_NUM_MAX] = {0 };
|
uint8_t pinStates[GPIO_NUM_MAX] = {0 };
|
||||||
Thread* thread = nullptr;
|
std::unique_ptr<Timer> timer;
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
bool interruptTask = true;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -32,9 +32,8 @@ public:
|
|||||||
void onShow(AppContext& app, lv_obj_t* parent);
|
void onShow(AppContext& app, lv_obj_t* parent);
|
||||||
void onHide(AppContext& app);
|
void onHide(AppContext& app);
|
||||||
|
|
||||||
void startTask();
|
void startTask(std::shared_ptr<Gpio> ptr);
|
||||||
void stopTask();
|
void stopTask();
|
||||||
bool shouldInterruptTask() const { return interruptTask; };
|
|
||||||
|
|
||||||
void updatePinStates();
|
void updatePinStates();
|
||||||
void updatePinWidgets();
|
void updatePinWidgets();
|
||||||
@ -86,50 +85,30 @@ static lv_obj_t* createGpioRowWrapper(lv_obj_t* parent) {
|
|||||||
|
|
||||||
// region Task
|
// region Task
|
||||||
|
|
||||||
static int32_t taskMain(void* context) {
|
static void onTimer(std::shared_ptr<void> context) {
|
||||||
Gpio* gpio = (Gpio*)context;
|
auto gpio = std::static_pointer_cast<Gpio>(context);
|
||||||
bool interrupted = false;
|
|
||||||
|
|
||||||
while (!interrupted) {
|
|
||||||
kernel::delayMillis(100);
|
|
||||||
|
|
||||||
gpio->updatePinStates();
|
gpio->updatePinStates();
|
||||||
gpio->updatePinWidgets();
|
gpio->updatePinWidgets();
|
||||||
|
|
||||||
gpio->lock();
|
|
||||||
interrupted = gpio->shouldInterruptTask();
|
|
||||||
gpio->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
void Gpio::startTask(std::shared_ptr<Gpio> ptr) {
|
||||||
}
|
|
||||||
|
|
||||||
void Gpio::startTask() {
|
|
||||||
lock();
|
lock();
|
||||||
tt_assert(thread == nullptr);
|
tt_assert(timer == nullptr);
|
||||||
thread = new Thread(
|
timer = std::make_unique<Timer>(
|
||||||
"gpio",
|
Timer::TypePeriodic,
|
||||||
4096,
|
&onTimer,
|
||||||
&taskMain,
|
ptr
|
||||||
this
|
|
||||||
);
|
);
|
||||||
interruptTask = false;
|
timer->start(100 / portTICK_PERIOD_MS);
|
||||||
thread->start();
|
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::stopTask() {
|
void Gpio::stopTask() {
|
||||||
tt_assert(thread);
|
tt_assert(timer);
|
||||||
lock();
|
|
||||||
interruptTask = true;
|
|
||||||
unlock();
|
|
||||||
|
|
||||||
thread->join();
|
timer->stop();
|
||||||
|
timer = nullptr;
|
||||||
lock();
|
|
||||||
delete thread;
|
|
||||||
thread = nullptr;
|
|
||||||
unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion Task
|
// endregion Task
|
||||||
@ -188,7 +167,7 @@ void Gpio::onShow(AppContext& app, lv_obj_t* parent) {
|
|||||||
}
|
}
|
||||||
gpio->unlock();
|
gpio->unlock();
|
||||||
|
|
||||||
gpio->startTask();
|
gpio->startTask(gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::onHide(AppContext& app) {
|
void Gpio::onHide(AppContext& app) {
|
||||||
@ -196,7 +175,6 @@ void Gpio::onHide(AppContext& app) {
|
|||||||
gpio->stopTask();
|
gpio->stopTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// region App lifecycle
|
// region App lifecycle
|
||||||
|
|
||||||
static void onShow(AppContext& app, lv_obj_t* parent) {
|
static void onShow(AppContext& app, lv_obj_t* parent) {
|
||||||
|
|||||||
@ -102,7 +102,7 @@ static void updateViewsSafely(std::shared_ptr<Data> data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onThreadFinished(std::shared_ptr<Data> data) {
|
void onScanTimerFinished(std::shared_ptr<Data> data) {
|
||||||
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||||
if (data->scanState == ScanStateScanning) {
|
if (data->scanState == ScanStateScanning) {
|
||||||
data->scanState = ScanStateStopped;
|
data->scanState = ScanStateStopped;
|
||||||
@ -110,7 +110,7 @@ void onThreadFinished(std::shared_ptr<Data> data) {
|
|||||||
}
|
}
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
tt_check(data->mutex.release() == TtStatusOk);
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_W(TAG, "onThreadFinished lock");
|
TT_LOG_W(TAG, "onScanTimerFinished lock");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +159,16 @@ static void onShow(AppContext& app, lv_obj_t* parent) {
|
|||||||
|
|
||||||
static void onHide(AppContext& app) {
|
static void onHide(AppContext& app) {
|
||||||
auto data = std::static_pointer_cast<Data>(app.getData());
|
auto data = std::static_pointer_cast<Data>(app.getData());
|
||||||
if (hasScanThread(data)) {
|
|
||||||
|
bool isRunning = false;
|
||||||
|
if (data->mutex.acquire(250 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||||
|
isRunning = data->scanTimer->isRunning();
|
||||||
|
data->mutex.release();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRunning) {
|
||||||
stopScanning(data);
|
stopScanning(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <Thread.h>
|
#include <Thread.h>
|
||||||
#include "lvgl.h"
|
#include "lvgl.h"
|
||||||
#include "hal/i2c/I2c.h"
|
#include "hal/i2c/I2c.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace tt::app::i2cscanner {
|
namespace tt::app::i2cscanner {
|
||||||
@ -20,7 +21,7 @@ enum ScanState {
|
|||||||
struct Data {
|
struct Data {
|
||||||
// Core
|
// Core
|
||||||
Mutex mutex = Mutex(Mutex::TypeRecursive);
|
Mutex mutex = Mutex(Mutex::TypeRecursive);
|
||||||
Thread* _Nullable scanThread = nullptr;
|
std::unique_ptr<Timer> scanTimer = nullptr;
|
||||||
// State
|
// State
|
||||||
ScanState scanState;
|
ScanState scanState;
|
||||||
i2c_port_t port = I2C_NUM_0;
|
i2c_port_t port = I2C_NUM_0;
|
||||||
@ -31,6 +32,6 @@ struct Data {
|
|||||||
lv_obj_t* scanListWidget = nullptr;
|
lv_obj_t* scanListWidget = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void onThreadFinished(std::shared_ptr<Data> data);
|
void onScanTimerFinished(std::shared_ptr<Data> data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace tt::app::i2cscanner {
|
|||||||
|
|
||||||
std::shared_ptr<Data> _Nullable optData();
|
std::shared_ptr<Data> _Nullable optData();
|
||||||
|
|
||||||
static bool shouldStopScanThread(std::shared_ptr<Data> data) {
|
static bool shouldStopScanTimer(std::shared_ptr<Data> data) {
|
||||||
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||||
bool is_scanning = data->scanState == ScanStateScanning;
|
bool is_scanning = data->scanState == ScanStateScanning;
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
tt_check(data->mutex.release() == TtStatusOk);
|
||||||
@ -38,10 +38,10 @@ static bool addAddressToList(std::shared_ptr<Data> data, uint8_t address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t scanThread(TT_UNUSED void* context) {
|
static void onScanTimer(TT_UNUSED std::shared_ptr<void> context) {
|
||||||
auto data = optData();
|
auto data = optData();
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Scan thread started");
|
TT_LOG_I(TAG, "Scan thread started");
|
||||||
@ -51,39 +51,39 @@ static int32_t scanThread(TT_UNUSED void* context) {
|
|||||||
if (getPort(data, &port)) {
|
if (getPort(data, &port)) {
|
||||||
if (hal::i2c::masterCheckAddressForDevice(port, address, 10 / portTICK_PERIOD_MS)) {
|
if (hal::i2c::masterCheckAddressForDevice(port, address, 10 / portTICK_PERIOD_MS)) {
|
||||||
TT_LOG_I(TAG, "Found device at address %d", address);
|
TT_LOG_I(TAG, "Found device at address %d", address);
|
||||||
if (!shouldStopScanThread(data)) {
|
if (!shouldStopScanTimer(data)) {
|
||||||
addAddressToList(data, address);
|
addAddressToList(data, address);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_W(TAG, "scanThread lock");
|
TT_LOG_W(TAG, "onScanTimer lock");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldStopScanThread(data)) {
|
if (shouldStopScanTimer(data)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Scan thread finalizing");
|
TT_LOG_I(TAG, "Scan thread finalizing");
|
||||||
|
|
||||||
onThreadFinished(data);
|
onScanTimerFinished(data);
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Scan thread stopped");
|
TT_LOG_I(TAG, "Scan timer done");
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasScanThread(std::shared_ptr<Data> data) {
|
bool hasScanThread(std::shared_ptr<Data> data) {
|
||||||
bool has_thread;
|
bool has_thread;
|
||||||
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
if (data->mutex.acquire(100 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||||
has_thread = data->scanThread != nullptr;
|
has_thread = data->scanTimer != nullptr;
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
tt_check(data->mutex.release() == TtStatusOk);
|
||||||
return has_thread;
|
return has_thread;
|
||||||
} else {
|
} else {
|
||||||
// Unsafe way
|
// Unsafe way
|
||||||
TT_LOG_W(TAG, "hasScanThread lock");
|
TT_LOG_W(TAG, "hasScanTimer lock");
|
||||||
return data->scanThread != nullptr;
|
return data->scanTimer != nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,15 +98,13 @@ void startScanning(std::shared_ptr<Data> data) {
|
|||||||
lv_obj_add_flag(data->scanListWidget, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(data->scanListWidget, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_clean(data->scanListWidget);
|
lv_obj_clean(data->scanListWidget);
|
||||||
|
|
||||||
tt_assert(data->scanThread == nullptr);
|
|
||||||
data->scanState = ScanStateScanning;
|
data->scanState = ScanStateScanning;
|
||||||
data->scanThread = new Thread(
|
data->scanTimer = std::make_unique<Timer>(
|
||||||
"i2c scanner",
|
Timer::TypeOnce,
|
||||||
4096,
|
onScanTimer,
|
||||||
scanThread,
|
data
|
||||||
nullptr
|
|
||||||
);
|
);
|
||||||
data->scanThread->start();
|
data->scanTimer->start(10);
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
tt_check(data->mutex.release() == TtStatusOk);
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_W(TAG, "startScanning lock");
|
TT_LOG_W(TAG, "startScanning lock");
|
||||||
@ -114,25 +112,12 @@ void startScanning(std::shared_ptr<Data> data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void stopScanning(std::shared_ptr<Data> data) {
|
void stopScanning(std::shared_ptr<Data> data) {
|
||||||
bool sent_halt;
|
|
||||||
if (data->mutex.acquire(250 / portTICK_PERIOD_MS) == TtStatusOk) {
|
if (data->mutex.acquire(250 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||||
tt_assert(data->scanThread != nullptr);
|
tt_assert(data->scanTimer != nullptr);
|
||||||
data->scanState = ScanStateStopped;
|
data->scanState = ScanStateStopped;
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
tt_check(data->mutex.release() == TtStatusOk);
|
||||||
sent_halt = true;
|
|
||||||
} else {
|
} else {
|
||||||
sent_halt = false;
|
TT_LOG_E(TAG, "Acquire mutex failed");
|
||||||
}
|
|
||||||
|
|
||||||
if (sent_halt) {
|
|
||||||
tt_assert(data->scanThread != nullptr);
|
|
||||||
data->scanThread->join();
|
|
||||||
|
|
||||||
if (data->mutex.acquire(250 / portTICK_PERIOD_MS) == TtStatusOk) {
|
|
||||||
delete data->scanThread;
|
|
||||||
data->scanThread = nullptr;
|
|
||||||
tt_check(data->mutex.release() == TtStatusOk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace tt::app::i2cscanner {
|
namespace tt::app::i2cscanner {
|
||||||
|
|
||||||
bool hasScanThread(std::shared_ptr<Data> data);
|
bool hasScanTimer(std::shared_ptr<Data> data);
|
||||||
void startScanning(std::shared_ptr<Data> data);
|
void startScanning(std::shared_ptr<Data> data);
|
||||||
void stopScanning(std::shared_ptr<Data> data);
|
void stopScanning(std::shared_ptr<Data> data);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user