mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 10:53:17 +00:00
Various improvements (#264)
- Replace C function pointers with C++ `std::function` in `Thread`, `Timer` and `DispatcherThread` - Rename `SystemEvent`-related functions - WiFi: fix auto-connect when WiFi disconnects from bad signal - WiFi: fix auto-connect when WiFi fails to auto-connect - WiFi: implement disconnect() when tapping connected WiFi ap in WiFi management app
This commit is contained in:
parent
d72852a6e2
commit
3f1bfee3f5
@ -45,17 +45,13 @@ bool tdeckInit() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tt::kernel::systemEventAddListener(tt::kernel::SystemEvent::BootSplash, [](tt::kernel::SystemEvent event){
|
tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootSplash, [](tt::kernel::SystemEvent event) {
|
||||||
auto gps_service = tt::service::gps::findGpsService();
|
auto gps_service = tt::service::gps::findGpsService();
|
||||||
if (gps_service != nullptr) {
|
if (gps_service != nullptr) {
|
||||||
std::vector<tt::hal::gps::GpsConfiguration> gps_configurations;
|
std::vector<tt::hal::gps::GpsConfiguration> gps_configurations;
|
||||||
gps_service->getGpsConfigurations(gps_configurations);
|
gps_service->getGpsConfigurations(gps_configurations);
|
||||||
if (gps_configurations.empty()) {
|
if (gps_configurations.empty()) {
|
||||||
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {
|
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {.uartName = "Grove", .baudRate = 38400, .model = tt::hal::gps::GpsModel::UBLOX10})) {
|
||||||
.uartName = "Grove",
|
|
||||||
.baudRate = 38400,
|
|
||||||
.model = tt::hal::gps::GpsModel::UBLOX10
|
|
||||||
})) {
|
|
||||||
TT_LOG_I(TAG, "Configured internal GPS");
|
TT_LOG_I(TAG, "Configured internal GPS");
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_E(TAG, "Failed to configure internal GPS");
|
TT_LOG_E(TAG, "Failed to configure internal GPS");
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
# TODOs
|
# TODOs
|
||||||
- rename kernel::systemEventAddListener() etc to subscribe/unsubscribe
|
|
||||||
- Split up boot stages, so the last stage can be done from the splash screen
|
- Split up boot stages, so the last stage can be done from the splash screen
|
||||||
- Start using non_null (either via MS GSL, or custom)
|
- Start using non_null (either via MS GSL, or custom)
|
||||||
- `hal/Configuration.h` defines C function types: Use C++ std::function instead
|
- `hal/Configuration.h` defines C function types: Use C++ std::function instead
|
||||||
|
|||||||
@ -113,16 +113,6 @@ private:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t viewThreadMainStatic(void* parameter) {
|
|
||||||
auto* view = (ConsoleView*)parameter;
|
|
||||||
return view->viewThreadMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t uartThreadMainStatic(void* parameter) {
|
|
||||||
auto* view = (ConsoleView*)parameter;
|
|
||||||
return view->uartThreadMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onSendClickedCallback(lv_event_t* event) {
|
static void onSendClickedCallback(lv_event_t* event) {
|
||||||
auto* view = (ConsoleView*)lv_event_get_user_data(event);
|
auto* view = (ConsoleView*)lv_event_get_user_data(event);
|
||||||
view->onSendClicked();
|
view->onSendClicked();
|
||||||
@ -177,8 +167,9 @@ public:
|
|||||||
uartThread = std::make_unique<Thread>(
|
uartThread = std::make_unique<Thread>(
|
||||||
"SerConsUart",
|
"SerConsUart",
|
||||||
4096,
|
4096,
|
||||||
uartThreadMainStatic,
|
[this]() {
|
||||||
this
|
return this->uartThreadMain();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
uartThread->setPriority(tt::Thread::Priority::High);
|
uartThread->setPriority(tt::Thread::Priority::High);
|
||||||
uartThread->start();
|
uartThread->start();
|
||||||
@ -226,8 +217,9 @@ public:
|
|||||||
viewThread = std::make_unique<Thread>(
|
viewThread = std::make_unique<Thread>(
|
||||||
"SerConsView",
|
"SerConsView",
|
||||||
4096,
|
4096,
|
||||||
viewThreadMainStatic,
|
[this]() {
|
||||||
this
|
return this->viewThreadMain();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
viewThread->setPriority(THREAD_PRIORITY_RENDER);
|
viewThread->setPriority(THREAD_PRIORITY_RENDER);
|
||||||
viewThread->start();
|
viewThread->start();
|
||||||
|
|||||||
@ -57,7 +57,6 @@ private:
|
|||||||
GpsModel model = GpsModel::Unknown;
|
GpsModel model = GpsModel::Unknown;
|
||||||
State state = State::Off;
|
State state = State::Off;
|
||||||
|
|
||||||
static int32_t threadMainStatic(void* parameter);
|
|
||||||
int32_t threadMain();
|
int32_t threadMain();
|
||||||
|
|
||||||
bool isThreadInterrupted() const;
|
bool isThreadInterrupted() const;
|
||||||
|
|||||||
@ -29,10 +29,10 @@ typedef uint32_t SystemEventSubscription;
|
|||||||
|
|
||||||
typedef std::function<void(SystemEvent)> OnSystemEvent;
|
typedef std::function<void(SystemEvent)> OnSystemEvent;
|
||||||
|
|
||||||
void systemEventPublish(SystemEvent event);
|
void publishSystemEvent(SystemEvent event);
|
||||||
|
|
||||||
SystemEventSubscription systemEventAddListener(SystemEvent event, OnSystemEvent handler);
|
SystemEventSubscription subscribeSystemEvent(SystemEvent event, OnSystemEvent handler);
|
||||||
|
|
||||||
void systemEventRemoveListener(SystemEventSubscription subscription);
|
void unsubscribeSystemEvent(SystemEventSubscription subscription);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -31,10 +31,8 @@ private:
|
|||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
|
|
||||||
// Dispatcher calls this and forwards to non-static function
|
// Dispatcher calls this and forwards to non-static function
|
||||||
static void enableFromDispatcher(std::shared_ptr<void> context);
|
|
||||||
void enableFromDispatcher(const EspNowConfig& config);
|
void enableFromDispatcher(const EspNowConfig& config);
|
||||||
|
|
||||||
static void disableFromDispatcher(std::shared_ptr<void> context);
|
|
||||||
void disableFromDispatcher();
|
void disableFromDispatcher();
|
||||||
|
|
||||||
static void receiveCallback(const esp_now_recv_info_t* receiveInfo, const uint8_t* data, int length);
|
static void receiveCallback(const esp_now_recv_info_t* receiveInfo, const uint8_t* data, int length);
|
||||||
|
|||||||
@ -37,7 +37,7 @@ private:
|
|||||||
static int32_t bootThreadCallback(TT_UNUSED void* context) {
|
static int32_t bootThreadCallback(TT_UNUSED void* context) {
|
||||||
TickType_t start_time = kernel::getTicks();
|
TickType_t start_time = kernel::getTicks();
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootSplash);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
|
||||||
|
|
||||||
auto hal_display = getHalDisplay();
|
auto hal_display = getHalDisplay();
|
||||||
assert(hal_display != nullptr);
|
assert(hal_display != nullptr);
|
||||||
|
|||||||
@ -21,7 +21,7 @@ private:
|
|||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
static lv_obj_t* createGpioRowWrapper(lv_obj_t* parent);
|
static lv_obj_t* createGpioRowWrapper(lv_obj_t* parent);
|
||||||
static void onTimer(TT_UNUSED std::shared_ptr<void> context);
|
void onTimer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -49,9 +49,9 @@ void GpioApp::updatePinStates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GpioApp::updatePinWidgets() {
|
void GpioApp::updatePinWidgets() {
|
||||||
auto scoped_lvgl_lock = lvgl::getSyncLock()->scoped();
|
auto scoped_lvgl_lock = lvgl::getSyncLock()->asScopedLock();
|
||||||
auto scoped_gpio_lock = mutex.asScopedLock();
|
auto scoped_gpio_lock = mutex.asScopedLock();
|
||||||
if (scoped_gpio_lock.lock() && scoped_lvgl_lock->lock(100)) {
|
if (scoped_gpio_lock.lock() && scoped_lvgl_lock.lock(lvgl::defaultLockTime)) {
|
||||||
for (int j = 0; j < GPIO_NUM_MAX; ++j) {
|
for (int j = 0; j < GPIO_NUM_MAX; ++j) {
|
||||||
int level = pinStates[j];
|
int level = pinStates[j];
|
||||||
lv_obj_t* label = lvPins[j];
|
lv_obj_t* label = lvPins[j];
|
||||||
@ -79,24 +79,17 @@ lv_obj_t* GpioApp::createGpioRowWrapper(lv_obj_t* parent) {
|
|||||||
|
|
||||||
// region Task
|
// region Task
|
||||||
|
|
||||||
void GpioApp::onTimer(TT_UNUSED std::shared_ptr<void> context) {
|
void GpioApp::onTimer() {
|
||||||
auto appContext = getCurrentAppContext();
|
updatePinStates();
|
||||||
if (appContext->getManifest().id == manifest.id) {
|
updatePinWidgets();
|
||||||
auto app = std::static_pointer_cast<GpioApp>(appContext->getApp());
|
|
||||||
if (app != nullptr) {
|
|
||||||
app->updatePinStates();
|
|
||||||
app->updatePinWidgets();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpioApp::startTask() {
|
void GpioApp::startTask() {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
assert(timer == nullptr);
|
assert(timer == nullptr);
|
||||||
timer = std::make_unique<Timer>(
|
timer = std::make_unique<Timer>(Timer::Type::Periodic, [this]() {
|
||||||
Timer::Type::Periodic,
|
onTimer();
|
||||||
&onTimer
|
});
|
||||||
);
|
|
||||||
timer->start(100 / portTICK_PERIOD_MS);
|
timer->start(100 / portTICK_PERIOD_MS);
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,12 +39,6 @@ private:
|
|||||||
PubSub::SubscriptionHandle serviceStateSubscription = nullptr;
|
PubSub::SubscriptionHandle serviceStateSubscription = nullptr;
|
||||||
std::shared_ptr<service::gps::GpsService> service;
|
std::shared_ptr<service::gps::GpsService> service;
|
||||||
|
|
||||||
static void onUpdateCallback(TT_UNUSED std::shared_ptr<void> context) {
|
|
||||||
auto appPtr = std::static_pointer_cast<GpsSettingsApp*>(context);
|
|
||||||
auto app = *appPtr;
|
|
||||||
app->updateViews();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onServiceStateChangedCallback(const void* data, void* context) {
|
static void onServiceStateChangedCallback(const void* data, void* context) {
|
||||||
auto* app = (GpsSettingsApp*)context;
|
auto* app = (GpsSettingsApp*)context;
|
||||||
app->onServiceStateChanged();
|
app->onServiceStateChanged();
|
||||||
@ -266,13 +260,13 @@ private:
|
|||||||
if (wants_on != is_on) {
|
if (wants_on != is_on) {
|
||||||
// start/stop are potentially blocking calls, so we use a dispatcher to not block the UI
|
// start/stop are potentially blocking calls, so we use a dispatcher to not block the UI
|
||||||
if (wants_on) {
|
if (wants_on) {
|
||||||
getMainDispatcher().dispatch([](auto service) {
|
getMainDispatcher().dispatch([this]() {
|
||||||
std::static_pointer_cast<service::gps::GpsService>(service)->startReceiving();
|
service->startReceiving();
|
||||||
}, service);
|
});
|
||||||
} else {
|
} else {
|
||||||
getMainDispatcher().dispatch([](auto service) {
|
getMainDispatcher().dispatch([this]() {
|
||||||
std::static_pointer_cast<service::gps::GpsService>(service)->stopReceiving();
|
service->stopReceiving();
|
||||||
}, service);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +274,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
GpsSettingsApp() {
|
GpsSettingsApp() {
|
||||||
timer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdateCallback, appReference);
|
timer = std::make_unique<Timer>(Timer::Type::Periodic, [this]() {
|
||||||
|
updateViews();
|
||||||
|
});
|
||||||
service = service::gps::findGpsService();
|
service = service::gps::findGpsService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@ private:
|
|||||||
|
|
||||||
static void onSelectBusCallback(lv_event_t* event);
|
static void onSelectBusCallback(lv_event_t* event);
|
||||||
static void onPressScanCallback(lv_event_t* event);
|
static void onPressScanCallback(lv_event_t* event);
|
||||||
static void onScanTimerCallback(std::shared_ptr<void> context);
|
static void onScanTimerCallback();
|
||||||
|
|
||||||
void onSelectBus(lv_event_t* event);
|
void onSelectBus(lv_event_t* event);
|
||||||
void onPressScan(lv_event_t* event);
|
void onPressScan(lv_event_t* event);
|
||||||
@ -180,7 +180,7 @@ void I2cScannerApp::onPressScanCallback(lv_event_t* event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2cScannerApp::onScanTimerCallback(TT_UNUSED std::shared_ptr<void> context) {
|
void I2cScannerApp::onScanTimerCallback() {
|
||||||
auto app = optApp();
|
auto app = optApp();
|
||||||
if (app != nullptr) {
|
if (app != nullptr) {
|
||||||
app->onScanTimer();
|
app->onScanTimer();
|
||||||
@ -284,10 +284,9 @@ void I2cScannerApp::startScanning() {
|
|||||||
lv_obj_clean(scanListWidget);
|
lv_obj_clean(scanListWidget);
|
||||||
|
|
||||||
scanState = ScanStateScanning;
|
scanState = ScanStateScanning;
|
||||||
scanTimer = std::make_unique<Timer>(
|
scanTimer = std::make_unique<Timer>(Timer::Type::Once, [](){
|
||||||
Timer::Type::Once,
|
onScanTimerCallback();
|
||||||
onScanTimerCallback
|
});
|
||||||
);
|
|
||||||
scanTimer->start(10);
|
scanTimer->start(10);
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class PowerApp : public App {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Timer update_timer = Timer(Timer::Type::Periodic, &onTimer, nullptr);
|
Timer update_timer = Timer(Timer::Type::Periodic, []() { onTimer(); });
|
||||||
|
|
||||||
std::shared_ptr<hal::power::PowerDevice> power;
|
std::shared_ptr<hal::power::PowerDevice> power;
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ private:
|
|||||||
lv_obj_t* chargeLevelLabel = nullptr;
|
lv_obj_t* chargeLevelLabel = nullptr;
|
||||||
lv_obj_t* currentLabel = nullptr;
|
lv_obj_t* currentLabel = nullptr;
|
||||||
|
|
||||||
static void onTimer(TT_UNUSED std::shared_ptr<void> context) {
|
static void onTimer() {
|
||||||
auto app = optApp();
|
auto app = optApp();
|
||||||
if (app != nullptr) {
|
if (app != nullptr) {
|
||||||
app->updateUi();
|
app->updateUi();
|
||||||
|
|||||||
@ -72,15 +72,10 @@ static void onModeSetCallback(TT_UNUSED lv_event_t* event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onTimerCallback(TT_UNUSED std::shared_ptr<void> context) {
|
|
||||||
auto app = optApp();
|
|
||||||
if (app != nullptr) {
|
|
||||||
app->onTimerTick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenshotApp::ScreenshotApp() {
|
ScreenshotApp::ScreenshotApp() {
|
||||||
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onTimerCallback, nullptr);
|
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, [this]() {
|
||||||
|
onTimerTick();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenshotApp::~ScreenshotApp() {
|
ScreenshotApp::~ScreenshotApp() {
|
||||||
@ -90,8 +85,8 @@ ScreenshotApp::~ScreenshotApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenshotApp::onTimerTick() {
|
void ScreenshotApp::onTimerTick() {
|
||||||
auto lvgl_lock = lvgl::getSyncLock()->scoped();
|
auto lock = lvgl::getSyncLock()->asScopedLock();
|
||||||
if (lvgl_lock->lock(50 / portTICK_PERIOD_MS)) {
|
if (lock.lock(lvgl::defaultLockTime)) {
|
||||||
updateScreenshotMode();
|
updateScreenshotMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,7 +117,7 @@ private:
|
|||||||
lv_obj_add_event_cb(btn, &onListItemSelectedCallback, LV_EVENT_SHORT_CLICKED, (void*)index);
|
lv_obj_add_event_cb(btn, &onListItemSelectedCallback, LV_EVENT_SHORT_CLICKED, (void*)index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateTimerCallback(std::shared_ptr<void> context) {
|
static void updateTimerCallback() {
|
||||||
auto appContext = getCurrentAppContext();
|
auto appContext = getCurrentAppContext();
|
||||||
if (appContext != nullptr && appContext->getManifest().id == manifest.id) {
|
if (appContext != nullptr && appContext->getManifest().id == manifest.id) {
|
||||||
auto app = std::static_pointer_cast<TimeZoneApp>(appContext->getApp());
|
auto app = std::static_pointer_cast<TimeZoneApp>(appContext->getApp());
|
||||||
@ -231,7 +231,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onCreate(AppContext& app) override {
|
void onCreate(AppContext& app) override {
|
||||||
updateTimer = std::make_unique<Timer>(Timer::Type::Once, updateTimerCallback, nullptr);
|
updateTimer = std::make_unique<Timer>(Timer::Type::Once, []() { updateTimerCallback(); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -69,7 +69,13 @@ static void connect(lv_event_t* event) {
|
|||||||
if (ssid != nullptr) {
|
if (ssid != nullptr) {
|
||||||
TT_LOG_I(TAG, "Clicked AP: %s", ssid);
|
TT_LOG_I(TAG, "Clicked AP: %s", ssid);
|
||||||
auto* bindings = (Bindings*)lv_event_get_user_data(event);
|
auto* bindings = (Bindings*)lv_event_get_user_data(event);
|
||||||
bindings->onConnectSsid(ssid);
|
|
||||||
|
std::string connection_target = service::wifi::getConnectionTarget();
|
||||||
|
if (connection_target == ssid) {
|
||||||
|
bindings->onDisconnect();
|
||||||
|
} else {
|
||||||
|
bindings->onConnectSsid(ssid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,19 +15,19 @@
|
|||||||
namespace tt::hal {
|
namespace tt::hal {
|
||||||
|
|
||||||
void init(const Configuration& configuration) {
|
void init(const Configuration& configuration) {
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitHalBegin);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitHalBegin);
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitI2cBegin);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitI2cBegin);
|
||||||
tt_check(i2c::init(configuration.i2c), "I2C init failed");
|
tt_check(i2c::init(configuration.i2c), "I2C init failed");
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitI2cEnd);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitI2cEnd);
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitSpiBegin);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitSpiBegin);
|
||||||
tt_check(spi::init(configuration.spi), "SPI init failed");
|
tt_check(spi::init(configuration.spi), "SPI init failed");
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitSpiEnd);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitSpiEnd);
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitUartBegin);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitUartBegin);
|
||||||
tt_check(uart::init(configuration.uart), "UART init failed");
|
tt_check(uart::init(configuration.uart), "UART init failed");
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitUartEnd);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitUartEnd);
|
||||||
|
|
||||||
if (configuration.initBoot != nullptr) {
|
if (configuration.initBoot != nullptr) {
|
||||||
TT_LOG_I(TAG, "Init power");
|
TT_LOG_I(TAG, "Init power");
|
||||||
@ -47,7 +47,7 @@ void init(const Configuration& configuration) {
|
|||||||
hal::registerDevice(power);
|
hal::registerDevice(power);
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitHalEnd);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitHalEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -10,11 +10,6 @@ namespace tt::hal::gps {
|
|||||||
constexpr uint32_t GPS_UART_BUFFER_SIZE = 256;
|
constexpr uint32_t GPS_UART_BUFFER_SIZE = 256;
|
||||||
constexpr const char* TAG = "GpsDevice";
|
constexpr const char* TAG = "GpsDevice";
|
||||||
|
|
||||||
int32_t GpsDevice::threadMainStatic(void* parameter) {
|
|
||||||
auto* gps_device = (GpsDevice*)parameter;
|
|
||||||
return gps_device->threadMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t GpsDevice::threadMain() {
|
int32_t GpsDevice::threadMain() {
|
||||||
uint8_t buffer[GPS_UART_BUFFER_SIZE];
|
uint8_t buffer[GPS_UART_BUFFER_SIZE];
|
||||||
|
|
||||||
@ -125,8 +120,9 @@ bool GpsDevice::start() {
|
|||||||
thread = std::make_unique<Thread>(
|
thread = std::make_unique<Thread>(
|
||||||
"gps",
|
"gps",
|
||||||
4096,
|
4096,
|
||||||
threadMainStatic,
|
[this]() {
|
||||||
this
|
return this->threadMain();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
thread->setPriority(tt::Thread::Priority::High);
|
thread->setPriority(tt::Thread::Priority::High);
|
||||||
thread->start();
|
thread->start();
|
||||||
|
|||||||
@ -55,7 +55,7 @@ static const char* getEventName(SystemEvent event) {
|
|||||||
tt_crash(); // Missing case above
|
tt_crash(); // Missing case above
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemEventPublish(SystemEvent event) {
|
void publishSystemEvent(SystemEvent event) {
|
||||||
TT_LOG_I(TAG, "%s", getEventName(event));
|
TT_LOG_I(TAG, "%s", getEventName(event));
|
||||||
|
|
||||||
if (mutex.lock(portMAX_DELAY)) {
|
if (mutex.lock(portMAX_DELAY)) {
|
||||||
@ -69,7 +69,7 @@ void systemEventPublish(SystemEvent event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemEventSubscription systemEventAddListener(SystemEvent event, std::function<void(SystemEvent)> handler) {
|
SystemEventSubscription subscribeSystemEvent(SystemEvent event, OnSystemEvent handler) {
|
||||||
if (mutex.lock(portMAX_DELAY)) {
|
if (mutex.lock(portMAX_DELAY)) {
|
||||||
auto id = ++subscriptionCounter;
|
auto id = ++subscriptionCounter;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ SystemEventSubscription systemEventAddListener(SystemEvent event, std::function<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemEventRemoveListener(SystemEventSubscription subscription) {
|
void unsubscribeSystemEvent(SystemEventSubscription subscription) {
|
||||||
if (mutex.lock(portMAX_DELAY)) {
|
if (mutex.lock(portMAX_DELAY)) {
|
||||||
std::erase_if(subscriptions, [subscription](auto& item) {
|
std::erase_if(subscriptions, [subscription](auto& item) {
|
||||||
return (item.id == subscription);
|
return (item.id == subscription);
|
||||||
|
|||||||
@ -84,7 +84,7 @@ static bool initKeyboard(const std::shared_ptr<hal::display::DisplayDevice>& dis
|
|||||||
void init(const hal::Configuration& config) {
|
void init(const hal::Configuration& config) {
|
||||||
TT_LOG_I(TAG, "Starting");
|
TT_LOG_I(TAG, "Starting");
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitLvglBegin);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitLvglBegin);
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
if (config.lvglInit == hal::LvglInit::Default && !initEspLvglPort()) {
|
if (config.lvglInit == hal::LvglInit::Default && !initEspLvglPort()) {
|
||||||
@ -114,7 +114,7 @@ void init(const hal::Configuration& config) {
|
|||||||
|
|
||||||
TT_LOG_I(TAG, "Finished");
|
TT_LOG_I(TAG, "Finished");
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitLvglEnd);
|
kernel::publishSystemEvent(kernel::SystemEvent::BootInitLvglEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace tt::lvgl {
|
|||||||
|
|
||||||
#define TAG "statusbar"
|
#define TAG "statusbar"
|
||||||
|
|
||||||
static void onUpdateTime(TT_UNUSED std::shared_ptr<void> context);
|
static void onUpdateTime();
|
||||||
|
|
||||||
struct StatusbarIcon {
|
struct StatusbarIcon {
|
||||||
std::string image;
|
std::string image;
|
||||||
@ -30,7 +30,7 @@ struct StatusbarData {
|
|||||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||||
std::shared_ptr<PubSub> pubsub = std::make_shared<PubSub>();
|
std::shared_ptr<PubSub> pubsub = std::make_shared<PubSub>();
|
||||||
StatusbarIcon icons[STATUSBAR_ICON_LIMIT] = {};
|
StatusbarIcon icons[STATUSBAR_ICON_LIMIT] = {};
|
||||||
Timer* time_update_timer = new Timer(Timer::Type::Once, onUpdateTime, nullptr);
|
Timer* time_update_timer = new Timer(Timer::Type::Once, []() { onUpdateTime(); });
|
||||||
uint8_t time_hours = 0;
|
uint8_t time_hours = 0;
|
||||||
uint8_t time_minutes = 0;
|
uint8_t time_minutes = 0;
|
||||||
bool time_set = false;
|
bool time_set = false;
|
||||||
@ -70,7 +70,7 @@ static TickType_t getNextUpdateTime() {
|
|||||||
return pdMS_TO_TICKS(seconds_to_wait * 1000U);
|
return pdMS_TO_TICKS(seconds_to_wait * 1000U);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onUpdateTime(TT_UNUSED std::shared_ptr<void> context) {
|
static void onUpdateTime() {
|
||||||
time_t now = ::time(nullptr);
|
time_t now = ::time(nullptr);
|
||||||
struct tm* tm_struct = localtime(&now);
|
struct tm* tm_struct = localtime(&now);
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ static void statusbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
|
|||||||
|
|
||||||
if (!statusbar_data.time_update_timer->isRunning()) {
|
if (!statusbar_data.time_update_timer->isRunning()) {
|
||||||
statusbar_data.time_update_timer->start(50 / portTICK_PERIOD_MS);
|
statusbar_data.time_update_timer->start(50 / portTICK_PERIOD_MS);
|
||||||
statusbar_data.systemEventSubscription = kernel::systemEventAddListener(
|
statusbar_data.systemEventSubscription = kernel::subscribeSystemEvent(
|
||||||
kernel::SystemEvent::Time,
|
kernel::SystemEvent::Time,
|
||||||
onNetworkConnected
|
onNetworkConnected
|
||||||
);
|
);
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace tt::network::ntp {
|
|||||||
|
|
||||||
static void onTimeSynced(struct timeval* tv) {
|
static void onTimeSynced(struct timeval* tv) {
|
||||||
TT_LOG_I(TAG, "Time synced (%llu)", tv->tv_sec);
|
TT_LOG_I(TAG, "Time synced (%llu)", tv->tv_sec);
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
kernel::publishSystemEvent(kernel::SystemEvent::Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
|
|||||||
@ -38,20 +38,9 @@ void EspNowService::onStop(ServiceContext& service) {
|
|||||||
// region Enable
|
// region Enable
|
||||||
|
|
||||||
void EspNowService::enable(const EspNowConfig& config) {
|
void EspNowService::enable(const EspNowConfig& config) {
|
||||||
auto enable_context = std::make_shared<EspNowConfig>(config);
|
getMainDispatcher().dispatch([this, config]() {
|
||||||
getMainDispatcher().dispatch(enableFromDispatcher, enable_context);
|
enableFromDispatcher(config);
|
||||||
}
|
});
|
||||||
|
|
||||||
void EspNowService::enableFromDispatcher(std::shared_ptr<void> context) {
|
|
||||||
auto service = findService();
|
|
||||||
if (service == nullptr) {
|
|
||||||
TT_LOG_E(TAG, "Service not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto config = std::static_pointer_cast<EspNowConfig>(context);
|
|
||||||
|
|
||||||
service->enableFromDispatcher(*config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspNowService::enableFromDispatcher(const EspNowConfig& config) {
|
void EspNowService::enableFromDispatcher(const EspNowConfig& config) {
|
||||||
@ -101,17 +90,9 @@ void EspNowService::enableFromDispatcher(const EspNowConfig& config) {
|
|||||||
// region Disable
|
// region Disable
|
||||||
|
|
||||||
void EspNowService::disable() {
|
void EspNowService::disable() {
|
||||||
getMainDispatcher().dispatch(disableFromDispatcher, nullptr);
|
getMainDispatcher().dispatch([this]() {
|
||||||
}
|
disableFromDispatcher();
|
||||||
|
});
|
||||||
void EspNowService::disableFromDispatcher(TT_UNUSED std::shared_ptr<void> context) {
|
|
||||||
auto service = findService();
|
|
||||||
if (service == nullptr) {
|
|
||||||
TT_LOG_E(TAG, "Service not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
service->disableFromDispatcher();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EspNowService::disableFromDispatcher() {
|
void EspNowService::disableFromDispatcher() {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "Tactility/app/AppManifest.h"
|
#include "Tactility/app/AppManifest.h"
|
||||||
#include "Tactility/app/ManifestRegistry.h"
|
#include "Tactility/app/ManifestRegistry.h"
|
||||||
#include "Tactility/service/gui/Gui.h"
|
|
||||||
#include "Tactility/service/loader/Loader_i.h"
|
#include "Tactility/service/loader/Loader_i.h"
|
||||||
|
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
@ -54,9 +53,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::unique_ptr<DispatcherThread> dispatcherThread = std::make_unique<DispatcherThread>("loader_dispatcher", 6144); // Files app requires ~5k
|
std::unique_ptr<DispatcherThread> dispatcherThread = std::make_unique<DispatcherThread>("loader_dispatcher", 6144); // Files app requires ~5k
|
||||||
|
|
||||||
static void onStartAppMessageCallback(std::shared_ptr<void> message);
|
|
||||||
static void onStopAppMessageCallback(std::shared_ptr<void> message);
|
|
||||||
|
|
||||||
void onStartAppMessage(const std::string& id, std::shared_ptr<const Bundle> parameters);
|
void onStartAppMessage(const std::string& id, std::shared_ptr<const Bundle> parameters);
|
||||||
void onStopAppMessage(const std::string& id);
|
void onStopAppMessage(const std::string& id);
|
||||||
|
|
||||||
@ -86,14 +82,6 @@ std::shared_ptr<LoaderService> _Nullable optScreenshotService() {
|
|||||||
return service::findServiceById<LoaderService>(manifest.id);
|
return service::findServiceById<LoaderService>(manifest.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoaderService::onStartAppMessageCallback(std::shared_ptr<void> message) {
|
|
||||||
auto start_message = std::reinterpret_pointer_cast<LoaderMessageAppStart>(message);
|
|
||||||
auto& id = start_message->id;
|
|
||||||
auto& parameters = start_message->parameters;
|
|
||||||
|
|
||||||
optScreenshotService()->onStartAppMessage(id, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoaderService::onStartAppMessage(const std::string& id, std::shared_ptr<const Bundle> parameters) {
|
void LoaderService::onStartAppMessage(const std::string& id, std::shared_ptr<const Bundle> parameters) {
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Start by id %s", id.c_str());
|
TT_LOG_I(TAG, "Start by id %s", id.c_str());
|
||||||
@ -130,12 +118,6 @@ void LoaderService::onStartAppMessage(const std::string& id, std::shared_ptr<con
|
|||||||
pubsubExternal->publish(&event_external);
|
pubsubExternal->publish(&event_external);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoaderService::onStopAppMessageCallback(std::shared_ptr<void> message) {
|
|
||||||
TT_LOG_I(TAG, "OnStopAppMessageCallback");
|
|
||||||
auto stop_message = std::reinterpret_pointer_cast<LoaderMessageAppStop>(message);
|
|
||||||
optScreenshotService()->onStopAppMessage(stop_message->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoaderService::onStopAppMessage(const std::string& id) {
|
void LoaderService::onStopAppMessage(const std::string& id) {
|
||||||
|
|
||||||
auto lock = mutex.asScopedLock();
|
auto lock = mutex.asScopedLock();
|
||||||
@ -271,14 +253,17 @@ void LoaderService::transitionAppToState(const std::shared_ptr<app::AppInstance>
|
|||||||
|
|
||||||
void LoaderService::startApp(const std::string& id, std::shared_ptr<const Bundle> parameters) {
|
void LoaderService::startApp(const std::string& id, std::shared_ptr<const Bundle> parameters) {
|
||||||
auto message = std::make_shared<LoaderMessageAppStart>(id, std::move(parameters));
|
auto message = std::make_shared<LoaderMessageAppStart>(id, std::move(parameters));
|
||||||
dispatcherThread->dispatch(onStartAppMessageCallback, message);
|
dispatcherThread->dispatch([this, id, parameters]() {
|
||||||
|
onStartAppMessage(id, parameters);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoaderService::stopApp() {
|
void LoaderService::stopApp() {
|
||||||
TT_LOG_I(TAG, "stopApp()");
|
TT_LOG_I(TAG, "stopApp()");
|
||||||
auto id = getCurrentAppContext()->getManifest().id;
|
auto id = getCurrentAppContext()->getManifest().id;
|
||||||
auto message = std::make_shared<LoaderMessageAppStop>(id);
|
dispatcherThread->dispatch([this, id]() {
|
||||||
dispatcherThread->dispatch(onStopAppMessageCallback, message);
|
onStopAppMessage(id);
|
||||||
|
});
|
||||||
TT_LOG_I(TAG, "dispatched");
|
TT_LOG_I(TAG, "dispatched");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,17 +49,14 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onUpdate(std::shared_ptr<void> context) {
|
|
||||||
auto service = std::static_pointer_cast<SdCardService>(context);
|
|
||||||
service->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void onStart(ServiceContext& serviceContext) final {
|
void onStart(ServiceContext& serviceContext) final {
|
||||||
if (hal::getConfiguration()->sdcard != nullptr) {
|
if (hal::getConfiguration()->sdcard != nullptr) {
|
||||||
auto service = findServiceById(manifest.id);
|
auto service = findServiceById<SdCardService>(manifest.id);
|
||||||
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, service);
|
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, [service]() {
|
||||||
|
service->update();
|
||||||
|
});
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
updateTimer->start(1000);
|
updateTimer->start(1000);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -223,8 +223,7 @@ private:
|
|||||||
updatePowerStatusIcon();
|
updatePowerStatusIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onUpdate(std::shared_ptr<void> parameter) {
|
static void onUpdate(const std::shared_ptr<StatusbarService>& service) {
|
||||||
auto service = std::static_pointer_cast<StatusbarService>(parameter);
|
|
||||||
service->update();
|
service->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,11 +241,14 @@ public:
|
|||||||
// TODO: Make thread-safe for LVGL
|
// TODO: Make thread-safe for LVGL
|
||||||
lvgl::statusbar_icon_set_visibility(wifi_icon_id, true);
|
lvgl::statusbar_icon_set_visibility(wifi_icon_id, true);
|
||||||
|
|
||||||
auto service = findServiceById(manifest.id);
|
auto service = findServiceById<StatusbarService>(manifest.id);
|
||||||
assert(service);
|
assert(service);
|
||||||
onUpdate(service);
|
onUpdate(service);
|
||||||
|
|
||||||
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, service);
|
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, [service]() {
|
||||||
|
onUpdate(service);
|
||||||
|
});
|
||||||
|
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
updateTimer->start(1000);
|
updateTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,12 @@ namespace tt::service::wifi {
|
|||||||
class Wifi;
|
class Wifi;
|
||||||
static void scan_list_free_safely(std::shared_ptr<Wifi> wifi);
|
static void scan_list_free_safely(std::shared_ptr<Wifi> wifi);
|
||||||
// Methods for main thread dispatcher
|
// Methods for main thread dispatcher
|
||||||
static void dispatchAutoConnect(std::shared_ptr<void> context);
|
static void dispatchAutoConnect(std::shared_ptr<Wifi> wifi);
|
||||||
static void dispatchEnable(std::shared_ptr<void> context);
|
static void dispatchEnable(std::shared_ptr<Wifi> wifi);
|
||||||
static void dispatchDisable(std::shared_ptr<void> context);
|
static void dispatchDisable(std::shared_ptr<Wifi> wifi);
|
||||||
static void dispatchScan(std::shared_ptr<void> context);
|
static void dispatchScan(std::shared_ptr<Wifi> wifi);
|
||||||
static void dispatchConnect(std::shared_ptr<void> context);
|
static void dispatchConnect(std::shared_ptr<Wifi> wifi);
|
||||||
static void dispatchDisconnectButKeepActive(std::shared_ptr<void> context);
|
static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi);
|
||||||
|
|
||||||
class Wifi {
|
class Wifi {
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ void scan() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMainDispatcher().dispatch(dispatchScan, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchScan(wifi); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isScanning() {
|
bool isScanning() {
|
||||||
@ -202,10 +202,10 @@ void connect(const settings::WifiApSettings* ap, bool remember) {
|
|||||||
wifi->connection_target_remember = remember;
|
wifi->connection_target_remember = remember;
|
||||||
|
|
||||||
if (wifi->getRadioState() == RadioState::Off) {
|
if (wifi->getRadioState() == RadioState::Off) {
|
||||||
getMainDispatcher().dispatch(dispatchEnable, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchEnable(wifi); });
|
||||||
}
|
}
|
||||||
|
|
||||||
getMainDispatcher().dispatch(dispatchConnect, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchConnect(wifi); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnect() {
|
void disconnect() {
|
||||||
@ -227,7 +227,7 @@ void disconnect() {
|
|||||||
};
|
};
|
||||||
// Manual disconnect (e.g. via app) should stop auto-connecting until a new connection is established
|
// Manual disconnect (e.g. via app) should stop auto-connecting until a new connection is established
|
||||||
wifi->pause_auto_connect = true;
|
wifi->pause_auto_connect = true;
|
||||||
getMainDispatcher().dispatch(dispatchDisconnectButKeepActive, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchDisconnectButKeepActive(wifi); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void setScanRecords(uint16_t records) {
|
void setScanRecords(uint16_t records) {
|
||||||
@ -291,10 +291,11 @@ void setEnabled(bool enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
getMainDispatcher().dispatch(dispatchEnable, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchEnable(wifi); });
|
||||||
} else {
|
} else {
|
||||||
getMainDispatcher().dispatch(dispatchDisable, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchDisable(wifi); });
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi->pause_auto_connect = false;
|
wifi->pause_auto_connect = false;
|
||||||
wifi->last_scan_time = 0;
|
wifi->last_scan_time = 0;
|
||||||
}
|
}
|
||||||
@ -405,8 +406,7 @@ static bool copy_scan_list(std::shared_ptr<Wifi> wifi) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_auto_connect_ap(std::shared_ptr<void> context, settings::WifiApSettings& settings) {
|
static bool find_auto_connect_ap(std::shared_ptr<Wifi> wifi, settings::WifiApSettings& settings) {
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
auto lock = wifi->dataMutex.asScopedLock();
|
||||||
|
|
||||||
if (lock.lock(10 / portTICK_PERIOD_MS)) {
|
if (lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||||
@ -430,14 +430,16 @@ static bool find_auto_connect_ap(std::shared_ptr<void> context, settings::WifiAp
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchAutoConnect(std::shared_ptr<void> context) {
|
static void dispatchAutoConnect(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchAutoConnect()");
|
TT_LOG_I(TAG, "dispatchAutoConnect()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
|
|
||||||
settings::WifiApSettings settings;
|
settings::WifiApSettings settings;
|
||||||
if (find_auto_connect_ap(context, settings)) {
|
if (find_auto_connect_ap(wifi, settings)) {
|
||||||
TT_LOG_I(TAG, "Auto-connecting to %s", settings.ssid);
|
TT_LOG_I(TAG, "Auto-connecting to %s", settings.ssid);
|
||||||
connect(&settings, false);
|
connect(&settings, false);
|
||||||
|
// TODO: We currently have to manually reset it because connect() sets it.
|
||||||
|
// connect() assumes it's only being called by the user and not internally, so it disables auto-connect
|
||||||
|
wifi->pause_auto_connect = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,8 +463,16 @@ static void eventHandler(TT_UNUSED void* arg, esp_event_base_t event_base, int32
|
|||||||
}
|
}
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
TT_LOG_I(TAG, "eventHandler: disconnected");
|
TT_LOG_I(TAG, "eventHandler: disconnected");
|
||||||
if (wifi->getRadioState() == RadioState::ConnectionPending) {
|
switch (wifi->getRadioState()) {
|
||||||
wifi->connection_wait_flags.set(WIFI_FAIL_BIT);
|
case RadioState::ConnectionPending:
|
||||||
|
wifi->connection_wait_flags.set(WIFI_FAIL_BIT);
|
||||||
|
break;
|
||||||
|
case RadioState::On:
|
||||||
|
// Ensure we can reconnect again
|
||||||
|
wifi->pause_auto_connect = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
wifi->setRadioState(RadioState::On);
|
wifi->setRadioState(RadioState::On);
|
||||||
publish_event_simple(wifi, EventType::Disconnected);
|
publish_event_simple(wifi, EventType::Disconnected);
|
||||||
@ -493,14 +503,13 @@ static void eventHandler(TT_UNUSED void* arg, esp_event_base_t event_base, int32
|
|||||||
TT_LOG_I(TAG, "eventHandler: Finished scan");
|
TT_LOG_I(TAG, "eventHandler: Finished scan");
|
||||||
|
|
||||||
if (copied_list && wifi_singleton->getRadioState() == RadioState::On && !wifi->pause_auto_connect) {
|
if (copied_list && wifi_singleton->getRadioState() == RadioState::On && !wifi->pause_auto_connect) {
|
||||||
getMainDispatcher().dispatch(dispatchAutoConnect, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchAutoConnect(wifi); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchEnable(std::shared_ptr<void> context) {
|
static void dispatchEnable(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchEnable()");
|
TT_LOG_I(TAG, "dispatchEnable()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
RadioState state = wifi->getRadioState();
|
||||||
if (
|
if (
|
||||||
@ -580,15 +589,17 @@ static void dispatchEnable(std::shared_ptr<void> context) {
|
|||||||
|
|
||||||
wifi->setRadioState(RadioState::On);
|
wifi->setRadioState(RadioState::On);
|
||||||
publish_event_simple(wifi, EventType::RadioStateOn);
|
publish_event_simple(wifi, EventType::RadioStateOn);
|
||||||
|
|
||||||
|
wifi->pause_auto_connect = false;
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Enabled");
|
TT_LOG_I(TAG, "Enabled");
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
TT_LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchDisable(std::shared_ptr<void> context) {
|
static void dispatchDisable(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchDisable()");
|
TT_LOG_I(TAG, "dispatchDisable()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
auto lock = wifi->radioMutex.asScopedLock();
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
@ -653,9 +664,8 @@ static void dispatchDisable(std::shared_ptr<void> context) {
|
|||||||
TT_LOG_I(TAG, "Disabled");
|
TT_LOG_I(TAG, "Disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchScan(std::shared_ptr<void> context) {
|
static void dispatchScan(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchScan()");
|
TT_LOG_I(TAG, "dispatchScan()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
auto lock = wifi->radioMutex.asScopedLock();
|
||||||
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||||
@ -687,9 +697,8 @@ static void dispatchScan(std::shared_ptr<void> context) {
|
|||||||
publish_event_simple(wifi, EventType::ScanStarted);
|
publish_event_simple(wifi, EventType::ScanStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchConnect(std::shared_ptr<void> context) {
|
static void dispatchConnect(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchConnect()");
|
TT_LOG_I(TAG, "dispatchConnect()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
auto lock = wifi->radioMutex.asScopedLock();
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
@ -786,9 +795,8 @@ static void dispatchConnect(std::shared_ptr<void> context) {
|
|||||||
wifi_singleton->connection_wait_flags.clear(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
wifi_singleton->connection_wait_flags.clear(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchDisconnectButKeepActive(std::shared_ptr<void> context) {
|
static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi) {
|
||||||
TT_LOG_I(TAG, "dispatchDisconnectButKeepActive()");
|
TT_LOG_I(TAG, "dispatchDisconnectButKeepActive()");
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(context);
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
auto lock = wifi->radioMutex.asScopedLock();
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
@ -836,6 +844,7 @@ static void dispatchDisconnectButKeepActive(std::shared_ptr<void> context) {
|
|||||||
static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
auto lock = wifi->dataMutex.asScopedLock();
|
||||||
if (!lock.lock(100)) {
|
if (!lock.lock(100)) {
|
||||||
|
TT_LOG_W(TAG, "Auto-connect can't lock");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -844,6 +853,7 @@ static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
|||||||
!wifi->pause_auto_connect;
|
!wifi->pause_auto_connect;
|
||||||
|
|
||||||
if (!is_radio_in_scannable_state) {
|
if (!is_radio_in_scannable_state) {
|
||||||
|
TT_LOG_W(TAG, "Auto-connect: radio state not ok (%d, %d, %d)", (int)wifi->getRadioState(), wifi->isScanActive(), wifi->pause_auto_connect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -851,15 +861,19 @@ static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
|||||||
bool scan_time_has_looped = (current_time < wifi->last_scan_time);
|
bool scan_time_has_looped = (current_time < wifi->last_scan_time);
|
||||||
bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);
|
bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
if (!scan_time_has_looped && !no_recent_scan) {
|
||||||
|
TT_LOG_W(TAG, "Auto-connect: scan time looped = %d, no recent scan = %d", scan_time_has_looped, no_recent_scan);
|
||||||
|
}
|
||||||
|
|
||||||
return scan_time_has_looped || no_recent_scan;
|
return scan_time_has_looped || no_recent_scan;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAutoConnectTimer(std::shared_ptr<void> context) {
|
void onAutoConnectTimer() {
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(wifi_singleton);
|
auto wifi = std::static_pointer_cast<Wifi>(wifi_singleton);
|
||||||
// Automatic scanning is done so we can automatically connect to access points
|
// Automatic scanning is done so we can automatically connect to access points
|
||||||
bool should_auto_scan = shouldScanForAutoConnect(wifi);
|
bool should_auto_scan = shouldScanForAutoConnect(wifi);
|
||||||
if (should_auto_scan) {
|
if (should_auto_scan) {
|
||||||
getMainDispatcher().dispatch(dispatchScan, wifi);
|
getMainDispatcher().dispatch([wifi]() { dispatchScan(wifi); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,13 +885,13 @@ public:
|
|||||||
assert(wifi_singleton == nullptr);
|
assert(wifi_singleton == nullptr);
|
||||||
wifi_singleton = std::make_shared<Wifi>();
|
wifi_singleton = std::make_shared<Wifi>();
|
||||||
|
|
||||||
wifi_singleton->autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, onAutoConnectTimer, wifi_singleton);
|
wifi_singleton->autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, []() { onAutoConnectTimer(); });
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
wifi_singleton->autoConnectTimer->start(std::min(2000, AUTO_SCAN_INTERVAL));
|
wifi_singleton->autoConnectTimer->start(std::min(2000, AUTO_SCAN_INTERVAL));
|
||||||
|
|
||||||
if (settings::shouldEnableOnBoot()) {
|
if (settings::shouldEnableOnBoot()) {
|
||||||
TT_LOG_I(TAG, "Auto-enabling due to setting");
|
TT_LOG_I(TAG, "Auto-enabling due to setting");
|
||||||
getMainDispatcher().dispatch(dispatchEnable, wifi_singleton);
|
getMainDispatcher().dispatch([]() { dispatchEnable(wifi_singleton); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ void setTimeZone(const std::string& name, const std::string& code) {
|
|||||||
setenv("TZ", code.c_str(), 1);
|
setenv("TZ", code.c_str(), 1);
|
||||||
tzset();
|
tzset();
|
||||||
|
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
kernel::publishSystemEvent(kernel::SystemEvent::Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getTimeZoneName() {
|
std::string getTimeZoneName() {
|
||||||
@ -65,7 +65,7 @@ bool isTimeFormat24Hour() {
|
|||||||
void setTimeFormat24Hour(bool show24Hour) {
|
void setTimeFormat24Hour(bool show24Hour) {
|
||||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||||
preferences.putBool(TIMEZONE_PREFERENCES_KEY_TIME24, show24Hour);
|
preferences.putBool(TIMEZONE_PREFERENCES_KEY_TIME24, show24Hour);
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
kernel::publishSystemEvent(kernel::SystemEvent::Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -79,7 +79,7 @@ void init() {}
|
|||||||
void setTimeZone(const std::string& name, const std::string& code) {
|
void setTimeZone(const std::string& name, const std::string& code) {
|
||||||
timeZoneName = name;
|
timeZoneName = name;
|
||||||
timeZoneCode = code;
|
timeZoneCode = code;
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
kernel::publishSystemEvent(kernel::SystemEvent::Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getTimeZoneName() {
|
std::string getTimeZoneName() {
|
||||||
@ -96,7 +96,7 @@ bool isTimeFormat24Hour() {
|
|||||||
|
|
||||||
void setTimeFormat24Hour(bool enabled) {
|
void setTimeFormat24Hour(bool enabled) {
|
||||||
show24Hour = enabled;
|
show24Hour = enabled;
|
||||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
kernel::publishSystemEvent(kernel::SystemEvent::Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -3,23 +3,14 @@
|
|||||||
|
|
||||||
struct TimerWrapper {
|
struct TimerWrapper {
|
||||||
std::unique_ptr<tt::Timer> timer;
|
std::unique_ptr<tt::Timer> timer;
|
||||||
TimerCallback callback;
|
|
||||||
void* _Nullable callbackContext;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
|
||||||
static void callbackWrapper(std::shared_ptr<void> wrapper) {
|
|
||||||
auto timer_wrapper = (TimerWrapper*)wrapper.get();
|
|
||||||
timer_wrapper->callback(timer_wrapper->callbackContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimerHandle tt_timer_alloc(TimerType type, TimerCallback callback, void* callbackContext) {
|
TimerHandle tt_timer_alloc(TimerType type, TimerCallback callback, void* callbackContext) {
|
||||||
auto wrapper = std::make_shared<TimerWrapper>();
|
auto wrapper = std::make_shared<TimerWrapper>();
|
||||||
wrapper->callback = callback;
|
wrapper->timer = std::make_unique<tt::Timer>((tt::Timer::Type)type, [callback, callbackContext](){ callback(callbackContext); });
|
||||||
wrapper->callbackContext = callbackContext;
|
|
||||||
wrapper->timer = std::make_unique<tt::Timer>((tt::Timer::Type)type, callbackWrapper, wrapper);
|
|
||||||
return wrapper.get();
|
return wrapper.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,23 +22,12 @@ namespace tt {
|
|||||||
class Dispatcher {
|
class Dispatcher {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef void (*Function)(std::shared_ptr<void> data);
|
typedef std::function<void()> Function;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct DispatcherMessage {
|
|
||||||
Function function;
|
|
||||||
std::shared_ptr<void> context; // Can't use unique_ptr with void, so we use shared_ptr
|
|
||||||
|
|
||||||
DispatcherMessage(Function function, std::shared_ptr<void> context) :
|
|
||||||
function(function),
|
|
||||||
context(std::move(context))
|
|
||||||
{}
|
|
||||||
|
|
||||||
~DispatcherMessage() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
std::queue<std::shared_ptr<DispatcherMessage>> queue = {};
|
std::queue<Function> queue = {};
|
||||||
EventFlag eventFlag;
|
EventFlag eventFlag;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -49,9 +38,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Queue a function to be consumed elsewhere.
|
* Queue a function to be consumed elsewhere.
|
||||||
* @param[in] function the function to execute elsewhere
|
* @param[in] function the function to execute elsewhere
|
||||||
* @param[in] context the data to pass onto the function
|
|
||||||
*/
|
*/
|
||||||
void dispatch(Function function, std::shared_ptr<void> context, TickType_t timeout = portMAX_DELAY);
|
void dispatch(Function function, TickType_t timeout = portMAX_DELAY);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume 1 or more dispatched function (if any) until the queue is empty.
|
* Consume 1 or more dispatched function (if any) until the queue is empty.
|
||||||
|
|||||||
@ -11,6 +11,8 @@ class DispatcherThread {
|
|||||||
std::unique_ptr<Thread> thread;
|
std::unique_ptr<Thread> thread;
|
||||||
bool interruptThread = false;
|
bool interruptThread = false;
|
||||||
|
|
||||||
|
int32_t threadMain();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit DispatcherThread(const std::string& threadName, size_t threadStackSize = 4096);
|
explicit DispatcherThread(const std::string& threadName, size_t threadStackSize = 4096);
|
||||||
@ -19,16 +21,13 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Dispatch a message.
|
* Dispatch a message.
|
||||||
*/
|
*/
|
||||||
void dispatch(Dispatcher::Function function, std::shared_ptr<void> context, TickType_t timeout = portMAX_DELAY);
|
void dispatch(Dispatcher::Function function, TickType_t timeout = portMAX_DELAY);
|
||||||
|
|
||||||
/** Start the thread (blocking). */
|
/** Start the thread (blocking). */
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
/** Stop the thread (blocking). */
|
/** Stop the thread (blocking). */
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
/** Internal method */
|
|
||||||
void _threadMain();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreDefines.h"
|
#include "CoreDefines.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "RtosCompatTask.h"
|
#include "RtosCompatTask.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
typedef TaskHandle_t ThreadId;
|
typedef TaskHandle_t ThreadId;
|
||||||
@ -38,6 +38,7 @@ public:
|
|||||||
* @warning never use osThreadExit in Thread
|
* @warning never use osThreadExit in Thread
|
||||||
*/
|
*/
|
||||||
typedef int32_t (*Callback)(void* context);
|
typedef int32_t (*Callback)(void* context);
|
||||||
|
typedef std::function<int32_t()> MainFunction;
|
||||||
|
|
||||||
/** Write to stdout callback
|
/** Write to stdout callback
|
||||||
* @param[in] data pointer to data
|
* @param[in] data pointer to data
|
||||||
@ -57,8 +58,7 @@ private:
|
|||||||
|
|
||||||
TaskHandle_t taskHandle = nullptr;
|
TaskHandle_t taskHandle = nullptr;
|
||||||
State state = State::Stopped;
|
State state = State::Stopped;
|
||||||
Callback callback = nullptr;
|
MainFunction mainFunction;
|
||||||
void* callbackContext = nullptr;
|
|
||||||
int32_t callbackResult = 0;
|
int32_t callbackResult = 0;
|
||||||
StateCallback stateCallback = nullptr;
|
StateCallback stateCallback = nullptr;
|
||||||
void* stateCallbackContext = nullptr;
|
void* stateCallbackContext = nullptr;
|
||||||
@ -80,6 +80,7 @@ public:
|
|||||||
* @param[in] callbackContext
|
* @param[in] callbackContext
|
||||||
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
|
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
|
||||||
*/
|
*/
|
||||||
|
[[deprecated("Use constructor variant with std::function")]]
|
||||||
Thread(
|
Thread(
|
||||||
std::string name,
|
std::string name,
|
||||||
configSTACK_DEPTH_TYPE stackSize,
|
configSTACK_DEPTH_TYPE stackSize,
|
||||||
@ -88,6 +89,19 @@ public:
|
|||||||
portBASE_TYPE affinity = -1
|
portBASE_TYPE affinity = -1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** Allocate Thread, shortcut version
|
||||||
|
* @param[in] name the name of the thread
|
||||||
|
* @param[in] stackSize in bytes
|
||||||
|
* @param[in] function
|
||||||
|
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
|
||||||
|
*/
|
||||||
|
Thread(
|
||||||
|
std::string name,
|
||||||
|
configSTACK_DEPTH_TYPE stackSize,
|
||||||
|
MainFunction function,
|
||||||
|
portBASE_TYPE affinity = -1
|
||||||
|
);
|
||||||
|
|
||||||
~Thread();
|
~Thread();
|
||||||
|
|
||||||
/** Set Thread name
|
/** Set Thread name
|
||||||
@ -104,8 +118,14 @@ public:
|
|||||||
* @param[in] callback ThreadCallback, called upon thread run
|
* @param[in] callback ThreadCallback, called upon thread run
|
||||||
* @param[in] callbackContext what to pass to the callback
|
* @param[in] callbackContext what to pass to the callback
|
||||||
*/
|
*/
|
||||||
|
[[deprecated("use setMainFunction()")]]
|
||||||
void setCallback(Callback callback, _Nullable void* callbackContext = nullptr);
|
void setCallback(Callback callback, _Nullable void* callbackContext = nullptr);
|
||||||
|
|
||||||
|
/** Set Thread callback
|
||||||
|
* @param[in] function called upon thread run
|
||||||
|
*/
|
||||||
|
void setMainFunction(MainFunction function);
|
||||||
|
|
||||||
/** Set Thread priority
|
/** Set Thread priority
|
||||||
* @param[in] priority ThreadPriority value
|
* @param[in] priority ThreadPriority value
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
#include "RtosCompatTimers.h"
|
#include "RtosCompatTimers.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
@ -10,7 +12,8 @@ class Timer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef void (*Callback)(std::shared_ptr<void> context);
|
typedef std::function<void()> Callback;
|
||||||
|
// typedef std::function<void(uint32_t)> PendingCallback;
|
||||||
typedef void (*PendingCallback)(void* context, uint32_t arg);
|
typedef void (*PendingCallback)(void* context, uint32_t arg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -22,7 +25,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Callback callback;
|
Callback callback;
|
||||||
std::shared_ptr<void> callbackContext;
|
|
||||||
std::unique_ptr<std::remove_pointer_t<TimerHandle_t>, TimerHandleDeleter> handle;
|
std::unique_ptr<std::remove_pointer_t<TimerHandle_t>, TimerHandleDeleter> handle;
|
||||||
|
|
||||||
static void onCallback(TimerHandle_t hTimer);
|
static void onCallback(TimerHandle_t hTimer);
|
||||||
@ -42,9 +44,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @param[in] type The timer type
|
* @param[in] type The timer type
|
||||||
* @param[in] callback The callback function
|
* @param[in] callback The callback function
|
||||||
* @param callbackContext The callback context
|
|
||||||
*/
|
*/
|
||||||
Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext = nullptr);
|
Timer(Type type, Callback callback);
|
||||||
|
|
||||||
~Timer();
|
~Timer();
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,10 @@ Dispatcher::~Dispatcher() {
|
|||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispatcher::dispatch(Function function, std::shared_ptr<void> context, TickType_t timeout) {
|
void Dispatcher::dispatch(Function function, TickType_t timeout) {
|
||||||
auto message = std::make_shared<DispatcherMessage>(function, std::move(context));
|
|
||||||
// Mutate
|
// Mutate
|
||||||
if (mutex.lock(timeout)) {
|
if (mutex.lock(timeout)) {
|
||||||
queue.push(std::move(message));
|
queue.push(std::move(function));
|
||||||
if (queue.size() == BACKPRESSURE_WARNING_COUNT) {
|
if (queue.size() == BACKPRESSURE_WARNING_COUNT) {
|
||||||
TT_LOG_W(TAG, "Backpressure: You're not consuming fast enough (100 queued)");
|
TT_LOG_W(TAG, "Backpressure: You're not consuming fast enough (100 queued)");
|
||||||
}
|
}
|
||||||
@ -46,13 +45,13 @@ uint32_t Dispatcher::consume(TickType_t timeout) {
|
|||||||
do {
|
do {
|
||||||
if (mutex.lock(10)) {
|
if (mutex.lock(10)) {
|
||||||
if (!queue.empty()) {
|
if (!queue.empty()) {
|
||||||
auto item = queue.front();
|
auto function = queue.front();
|
||||||
queue.pop();
|
queue.pop();
|
||||||
consumed++;
|
consumed++;
|
||||||
processing = !queue.empty();
|
processing = !queue.empty();
|
||||||
// Don't keep lock as callback might be slow
|
// Don't keep lock as callback might be slow
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
item->function(item->context);
|
function();
|
||||||
} else {
|
} else {
|
||||||
processing = false;
|
processing = false;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
|||||||
@ -2,18 +2,13 @@
|
|||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
int32_t dispatcherThreadMain(void* context) {
|
|
||||||
auto* dispatcherThread = (DispatcherThread*)context;
|
|
||||||
dispatcherThread->_threadMain();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DispatcherThread::DispatcherThread(const std::string& threadName, size_t threadStackSize) {
|
DispatcherThread::DispatcherThread(const std::string& threadName, size_t threadStackSize) {
|
||||||
thread = std::make_unique<Thread>(
|
thread = std::make_unique<Thread>(
|
||||||
threadName,
|
threadName,
|
||||||
threadStackSize,
|
threadStackSize,
|
||||||
dispatcherThreadMain,
|
[this]() {
|
||||||
this
|
return threadMain();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +18,7 @@ DispatcherThread::~DispatcherThread() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatcherThread::_threadMain() {
|
int32_t DispatcherThread::threadMain() {
|
||||||
do {
|
do {
|
||||||
/**
|
/**
|
||||||
* If this value is too high (e.g. 1 second) then the dispatcher destroys too slowly when the simulator exits.
|
* If this value is too high (e.g. 1 second) then the dispatcher destroys too slowly when the simulator exits.
|
||||||
@ -31,10 +26,12 @@ void DispatcherThread::_threadMain() {
|
|||||||
*/
|
*/
|
||||||
dispatcher.consume(100 / portTICK_PERIOD_MS);
|
dispatcher.consume(100 / portTICK_PERIOD_MS);
|
||||||
} while (!interruptThread);
|
} while (!interruptThread);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatcherThread::dispatch(Dispatcher::Function function, std::shared_ptr<void> context, TickType_t timeout) {
|
void DispatcherThread::dispatch(Dispatcher::Function function, TickType_t timeout) {
|
||||||
dispatcher.dispatch(function, std::move(context), timeout);
|
dispatcher.dispatch(function, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatcherThread::start() {
|
void DispatcherThread::start() {
|
||||||
|
|||||||
@ -53,7 +53,7 @@ void Thread::mainBody(void* context) {
|
|||||||
TT_LOG_I(TAG, "Starting %s", thread->name.c_str());
|
TT_LOG_I(TAG, "Starting %s", thread->name.c_str());
|
||||||
assert(thread->state == Thread::State::Starting);
|
assert(thread->state == Thread::State::Starting);
|
||||||
thread->setState(Thread::State::Running);
|
thread->setState(Thread::State::Running);
|
||||||
thread->callbackResult = thread->callback(thread->callbackContext);
|
thread->callbackResult = thread->mainFunction();
|
||||||
assert(thread->state == Thread::State::Running);
|
assert(thread->state == Thread::State::Running);
|
||||||
|
|
||||||
thread->setState(Thread::State::Stopped);
|
thread->setState(Thread::State::Stopped);
|
||||||
@ -73,8 +73,21 @@ Thread::Thread(
|
|||||||
_Nullable void* callbackContext,
|
_Nullable void* callbackContext,
|
||||||
portBASE_TYPE affinity
|
portBASE_TYPE affinity
|
||||||
) :
|
) :
|
||||||
callback(callback),
|
mainFunction([callback, callbackContext]() {
|
||||||
callbackContext(callbackContext),
|
return callback(callbackContext);
|
||||||
|
}),
|
||||||
|
name(std::move(name)),
|
||||||
|
stackSize(stackSize),
|
||||||
|
affinity(affinity)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Thread::Thread(
|
||||||
|
std::string name,
|
||||||
|
configSTACK_DEPTH_TYPE stackSize,
|
||||||
|
MainFunction function,
|
||||||
|
portBASE_TYPE affinity
|
||||||
|
) :
|
||||||
|
mainFunction(function),
|
||||||
name(std::move(name)),
|
name(std::move(name)),
|
||||||
stackSize(stackSize),
|
stackSize(stackSize),
|
||||||
affinity(affinity)
|
affinity(affinity)
|
||||||
@ -97,12 +110,17 @@ void Thread::setStackSize(size_t newStackSize) {
|
|||||||
stackSize = newStackSize;
|
stackSize = newStackSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setCallback(Callback newCallback, _Nullable void* newCallbackContext) {
|
void Thread::setCallback(Callback callback, _Nullable void* callbackContext) {
|
||||||
assert(state == State::Stopped);
|
assert(state == State::Stopped);
|
||||||
callback = newCallback;
|
mainFunction = [callback, callbackContext]() {
|
||||||
callbackContext = newCallbackContext;
|
return callback(callbackContext);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Thread::setMainFunction(MainFunction function) {
|
||||||
|
assert(state == State::Stopped);
|
||||||
|
mainFunction = function;
|
||||||
|
}
|
||||||
|
|
||||||
void Thread::setPriority(Priority newPriority) {
|
void Thread::setPriority(Priority newPriority) {
|
||||||
assert(state == State::Stopped);
|
assert(state == State::Stopped);
|
||||||
@ -121,7 +139,7 @@ Thread::State Thread::getState() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Thread::start() {
|
void Thread::start() {
|
||||||
assert(callback);
|
assert(mainFunction);
|
||||||
assert(state == State::Stopped);
|
assert(state == State::Stopped);
|
||||||
assert(stackSize > 0U && stackSize < (UINT16_MAX * sizeof(StackType_t)));
|
assert(stackSize > 0U && stackSize < (UINT16_MAX * sizeof(StackType_t)));
|
||||||
|
|
||||||
|
|||||||
@ -4,15 +4,12 @@
|
|||||||
#include "Tactility/RtosCompat.h"
|
#include "Tactility/RtosCompat.h"
|
||||||
#include "Tactility/kernel/Kernel.h"
|
#include "Tactility/kernel/Kernel.h"
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
void Timer::onCallback(TimerHandle_t hTimer) {
|
void Timer::onCallback(TimerHandle_t hTimer) {
|
||||||
auto* timer = static_cast<Timer*>(pvTimerGetTimerID(hTimer));
|
auto* timer = static_cast<Timer*>(pvTimerGetTimerID(hTimer));
|
||||||
|
|
||||||
if (timer != nullptr) {
|
if (timer != nullptr) {
|
||||||
timer->callback(timer->callbackContext);
|
timer->callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,9 +27,8 @@ static inline TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCa
|
|||||||
return xTimerCreate(nullptr, portMAX_DELAY, (BaseType_t)reload, timerId, callback);
|
return xTimerCreate(nullptr, portMAX_DELAY, (BaseType_t)reload, timerId, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext) :
|
Timer::Timer(Type type, Callback callback) :
|
||||||
callback(callback),
|
callback(callback),
|
||||||
callbackContext(std::move(callbackContext)),
|
|
||||||
handle(createTimer(type, this, onCallback))
|
handle(createTimer(type, this, onCallback))
|
||||||
{
|
{
|
||||||
assert(!kernel::isIsr());
|
assert(!kernel::isIsr());
|
||||||
|
|||||||
@ -4,26 +4,10 @@
|
|||||||
|
|
||||||
using namespace tt;
|
using namespace tt;
|
||||||
|
|
||||||
static uint32_t counter = 0;
|
|
||||||
static const uint32_t value_chacker_expected = 123;
|
|
||||||
|
|
||||||
void increment_callback(TT_UNUSED std::shared_ptr<void> context) {
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void value_checker(std::shared_ptr<void> context) {
|
|
||||||
auto value = std::static_pointer_cast<uint32_t>(context);
|
|
||||||
if (*value != value_chacker_expected) {
|
|
||||||
tt_crash("Test error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("dispatcher should not call callback if consume isn't called") {
|
TEST_CASE("dispatcher should not call callback if consume isn't called") {
|
||||||
counter = 0;
|
int counter = 0;
|
||||||
Dispatcher dispatcher;
|
Dispatcher dispatcher;
|
||||||
|
dispatcher.dispatch([&counter]() { counter++; });
|
||||||
auto context = std::make_shared<uint32_t>();
|
|
||||||
dispatcher.dispatch(&increment_callback, std::move(context));
|
|
||||||
kernel::delayTicks(10);
|
kernel::delayTicks(10);
|
||||||
|
|
||||||
CHECK_EQ(counter, 0);
|
CHECK_EQ(counter, 0);
|
||||||
@ -32,24 +16,23 @@ TEST_CASE("dispatcher should not call callback if consume isn't called") {
|
|||||||
TEST_CASE("dispatcher should be able to dealloc when message is not consumed") {
|
TEST_CASE("dispatcher should be able to dealloc when message is not consumed") {
|
||||||
auto* dispatcher = new Dispatcher();
|
auto* dispatcher = new Dispatcher();
|
||||||
auto context = std::make_shared<uint32_t>();
|
auto context = std::make_shared<uint32_t>();
|
||||||
dispatcher->dispatch(increment_callback, std::move(context));
|
dispatcher->dispatch([]() { /* NO-OP */ });
|
||||||
delete dispatcher;
|
delete dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("dispatcher should call callback when consume is called") {
|
TEST_CASE("dispatcher should call callback when consume is called") {
|
||||||
counter = 0;
|
int counter = 0;
|
||||||
Dispatcher dispatcher;
|
Dispatcher dispatcher;
|
||||||
|
|
||||||
auto context = std::make_shared<uint32_t>();
|
dispatcher.dispatch([&counter]() { counter++; });
|
||||||
dispatcher.dispatch(increment_callback, std::move(context));
|
|
||||||
dispatcher.consume(100);
|
dispatcher.consume(100);
|
||||||
|
|
||||||
CHECK_EQ(counter, 1);
|
CHECK_EQ(counter, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("message should be passed on correctly") {
|
TEST_CASE("message should be passed on correctly") {
|
||||||
Dispatcher dispatcher;
|
Dispatcher dispatcher;
|
||||||
|
|
||||||
auto context = std::make_shared<uint32_t>(value_chacker_expected);
|
dispatcher.dispatch([]() { /* NO-OP */ });
|
||||||
dispatcher.dispatch(value_checker, std::move(context));
|
|
||||||
dispatcher.consume(100);
|
dispatcher.consume(100);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,34 +2,11 @@
|
|||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
using namespace tt;
|
using namespace tt;
|
||||||
|
|
||||||
std::shared_ptr<void> timer_callback_context = NULL;
|
|
||||||
static void timer_callback_with_context(std::shared_ptr<void> context) {
|
|
||||||
timer_callback_context = std::move(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_callback_with_counter(std::shared_ptr<void> context) {
|
|
||||||
auto int_ptr = std::static_pointer_cast<int>(context);
|
|
||||||
(*int_ptr)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("a timer passes the context correctly") {
|
|
||||||
auto foo = std::make_shared<int>(1);
|
|
||||||
auto* timer = new Timer(Timer::Type::Once, &timer_callback_with_context, foo);
|
|
||||||
timer->start(1);
|
|
||||||
kernel::delayTicks(10);
|
|
||||||
timer->stop();
|
|
||||||
delete timer;
|
|
||||||
|
|
||||||
CHECK_EQ(*std::static_pointer_cast<int>(timer_callback_context), *foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("TimerType::Periodic timers can be stopped and restarted") {
|
TEST_CASE("TimerType::Periodic timers can be stopped and restarted") {
|
||||||
auto counter = std::make_shared<int>(0);
|
int counter = 0;
|
||||||
auto* timer = new Timer(Timer::Type::Periodic, &timer_callback_with_counter, counter);
|
auto* timer = new Timer(Timer::Type::Periodic, [&counter]() { counter++; });
|
||||||
timer->start(1);
|
timer->start(1);
|
||||||
kernel::delayTicks(10);
|
kernel::delayTicks(10);
|
||||||
timer->stop();
|
timer->stop();
|
||||||
@ -38,24 +15,24 @@ TEST_CASE("TimerType::Periodic timers can be stopped and restarted") {
|
|||||||
timer->stop();
|
timer->stop();
|
||||||
delete timer;
|
delete timer;
|
||||||
|
|
||||||
CHECK_GE(*counter, 2);
|
CHECK_GE(counter, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("TimerType::Periodic calls the callback periodically") {
|
TEST_CASE("TimerType::Periodic calls the callback periodically") {
|
||||||
auto counter = std::make_shared<int>(0);
|
|
||||||
int ticks_to_run = 10;
|
int ticks_to_run = 10;
|
||||||
auto* timer = new Timer(Timer::Type::Periodic, &timer_callback_with_counter, counter);
|
int counter = 0;
|
||||||
|
auto* timer = new Timer(Timer::Type::Periodic, [&counter]() { counter++; });
|
||||||
timer->start(1);
|
timer->start(1);
|
||||||
kernel::delayTicks(ticks_to_run);
|
kernel::delayTicks(ticks_to_run);
|
||||||
timer->stop();
|
timer->stop();
|
||||||
delete timer;
|
delete timer;
|
||||||
|
|
||||||
CHECK_EQ(*counter, ticks_to_run);
|
CHECK_EQ(counter, ticks_to_run);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("restarting TimerType::Once timers calls the callback again") {
|
TEST_CASE("restarting TimerType::Once timers calls the callback again") {
|
||||||
auto counter = std::make_shared<int>(0);
|
int counter = 0;
|
||||||
auto* timer = new Timer(Timer::Type::Once, &timer_callback_with_counter, counter);
|
auto* timer = new Timer(Timer::Type::Once, [&counter]() { counter++; });
|
||||||
timer->start(1);
|
timer->start(1);
|
||||||
kernel::delayTicks(10);
|
kernel::delayTicks(10);
|
||||||
timer->stop();
|
timer->stop();
|
||||||
@ -64,5 +41,5 @@ TEST_CASE("restarting TimerType::Once timers calls the callback again") {
|
|||||||
timer->stop();
|
timer->stop();
|
||||||
delete timer;
|
delete timer;
|
||||||
|
|
||||||
CHECK_EQ(*counter, 2);
|
CHECK_EQ(counter, 2);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user