diff --git a/.gdbinit-1051 b/.gdbinit-1051 index 682d58d73..66d12498b 100644 --- a/.gdbinit-1051 +++ b/.gdbinit-1051 @@ -1,4 +1,5 @@ target remote localhost:2331 +source tools/gdb_crash_extend.py monitor reset 0 monitor halt monitor memU32 0x401BC000 = 128; diff --git a/CMakeLists.txt b/CMakeLists.txt index 660cfdaeb..ef0fc3a73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ add_compile_options( ${TARGET_COMPILE_OPTIONS} -MMD -MP -fno-builtin + -fno-diagnostics-color # warning flags -Wall -Wextra -Werror -Wno-unused-parameter) diff --git a/changelog.md b/changelog.md index 00159a5d4..074313754 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,19 @@ # MuditaOS changelog +## [Current release] + +### Added + +* `[gui]` Added GUI timers capability + +### Changed +* `[system]` Timer API - linked to timer, same for Services and Applications. Updated docs +* `[system]` Removed `using std` and `using cpp_freertos` from commonly used headers + +### Fixed + +* `[system]` Timers race condition, Timers should be thread safe for Services/Applications + ## [0.40.1 2020-10-02] ### Added diff --git a/flash_eMMC.sh b/flash_eMMC.sh index c7f98ada1..561b47e5c 100755 --- a/flash_eMMC.sh +++ b/flash_eMMC.sh @@ -44,7 +44,7 @@ mkdir -p $PURE_PATH_ROOT/$PURE_OS_FACTORY # sudo sync $PURE_DEV echo "PurePhone copy build files" -cp -v $BUILD_PATH/boot.bin "$PURE_PATH_CURRENT"/ # | sed 's/'-\>'/'→'/g' +# cp -v $BUILD_PATH/boot.bin "$PURE_PATH_CURRENT"/ # | sed 's/'-\>'/'→'/g' for file in $IMAGE_FILES; do echo Copying $file diff --git a/module-apps/Application.cpp b/module-apps/Application.cpp index b5fe6a9df..9b559e41f 100644 --- a/module-apps/Application.cpp +++ b/module-apps/Application.cpp @@ -1,29 +1,37 @@ -#include -#include -// module-utils -#include "log/log.hpp" -// module-services -#include "service-gui/messages/DrawMessage.hpp" -#include "service-appmgr/messages/APMMessage.hpp" -#include "service-evtmgr/messages/EVMessages.hpp" -#include "service-appmgr/ApplicationManager.hpp" -#include "service-db/api/DBServiceAPI.hpp" -#include "service-cellular/ServiceCellular.hpp" -#include "service-cellular/api/CellularServiceAPI.hpp" -// module-gui -#include "gui/core/DrawCommand.hpp" -#include "gui/input/InputEvent.hpp" -// module-sys -#include "SystemManager/SystemManager.hpp" - #include "Application.hpp" -#include "MessageType.hpp" -#include "messages/AppMessage.hpp" -#include "windows/AppWindow.hpp" -#include -#include +#include "BusChannelsCustom.hpp" // for BusChannels... +#include "Common.hpp" // for RefreshModes +#include "GuiTimer.hpp" // for GuiTimer +#include "Item.hpp" // for Item +#include "MessageType.hpp" // for MessageType +#include "Service/Timer.hpp" // for Timer +#include "SettingsRecord.hpp" // for SettingsRecord +#include "Timer.hpp" // for Timer +#include "Translator.hpp" // for KeyInputSim... +#include "common_data/EventStore.hpp" // for Battery +#include "common_data/RawKey.hpp" // for RawKey, key... +#include "gui/input/InputEvent.hpp" // for InputEvent +#include "log/debug.hpp" // for DEBUG_APPLI... +#include "log/log.hpp" // for LOG_INFO +#include "messages/AppMessage.hpp" // for AppSwitchMe... +#include "service-appmgr/ApplicationManager.hpp" // for Application... +#include "service-cellular/messages/CellularMessage.hpp" // for CellularNot... +#include "service-db/api/DBServiceAPI.hpp" // for DBServiceAPI +#include "service-evtmgr/messages/BatteryMessages.hpp" // for BatteryLeve... +#include "service-evtmgr/messages/EVMessages.hpp" // for RtcMinuteAl... +#include "service-evtmgr/messages/KbdMessage.hpp" // for KbdMessage +#include "service-gui/messages/DrawMessage.hpp" // for DrawMessage +#include "task.h" // for xTaskGetTic... +#include "windows/AppWindow.hpp" // for AppWindow +#include // for Text +#include // for find +#include // for distance, next +#include // for add_const<>... -#include "common_data/EventStore.hpp" +namespace gui +{ + class DrawCommand; +} namespace app::audioConsts { @@ -60,8 +68,6 @@ namespace app Application::Application( std::string name, std::string parent, bool startBackground, uint32_t stackDepth, sys::ServicePriority priority) : Service(name, parent, stackDepth, priority), - longPressTimer(CreateAppTimer( - key_timer_ms, true, [&]() { longPressTimerCallback(); }, "longPressTimer")), startBackground{startBackground} { keyTranslator = std::make_unique(); @@ -69,7 +75,9 @@ namespace app if (startBackground) { setState(State::ACTIVE_BACKGROUND); } - longPressTimer.restart(); + + longPressTimer = std::make_unique("LongPress", this, key_timer_ms); + longPressTimer->connect([&](sys::Timer &) { longPressTimerCallback(); }); } Application::~Application() @@ -93,34 +101,6 @@ namespace app state = st; } - void Application::TickHandler(uint32_t id) - { - auto appTimer = std::find(appTimers.begin(), appTimers.end(), id); - if (appTimer != appTimers.end()) { - appTimer->runCallback(); - } - else { - LOG_ERROR("Requested timer doesn't exist here (ID: %s)\n", - std::to_string(id).c_str()); // either timer was deleted or this id should not arrive. - } - } - - void Application::DeleteTimer(AppTimer &timer) - { - Service::DeleteTimer(timer.getID()); // remove the real FreeRTOS timer - auto timerOnTheList = std::find(appTimers.begin(), appTimers.end(), timer); - if (timerOnTheList != appTimers.end()) { - appTimers.erase(timerOnTheList); - } - } - - [[deprecated("only for compatibility")]] void Application::DeleteTimer(uint32_t id) - { - auto found = std::find(appTimers.begin(), appTimers.end(), id); - if (found != appTimers.end()) { - DeleteTimer(*found); - } - } void Application::longPressTimerCallback() { @@ -132,6 +112,7 @@ namespace app messageInputEventApplication(this, this->GetName(), iev); // clean previous key keyTranslator->prev_key_press = {}; + longPressTimer->stop(); } } @@ -281,6 +262,12 @@ namespace app sys::Message_t Application::handleInputEvent(sys::DataMessage *msgl) { AppInputEventMessage *msg = reinterpret_cast(msgl); + if (msg->getEvent().state == gui::InputEvent::State::keyPressed) { + longPressTimer->start(); + } + else if (msg->getEvent().state == gui::InputEvent::State::keyReleasedShort) { + longPressTimer->stop(); + } if (getCurrentWindow() != nullptr && getCurrentWindow()->onInput(msg->getEvent())) { refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST); } @@ -341,7 +328,7 @@ namespace app sys::Message_t Application::handleApplicationSwitch(sys::DataMessage *msgl) { - AppSwitchMessage *msg = reinterpret_cast(msgl); + auto *msg = static_cast(msgl); bool handled = false; LOG_DEBUG("AppSwitch: %s", msg->getTargetApplicationName().c_str()); // Application is starting or it is in the background. Upon switch command if name if correct it goes @@ -647,65 +634,14 @@ namespace app return getWindow(window); } - AppTimer Application::CreateAppTimer(TickType_t interval, - bool isPeriodic, - std::function callback, - const std::string &name) - { - auto id = CreateTimer(interval, isPeriodic, name); - auto timer = AppTimer(this, id, callback, name); - appTimers.push_back(timer); - return timer; // return ptr to the timer on the list - } - void Application::attachWindow(gui::AppWindow *window) { windows.insert({window->getName(), window}); } - AppTimer::AppTimer(Application *parent, uint32_t id, std::function callback, const std::string &name) - : parent(parent) + void Application::connect(std::unique_ptr &&timer, gui::Item *item) { - this->id = id; - registerCallback(callback); - } - AppTimer::AppTimer() = default; - - AppTimer::~AppTimer() - { - callback = nullptr; - } - - void AppTimer::registerCallback(std::function callback) - { - this->callback = callback; - } - void AppTimer::runCallback() - { - callback(); - } - uint32_t AppTimer::getID() - { - return id; - } - void AppTimer::stop() - { - if (parent) { - parent->stopTimer(getID()); - } - } - void AppTimer::restart() - { - if (parent) { - parent->ReloadTimer(getID()); - } - } - bool AppTimer::operator==(const AppTimer &rhs) const - { - return this->id == rhs.id; - } - bool AppTimer::operator==(const uint32_t &rhs) const - { - return this->id == rhs; + timer->sysapi.connect(item); + item->attachTimer(std::move(timer)); } } /* namespace app */ diff --git a/module-apps/Application.hpp b/module-apps/Application.hpp index 565f9fdea..b01921581 100644 --- a/module-apps/Application.hpp +++ b/module-apps/Application.hpp @@ -1,67 +1,59 @@ -/* - * @file Application.hpp - * @author Robert Borzecki (robert.borzecki@mudita.com) - * @date 1 cze 2019 - * @brief - * @copyright Copyright (C) 2019 mudita.com - * @details - */ -#ifndef MODULE_APPS_APPLICATION_HPP_ -#define MODULE_APPS_APPLICATION_HPP_ +#pragma once -#include -// module-gui -#include "gui/Common.hpp" -//#include "gui/widgets/Window.hpp" -#include "gui/input/Translator.hpp" -// module-sys -#include "Service/Service.hpp" -#include "Service/Message.hpp" -#include "Service/Common.hpp" -#include "SystemManager/SystemManager.hpp" -// module-db -#include "Interface/SettingsRecord.hpp" - -#include -#include -#include "service-evtmgr/messages/EVMessages.hpp" - -#include "SwitchData.hpp" -#include "service-cellular/api/CellularServiceAPI.hpp" -#include "windows/AppWindow.hpp" +#include "Audio/AudioCommon.hpp" // for Volume, Play... +#include "Audio/Profiles/Profile.hpp" // for Profile, Pro... +#include "AudioServiceAPI.hpp" // for GetOutputVolume +#include "Interface/SettingsRecord.hpp" // for SettingsRecord +#include "Service/Bus.hpp" // for Bus +#include "Service/Common.hpp" // for ReturnCodes +#include "Service/Message.hpp" // for Message_t +#include "Service/Service.hpp" // for Service +#include "SwitchData.hpp" // for SwitchData +#include "SystemManager/SystemManager.hpp" // for SystemManager +#include "bsp/keyboard/key_codes.hpp" // for bsp +#include "gui/Common.hpp" // for ShowMode +#include "projdefs.h" // for pdMS_TO_TICKS +#include "service-evtmgr/messages/EVMessages.hpp" // for TorchStateMe... +#include // for list +#include // for allocator, map +#include // for make_shared +#include // for State, State... +#include // for evt_manager +#include // for uint32_t +#include // for string +#include // for move, pair +#include // for vector +namespace app +{ + class GuiTimer; +} // namespace app namespace gui { class AppWindow; -}; +} // namespace gui +namespace gui +{ + class InputEvent; +} +namespace gui +{ + class Item; +} +namespace gui +{ + class KeyInputSimpleTranslation; +} +namespace sys +{ + class Timer; +} namespace app { class Application; - - class AppTimer // this should inherit from ServiceTimer, but *bodge* - { - private: - uint32_t id = 0; // let's say 0 indicates not initalized timer - std::function callback = nullptr; - Application *parent = nullptr; - - void registerCallback(std::function); - AppTimer(); - - public: - AppTimer(Application *parent, uint32_t id, std::function callback, const std::string &name); - ~AppTimer(); - void runCallback(); - uint32_t getID(); - static uint32_t getNextUniqueID(); - // timer controls: - void restart(); - void stop(); - bool operator==(const AppTimer &rhs) const; - bool operator==(const uint32_t &rhs) const; - }; + class GuiTimer; inline auto msgHandled() -> sys::Message_t { @@ -129,10 +121,10 @@ namespace app sys::Message_t handleAppRefresh(sys::DataMessage *msgl); sys::Message_t handleSIMMessage(sys::DataMessage *msgl); + std::list> gui_timers; + public: - std::list timerIDs; - std::list appTimers; // @TODO decide on type - AppTimer longPressTimer; + std::unique_ptr longPressTimer; Application(std::string name, std::string parent = "", bool startBackground = false, @@ -143,22 +135,6 @@ namespace app Application::State getState(); void setState(State st); - /// @defgroup AppTimers Application timers - /// @note Please mind that timers are from Service and implementation in service should be revritten to send - /// notify instead of calling callback - /// Right now timers can create races. - /// @{ - /// Method to register callback function to be run on timer. - AppTimer CreateAppTimer(TickType_t interval, - bool isPeriodic, - std::function callback, - const std::string &name = ""); - /// Remove previousy registered AppTimer by object - void DeleteTimer(AppTimer &timer); - /// Remove previousy registered AppTimer by id - void DeleteTimer(uint32_t id); - /// @} - /// Method responsible for rendering currently active window. /// 1. queries for static data for all windows form Store (i.e. battery level, sim card level) /// 2. loads rendering commands and send them to GUI renderer (sgui::ServiceGUI) @@ -194,6 +170,9 @@ namespace app /// Method refreshing active window void refreshWindow(gui::RefreshModes mode); + /// to not hide overload from parent + using Service::DataReceivedHandler; + /// Mehtod to handle bus messages, all message types are defined in Message.hpp /// Message types are in MessageType sys::Message_t DataReceivedHandler(sys::DataMessage *msgl); @@ -313,9 +292,6 @@ namespace app SettingsRecord settings; void longPressTimerCallback(); - /// function executing functions registered by CreateAppTimer - /// @param id - timer identification number - virtual void TickHandler(uint32_t id) override final; /// Method used to register all windows and widgets in application virtual void createUserInterface() = 0; /// Method closing application's windows. @@ -352,6 +328,10 @@ namespace app /// getter for current wisible window in application /// @ingrup AppWindowStack gui::AppWindow *getCurrentWindow(); + /// to avoid conflicts with connect below + using Service::connect; + /// connects item with GuiTimer and stores it in app + void connect(std::unique_ptr &&timer, gui::Item *item); protected: /// Flag defines whether keyboard input should be processed @@ -451,5 +431,3 @@ namespace app } } /* namespace app */ - -#endif /* MODULE_APPS_APPLICATION_HPP_ */ diff --git a/module-apps/CMakeLists.txt b/module-apps/CMakeLists.txt index 50cd6f4d9..6a21a8f2d 100644 --- a/module-apps/CMakeLists.txt +++ b/module-apps/CMakeLists.txt @@ -13,6 +13,7 @@ endif() set( SOURCES "Application.cpp" + "GuiTimer.cpp" "UiCommonActions.cpp" "windows/AppWindow.cpp" "windows/OptionWindow.cpp" diff --git a/module-apps/GuiTimer.cpp b/module-apps/GuiTimer.cpp new file mode 100644 index 000000000..af9657d3c --- /dev/null +++ b/module-apps/GuiTimer.cpp @@ -0,0 +1,46 @@ +#include "GuiTimer.hpp" +#include "Item.hpp" // for Item +#include "Service/Timer.hpp" // for Timer, Timer::Type, Timer::Ty... +#include "module-apps/Application.hpp" // for Application +#include // for allocator + +namespace app +{ + void GuiTimer::start() + { + sys::Timer::start(); + } + + void GuiTimer::stop() + { + sys::Timer::stop(); + } + + void GuiTimer::reset() + { + sys::Timer::start(); + } + + void GuiTimer::setInterval(gui::ms time) + { + sys::Timer::setInterval(time); + } + + GuiTimer::GuiTimer(Application *parent) : GuiTimer("GUI", parent) + {} + + GuiTimer::GuiTimer(const std::string &name, Application *parent) + : GuiTimer(name, parent, sys::Timer::timeout_infinite) + {} + + GuiTimer::GuiTimer(const std::string &name, Application *parent, gui::ms timeout) + : sys::Timer(name, parent, timeout, sys::Timer::Type::SingleShot), sysapi(*this) + {} + + void GuiTimer::Sysapi::connect(gui::Item *item) + { + if (item != nullptr) { + parent.connect([item, this](sys::Timer &timer) { item->onTimer(parent); }); + } + } +} // namespace app diff --git a/module-apps/GuiTimer.hpp b/module-apps/GuiTimer.hpp new file mode 100644 index 000000000..8ab3ec03c --- /dev/null +++ b/module-apps/GuiTimer.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "Service/Timer.hpp" // for Timer +#include "Timer.hpp" // for ms, Timer +#include // for string +namespace app +{ + class Application; +} // namespace app +namespace gui +{ + class Item; +} // namespace gui + +namespace app +{ + + class Application; + + /// proxies system Timer capabilities to gui::Timer and disconnects dependencies + /// by default one time run + class GuiTimer : public gui::Timer, protected sys::Timer + { + public: + /// gui timer default named GUI, infinite timeout on start + GuiTimer(Application *parent); + /// gui timer with user name, infinite timeout on start + GuiTimer(const std::string &name, Application *parent); + /// gui timer with user name, variable timeout + GuiTimer(const std::string &name, Application *parent, gui::ms timeout); + /// there is no valid reason to create timer without app + GuiTimer() = delete; + + /// @defgroup interface + /// @ { + void start() override; + void stop() override; + void reset() override; + void setInterval(gui::ms time) override; + /// @ } + + /// interface to trigger timing callback + class Sysapi + { + friend Application; + GuiTimer &parent; + void connect(gui::Item *item); + + public: + Sysapi(GuiTimer &parent) : parent(parent) + {} + } sysapi; + }; +}; // namespace app diff --git a/module-apps/application-antenna/ApplicationAntenna.cpp b/module-apps/application-antenna/ApplicationAntenna.cpp index e4b1e0c45..3efae5daf 100644 --- a/module-apps/application-antenna/ApplicationAntenna.cpp +++ b/module-apps/application-antenna/ApplicationAntenna.cpp @@ -6,8 +6,9 @@ */ #include "ApplicationAntenna.hpp" -#include "service-cellular/api/CellularServiceAPI.hpp" +#include "Service/Timer.hpp" #include "module-cellular/at/response.hpp" +#include "service-cellular/api/CellularServiceAPI.hpp" #include "windows/AntennaMainWindow.hpp" #include "windows/ScanModesWindow.hpp" @@ -31,13 +32,13 @@ namespace app } ApplicationAntenna::ApplicationAntenna(std::string name, std::string parent, bool startBackgound) - : Application(name, parent, startBackgound, 4096 * 2), - appTimer(CreateAppTimer(2000, true, [=]() { timerHandler(); })) - + : Application(name, parent, startBackgound, 4096 * 2) { busChannels.push_back(sys::BusChannels::AntennaNotifications); busChannels.push_back(sys::BusChannels::AntennaNotifications); - appTimer.restart(); + appTimer = std::make_unique("Antena", this, 2000); + appTimer->connect([=](sys::Timer &) { timerHandler(); }); + appTimer->start(); } ApplicationAntenna::~ApplicationAntenna() diff --git a/module-apps/application-antenna/ApplicationAntenna.hpp b/module-apps/application-antenna/ApplicationAntenna.hpp index de4012bc5..d4ed96c53 100644 --- a/module-apps/application-antenna/ApplicationAntenna.hpp +++ b/module-apps/application-antenna/ApplicationAntenna.hpp @@ -9,6 +9,7 @@ #define MODULE_APPS_APPLICATION_ANTENNA_APPLICATIONANTENNA_HPP_ #include "Application.hpp" +#include "service-cellular/api/CellularServiceAPI.hpp" #include "windows/AppWindow.hpp" namespace app @@ -29,7 +30,7 @@ namespace app class ApplicationAntenna : public app::Application { protected: - AppTimer appTimer; + std::unique_ptr appTimer; void timerHandler(void); bool cellularRequestInProgress = false; bsp::cellular::antenna antenna; diff --git a/module-apps/application-calendar/ApplicationCalendar.cpp b/module-apps/application-calendar/ApplicationCalendar.cpp index 8d398b76e..962942fe7 100644 --- a/module-apps/application-calendar/ApplicationCalendar.cpp +++ b/module-apps/application-calendar/ApplicationCalendar.cpp @@ -16,7 +16,7 @@ namespace app { - const map ApplicationCalendar::reminderOptions = { + const std::map ApplicationCalendar::reminderOptions = { {Reminder::never, "app_calendar_reminder_never"}, {Reminder::event_time, "app_calendar_reminder_event_time"}, {Reminder::five_min_before, "app_calendar_reminder_5_min_before"}, @@ -28,7 +28,7 @@ namespace app {Reminder::two_days_before, "app_calendar_reminder_2_days_before"}, {Reminder::one_week_before, "app_calendar_reminder_1_week_before"}}; - const map ApplicationCalendar::repeatOptions = { + const std::map ApplicationCalendar::repeatOptions = { {Repeat::never, "app_calendar_repeat_never"}, {Repeat::daily, "app_calendar_repeat_daily"}, {Repeat::weekly, "app_calendar_repeat_weekly"}, diff --git a/module-apps/application-calendar/models/NewEditEventModel.cpp b/module-apps/application-calendar/models/NewEditEventModel.cpp index 3bf700181..78c87c279 100644 --- a/module-apps/application-calendar/models/NewEditEventModel.cpp +++ b/module-apps/application-calendar/models/NewEditEventModel.cpp @@ -1,11 +1,12 @@ #include "NewEditEventModel.hpp" +#include "AppWindow.hpp" #include "application-calendar/widgets/NewEventCheckBoxWithLabel.hpp" #include "module-apps/application-calendar/data/CalendarData.hpp" -#include #include -#include +#include #include #include +#include #include