~aleteoryx/muditaos

46f9cc7e100b471afef4efc4449880eb480ac7fa — Lucjan Bryndza 5 years ago af960b6 + 7b52b85
[EGD-5737] Merge master into experimental

Keep experimental up to date with changes from master
258 files changed, 3823 insertions(+), 1704 deletions(-)

M .github/workflows/main.yml
M .github/workflows/releases.yaml
M CMakeLists.txt
A art/phone/application_desktop/menu/dead_battery_W_G.png
M changelog.md
M config/GenUpdateVersionJson.cmake
M doc/development_workflow.md
A doc/static_analysis.md
A image/assets/images/dead_battery_W_G.vpi
M image/assets/lang/English.json
M module-apps/Application.cpp
M module-apps/Application.hpp
M module-apps/CMakeLists.txt
A module-apps/TopBarManager.cpp
A module-apps/TopBarManager.hpp
M module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp
M module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp
M module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp
M module-apps/application-antenna/windows/AlgoParamsWindow.cpp
M module-apps/application-antenna/windows/AntennaMainWindow.cpp
M module-apps/application-antenna/windows/ScanModesWindow.cpp
M module-apps/application-calculator/data/CalculatorUtility.cpp
M module-apps/application-calculator/data/CalculatorUtility.hpp
M module-apps/application-calculator/tests/CalculatorUtility_tests.cpp
M module-apps/application-calculator/widgets/CalculatorStyle.hpp
M module-apps/application-calculator/windows/CalculatorMainWindow.cpp
M module-apps/application-calculator/windows/CalculatorMainWindow.hpp
M module-apps/application-calendar/ApplicationCalendar.cpp
M module-apps/application-calendar/ApplicationCalendar.hpp
M module-apps/application-calendar/data/CalendarData.hpp
M module-apps/application-calendar/data/dateCommon.hpp
M module-apps/application-calendar/models/AllEventsModel.cpp
M module-apps/application-calendar/models/DayEventsModel.cpp
M module-apps/application-calendar/models/DayEventsModel.hpp
M module-apps/application-calendar/widgets/EventDateItem.cpp
M module-apps/application-calendar/widgets/EventDateItem.hpp
M module-apps/application-calendar/widgets/EventTimeItem.cpp
M module-apps/application-calendar/widgets/EventTimeItem.hpp
M module-apps/application-calendar/widgets/MonthBox.cpp
M module-apps/application-calendar/windows/AllEventsWindow.cpp
M module-apps/application-calendar/windows/AllEventsWindow.hpp
M module-apps/application-calendar/windows/CalendarMainWindow.cpp
M module-apps/application-calendar/windows/CustomRepeatWindow.cpp
M module-apps/application-calendar/windows/DayEventsWindow.cpp
M module-apps/application-calendar/windows/DayEventsWindow.hpp
M module-apps/application-calendar/windows/EventDetailWindow.cpp
M module-apps/application-calendar/windows/EventReminderWindow.cpp
M module-apps/application-calendar/windows/EventReminderWindow.hpp
M module-apps/application-calendar/windows/NewEditEventWindow.cpp
M module-apps/application-call/ApplicationCall.cpp
M module-apps/application-call/windows/CallWindow.cpp
M module-apps/application-call/windows/EnterNumberWindow.cpp
M module-apps/application-calllog/windows/CallLogDetailsWindow.cpp
M module-apps/application-calllog/windows/CallLogMainWindow.cpp
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/ApplicationDesktop.hpp
M module-apps/application-desktop/CMakeLists.txt
A module-apps/application-desktop/windows/DeadBatteryWindow.cpp
A module-apps/application-desktop/windows/DeadBatteryWindow.hpp
M module-apps/application-desktop/windows/DesktopMainWindow.cpp
M module-apps/application-desktop/windows/DesktopMainWindow.hpp
M module-apps/application-desktop/windows/LockWindow.cpp
M module-apps/application-desktop/windows/LockWindow.hpp
M module-apps/application-desktop/windows/LockedInfoWindow.cpp
M module-apps/application-desktop/windows/LockedInfoWindow.hpp
M module-apps/application-desktop/windows/MenuWindow.cpp
M module-apps/application-desktop/windows/MmiPullWindow.cpp
M module-apps/application-desktop/windows/MmiPushWindow.cpp
M module-apps/application-desktop/windows/Names.hpp
M module-apps/application-desktop/windows/PinLockBaseWindow.cpp
M module-apps/application-desktop/windows/PinLockBaseWindow.hpp
M module-apps/application-desktop/windows/PowerOffWindow.cpp
M module-apps/application-desktop/windows/PowerOffWindow.hpp
M module-apps/application-meditation/windows/MeditationListViewWindows.cpp
M module-apps/application-meditation/windows/MeditationTimerWindow.cpp
M module-apps/application-messages/windows/MessagesMainWindow.cpp
M module-apps/application-messages/windows/NewMessage.cpp
M module-apps/application-messages/windows/SMSTemplatesWindow.cpp
M module-apps/application-messages/windows/SMSThreadViewWindow.cpp
M module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp
M module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp
M module-apps/application-notes/windows/NoteEditWindow.cpp
M module-apps/application-notes/windows/NoteMainWindow.cpp
M module-apps/application-notes/windows/NotePreviewWindow.cpp
M module-apps/application-phonebook/windows/PhonebookContactDetails.cpp
M module-apps/application-phonebook/windows/PhonebookIceContacts.cpp
M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp
M module-apps/application-phonebook/windows/PhonebookSearch.cpp
M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp
M module-apps/application-settings-new/ApplicationSettings.cpp
M module-apps/application-settings-new/ApplicationSettings.hpp
M module-apps/application-settings-new/CMakeLists.txt
A module-apps/application-settings-new/data/ApnListData.hpp
M module-apps/application-settings-new/data/QuoteSwitchData.hpp
A module-apps/application-settings-new/data/SettingsInternals.hpp
A module-apps/application-settings-new/data/SettingsItemData.hpp
A module-apps/application-settings-new/models/ApnSettingsModel.cpp
A module-apps/application-settings-new/models/ApnSettingsModel.hpp
A module-apps/application-settings-new/models/NewApnModel.cpp
A module-apps/application-settings-new/models/NewApnModel.hpp
R module-apps/application-settings-new/{model => models}/QuotesModel.cpp
R module-apps/application-settings-new/{model => models}/QuotesModel.hpp
R module-apps/application-settings-new/{model => models}/QuotesRepository.cpp
R module-apps/application-settings-new/{model => models}/QuotesRepository.hpp
A module-apps/application-settings-new/widgets/ApnInputWidget.cpp
A module-apps/application-settings-new/widgets/ApnInputWidget.hpp
A module-apps/application-settings-new/widgets/ApnListItem.hpp
M module-apps/application-settings-new/widgets/SettingsStyle.hpp
D module-apps/application-settings-new/windows/APNSettingsWindow.cpp
M module-apps/application-settings-new/windows/AllDevicesWindow.cpp
A module-apps/application-settings-new/windows/ApnOptionsWindow.cpp
A module-apps/application-settings-new/windows/ApnOptionsWindow.hpp
A module-apps/application-settings-new/windows/ApnSettingsWindow.cpp
R module-apps/application-settings-new/windows/{APNSettingsWindow => ApnSettingsWindow}.hpp
M module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp
M module-apps/application-settings-new/windows/BaseSettingsWindow.cpp
M module-apps/application-settings-new/windows/BluetoothWindow.cpp
M module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp
M module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp
M module-apps/application-settings-new/windows/DisplayLightWindow.cpp
M module-apps/application-settings-new/windows/MessagesWindow.cpp
M module-apps/application-settings-new/windows/NetworkWindow.cpp
A module-apps/application-settings-new/windows/NewApnWindow.cpp
A module-apps/application-settings-new/windows/NewApnWindow.hpp
M module-apps/application-settings-new/windows/NightshiftWindow.cpp
M module-apps/application-settings-new/windows/PhoneNameWindow.cpp
M module-apps/application-settings-new/windows/QuotesAddWindow.cpp
M module-apps/application-settings-new/windows/QuotesAddWindow.hpp
M module-apps/application-settings-new/windows/QuotesMainWindow.cpp
M module-apps/application-settings-new/windows/QuotesMainWindow.hpp
M module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp
M module-apps/application-settings/ApplicationSettings.cpp
M module-apps/application-settings/windows/BtScanWindow.cpp
M module-apps/application-settings/windows/BtWindow.cpp
M module-apps/application-settings/windows/CellularPassthroughWindow.cpp
M module-apps/application-settings/windows/CellularPassthroughWindow.hpp
M module-apps/application-settings/windows/DateTimeWindow.cpp
M module-apps/application-settings/windows/EinkModeWindow.cpp
M module-apps/application-settings/windows/FotaWindow.cpp
M module-apps/application-settings/windows/Info.cpp
M module-apps/application-settings/windows/LanguageWindow.cpp
M module-apps/application-settings/windows/TestMessageWindow.cpp
M module-apps/application-special-input/windows/SpecialInputMainWindow.cpp
M module-apps/windows/AppWindow.cpp
M module-apps/windows/AppWindow.hpp
M module-apps/windows/Dialog.cpp
M module-apps/windows/OptionWindow.cpp
M module-audio/Audio/StreamQueuedEventsListener.cpp
M module-audio/Audio/StreamQueuedEventsListener.hpp
M module-bsp/board/linux/battery-charger/battery_charger.cpp
M module-bsp/board/linux/usb_cdc/usb_cdc.cpp
A module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp
M module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp
M module-bsp/board/rt1051/common/irq/irq_gpio.cpp
M module-bsp/bsp/battery-charger/battery_charger.hpp
M module-db/Common/Query.cpp
M module-db/Common/Query.hpp
M module-db/Interface/AlarmsRecord.hpp
M module-db/Interface/EventsRecord.cpp
M module-db/Interface/EventsRecord.hpp
M module-db/Tables/AlarmsTable.cpp
M module-db/Tables/AlarmsTable.hpp
M module-db/Tables/EventsTable.cpp
M module-db/Tables/EventsTable.hpp
M module-db/queries/calendar/QueryEventsGetFiltered.cpp
M module-db/queries/calendar/QueryEventsGetFiltered.hpp
M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp
M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp
M module-db/tests/AlarmsRecord_tests.cpp
M module-db/tests/AlarmsTable_tests.cpp
M module-db/tests/EventsRecord_tests.cpp
M module-db/tests/EventsTable_tests.cpp
M module-db/tests/QueryInterface.cpp
M module-gui/gui/dom/Item2JsonSerializingVisitor.cpp
M module-gui/gui/dom/Item2JsonSerializingVisitor.hpp
M module-gui/gui/widgets/BoxLayout.cpp
M module-gui/gui/widgets/GridLayout.cpp
M module-gui/gui/widgets/GridLayout.hpp
M module-gui/gui/widgets/Item.hpp
M module-gui/gui/widgets/TopBar.cpp
M module-gui/gui/widgets/TopBar.hpp
M module-gui/gui/widgets/visitor/GuiVisitor.hpp
M module-gui/test/test-google/test-gui-gridlayout.cpp
M module-gui/test/test-google/test-gui-visitor-call.cpp
M module-services/service-appmgr/model/ApplicationManager.cpp
M module-services/service-appmgr/service-appmgr/Actions.hpp
M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp
M module-services/service-cellular/CellularRequestHandler.cpp
M module-services/service-cellular/CellularUrcHandler.cpp
M module-services/service-cellular/CellularUrcHandler.hpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-cellular/service-cellular/CellularRequestHandler.hpp
M module-services/service-cellular/service-cellular/PacketDataTypes.hpp
M module-services/service-db/DBServiceAPI.cpp
M module-services/service-db/agents/settings/Settings.cpp
M module-services/service-db/agents/settings/SettingsAgent.cpp
M module-services/service-db/agents/settings/SettingsAgent.hpp
M module-services/service-db/service-db/Settings.hpp
M module-services/service-db/service-db/SettingsMessages.hpp
A module-services/service-db/service-db/SettingsScope.hpp
M module-services/service-db/test/test-service-db-settings-messages.cpp
M module-services/service-db/test/test-service-db-settings-testservices.hpp
M module-services/service-desktop/DesktopMessages.cpp
M module-services/service-desktop/ServiceDesktop.cpp
M module-services/service-desktop/WorkerDesktop.cpp
M module-services/service-desktop/endpoints/EndpointFactory.hpp
M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp
M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp
M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp
M module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp
M module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp
M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp
M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp
M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp
M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp
M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp
M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp
M module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp
M module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp
M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp
M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp
M module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp
M module-services/service-desktop/parser/MessageHandler.cpp
M module-services/service-desktop/parser/MessageHandler.hpp
M module-services/service-desktop/parser/ParserFSM.cpp
M module-services/service-desktop/parser/ParserFSM.hpp
M module-services/service-desktop/service-desktop/DesktopMessages.hpp
M module-services/service-desktop/tests/unittest.cpp
M module-services/service-evtmgr/WorkerEvent.cpp
M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp
M module-services/service-fota/FotaUrcHandler.cpp
M module-services/service-fota/FotaUrcHandler.hpp
M module-services/service-time/service-time/CalendarTimeEvents.hpp
M module-services/service-time/timeEvents/CalendarTimeEvents.cpp
M module-sys/SystemManager/SystemManager.cpp
M module-sys/SystemManager/SystemManager.hpp
M module-sys/SystemManager/messages/SystemManagerMessage.hpp
M module-utils/CMakeLists.txt
M module-utils/Utils.hpp
A module-utils/circular_buffer/StringCircularBuffer.cpp
A module-utils/circular_buffer/StringCircularBuffer.hpp
A module-utils/generators/RandomStringGenerator.cpp
A module-utils/generators/RandomStringGenerator.hpp
M module-utils/ical/ParserICS.cpp
M module-utils/ical/ParserICS.hpp
A module-utils/log/LoggerBuffer.cpp
A module-utils/log/LoggerBuffer.hpp
M module-utils/test/CMakeLists.txt
A module-utils/test/test_LoggerBuffer.cpp
M module-utils/time/TimeRangeParser.cpp
M module-utils/time/TimeRangeParser.hpp
M test/harness/harness.py
M test/harness/utils.py
M test/pytest/conftest.py
M tools/check_commit_messages.py
A tools/clang-tidy.cmake
M tools/download_asset.py
M .github/workflows/main.yml => .github/workflows/main.yml +0 -6
@@ 20,12 20,6 @@ jobs:
          fetch-depth: 0
      - name: check commit messages
        run: ./tools/check_commit_messages.py
  build:
    if: github.event.pull_request.draft == false
    runs-on: self-hosted
    steps:
      - name: build
        run: echo "Placeholder for old CI scripts"
  check_copyright_and_style:
    name: check copyright and style
    if: github.event.pull_request.draft == false

M .github/workflows/releases.yaml => .github/workflows/releases.yaml +21 -6
@@ 27,13 27,17 @@ jobs:
        popd
    - name: "Build and package for RT1051"
      id: build_release_package 
      env:
        ASSETS_LOGIN: ${{ secrets.ASSETS_LOGIN }}
        ASSETS_TOKEN: ${{ secrets.ASSETS_TOKEN }}
      run: |
        ./configure.sh rt1051 RelWithDebInfo && \
        pushd build-rt1051-RelWithDebInfo && \
        export JOBS=${JOBS:-`nproc`} && \
        echo "JOBS=${JOBS}" && \
        make -j ${JOBS} && \
        make -j ${JOBS}  package && \
        make package-update VERBOSE=1 && \
        make package-standalone && \
        popd && \
        ./print_last_changes.sh && \
        uptime


@@ 48,15 52,26 @@ jobs:
        draft: true
        prerelease: true
        body: ${{steps.build_release_package.outputs.release_notes }}
    - name: Upload Release Package
      id: upload-release-package
    - name: Upload Standalone Package
      id: upload-stanalone-package
      uses: actions/upload-release-asset@v1.0.2
      env:
        GITHUB_TOKEN: ${{ secrets.GitHub_PAT }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        # here we have to use relative path with starting "./"
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{ steps.build_release_package.outputs.package-standalone }}
        asset_name: ${{ steps.build_release_package.outputs.package-standalone }}
        asset_content_type: ${{ steps.build_release_package.outputs.standalone-mime_type }}
    - name: Upload Update Package
      id: upload-update-package
      uses: actions/upload-release-asset@v1.0.2
      env:
        GITHUB_TOKEN: ${{ secrets.GitHub_PAT }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        # here we have to use relative path with starting "./"
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{steps.build_release_package.outputs.package}}
        asset_name: ${{ steps.build_release_package.outputs.package }}
        asset_content_type: ${{ steps.build_release_package.outputs.mime_type }}
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{ steps.build_release_package.outputs.package-update }}
        asset_name: ${{ steps.build_release_package.outputs.package-update }}
        asset_content_type: ${{ steps.build_release_package.outputs.update-mime_type }}


M CMakeLists.txt => CMakeLists.txt +55 -22
@@ 269,24 269,48 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
        )

    # download the bootloader
    add_custom_target(ecoboot.bin
        COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
        -w ${CMAKE_BINARY_DIR}/update ecoboot download
        > ${CMAKE_BINARY_DIR}/update/download_info.txt
        BYPRODUCTS update/ecoboot.bin
        COMMENT "Downloading ecoboot.bin"
        )
    set(ECOBOOT_FILE ${CMAKE_BINARY_DIR}/ecoboot.bin)
    set(ECOBOOT_DOWNLOAD_LOG ${CMAKE_BINARY_DIR}/download_info.txt)

    if(DEFINED ENV{ASSETS_LOGIN} AND DEFINED ENV{ASSETS_TOKEN})
        message("ecooboot download with tokens")
        add_custom_command(OUTPUT ${ECOBOOT_FILE}
            COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
            -l $ENV{ASSETS_LOGIN}
            -t $ENV{ASSETS_TOKEN}
            -w ${CMAKE_BINARY_DIR} ecoboot download
            > ${ECOBOOT_DOWNLOAD_LOG}
            COMMENT "Downloading ecoboot.bin"
            BYPRODUCTS ${ECOBOOT_FILE} ${ECOBOOT_DOWNLOAD_LOG}
            )
    else()
        message("ecoboot download with git")
        add_custom_command(OUTPUT ${ECOBOOT_FILE}
            COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
            -w ${CMAKE_BINARY_DIR} ecoboot download
            > ${ECOBOOT_DOWNLOAD_LOG}
            COMMENT "Downloading ecoboot.bin"
            BYPRODUCTS ${ECOBOOT_FILE} ${ECOBOOT_DOWNLOAD_LOG}
            )
    endif()

    add_custom_target(ecoboot.bin DEPENDS ${ECOBOOT_FILE})

    # generate version.json file (runs CMake script at build time)
    add_custom_target(
        version.json
    set(VERSION_JSON ${CMAKE_BINARY_DIR}/version.json)
    add_custom_command(OUTPUT ${VERSION_JSON}
        COMMAND ${CMAKE_COMMAND}
        -DSRC_DIR=${CMAKE_SOURCE_DIR}
        -DECOBOOT_DOWNLOAD_LOG=${ECOBOOT_DOWNLOAD_LOG}
        -B ${CMAKE_BINARY_DIR}
        -P ${CMAKE_SOURCE_DIR}/config/GenUpdateVersionJson.cmake
        DEPENDS ecoboot.bin
        DEPENDS ecoboot.bin ${ECOBOOT_DOWNLOAD_LOG}
        BYPRODUCTS ${VERSION_JSON}
        )
    install(FILES ${CMAKE_BINARY_DIR}/update/ecoboot.bin DESTINATION "./" COMPONENT Update)
    install(FILES ${CMAKE_BINARY_DIR}/update/version.json DESTINATION "./" COMPONENT Update)
    add_custom_target(version.json DEPENDS ${VERSION_JSON})

    multicomp_install(PROGRAMS ${ECOBOOT_FILE} DESTINATION "./" COMPONENTS Standalone Update)
    multicomp_install(FILES ${VERSION_JSON} DESTINATION "./" COMPONENTS Standalone Update)

    set(CPACK_SYSTEM_NAME "RT1051")
    # allow both standalone and update packages in RT1051 config


@@ 403,19 427,23 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
    add_custom_target(package-standalone
        COMMAND zip -rq ${CMAKE_BINARY_DIR}/${PACKAGE_STANDALONE_FILE_NAME} "."
        WORKING_DIRECTORY ${PACKAGE_STAGING_DIRECTORY}/Standalone
        DEPENDS package-standalone-staged
        DEPENDS ${ECOBOOT_FILE} package-standalone-staged  PurePhone
        )
    set(UPDATE_STAGING_DIRECTORY ${PACKAGE_STAGING_DIRECTORY}/Update)
    add_custom_target(package-update-checksums
        COMMAND rhash
        -u ${PACKAGE_STAGING_DIRECTORY}/Update/checksums.txt
        -r ${PACKAGE_STAGING_DIRECTORY}/Update
        -u checksums.txt
        -r .
        WORKING_DIRECTORY ${UPDATE_STAGING_DIRECTORY}
        DEPENDS package-update-staged
        )
    set(PACKAGE_UPDATE_FILE_NAME ${PACKAGE_COMMON_NAME}-Update.tar)
    set(PACKAGE_UPDATE_MIME "application/x-tar")
    add_custom_target(package-update
        COMMAND tar
        -czf ${CMAKE_BINARY_DIR}/${PACKAGE_COMMON_NAME}-Update.tar.gz
        -cf ${CMAKE_BINARY_DIR}/${PACKAGE_UPDATE_FILE_NAME}
        -C ${PACKAGE_STAGING_DIRECTORY}/Update "."
        DEPENDS package-update-staged package-update-checksums
        DEPENDS ecoboot.bin version.json PurePhone package-update-staged package-update-checksums
        )
elseif (${PROJECT_TARGET} STREQUAL "TARGET_Linux")
    set(PACKAGE_STANDALONE_FILE_NAME ${PACKAGE_COMMON_NAME}-Standalone.tar.gz)


@@ 429,9 457,14 @@ elseif (${PROJECT_TARGET} STREQUAL "TARGET_Linux")
endif()

if (NOT "$ENV{GITHUB_WORKSPACE}" STREQUAL "")
    message("set-output name=package::${PACKAGE_STANDALONE_FILE_NAME}")
    message("::set-output name=package::${PACKAGE_STANDALONE_FILE_NAME}")
    
    message("set-output name=mime_type::${PACKAGE_STANDALONE_MIME}")
    message("::set-output name=mime_type::${PACKAGE_STANDALONE_MIME}")
    message("set-output name=package-standalone::${PACKAGE_STANDALONE_FILE_NAME}")
    message("::set-output name=package-standalone::${PACKAGE_STANDALONE_FILE_NAME}")
    message("set-output name=standalone-mime_type::${PACKAGE_STANDALONE_MIME}")
    message("::set-output name=standalone-mime_type::${PACKAGE_STANDALONE_MIME}")

    message("set-output name=package-update::${PACKAGE_UPDATE_FILE_NAME}")
    message("::set-output name=package-update::${PACKAGE_UPDATE_FILE_NAME}")
    message("set-output name=update-mime_type::${PACKAGE_UPDATE_MIME}")
    message("::set-output name=update-mime_type::${PACKAGE_UPDATE_MIME}")

endif()

A art/phone/application_desktop/menu/dead_battery_W_G.png => art/phone/application_desktop/menu/dead_battery_W_G.png +0 -0
M changelog.md => changelog.md +3 -1
@@ 5,7 5,9 @@
### Added

* Add hardware in the loop tests.
* Add empty APN settings window.
* Add APN settings window.
* Add New/Edit APN window
* Add APN options window

### Changed


M config/GenUpdateVersionJson.cmake => config/GenUpdateVersionJson.cmake +2 -2
@@ 8,7 8,7 @@ include(Version)
set(BOOTLOADER_INCLUDED "true")
set(BOOTLOADER_FILENAME "ecoboot.bin")
execute_process(
    COMMAND grep "release:" "${CMAKE_BINARY_DIR}/update/download_info.txt"
    COMMAND grep "release:" "${ECOBOOT_DOWNLOAD_LOG}"
    COMMAND awk "{print $2}"
    OUTPUT_VARIABLE BOOTLOADER_VERSION
    OUTPUT_STRIP_TRAILING_WHITESPACE


@@ 16,6 16,6 @@ execute_process(

configure_file(
    ${SRC_DIR}/config/version.json.cmake_template
    ${CMAKE_BINARY_DIR}/update/version.json
    ${CMAKE_BINARY_DIR}/version.json
    @ONLY
    )

M doc/development_workflow.md => doc/development_workflow.md +1 -0
@@ 53,6 53,7 @@ Before submitting a Pull Request please go through some basic checks:

- test your changes on both Linux and RT1051 platforms (please pay special attention to the things you might break unintentionally, e.g. when working on calling, check call log too,
- run unit tests (`make check`),
- [run static analysis](static_analysis.md)
- check if your code formatting complies with [`.clang-format`](../clang-format),
- whenever you add third-party software to MuditaOS source code, please make sure that the software component is added to a dedicated [section in `LICENSE.md` file on MuditaOS GitHub repository](../LICENSE.md) with a link to the text of the license where applicable.


A doc/static_analysis.md => doc/static_analysis.md +31 -0
@@ 0,0 1,31 @@
# Static code analysis

The Static code analysis is a method of debugging that is done by examining the source code without executing the program.

Before submitting the Pull Request a developer should run static code analyzer tool and make sure that his code complies with the Coding Standards.

## Clang-tidy

The clang-tidy is a clang-based C++ “linter” tool. Its purpose is to provide an extensible framework for diagnosing and fixing typical programming errors, like style violations, interface misuse, or bugs that can be deduced via static analysis.

### Install clang-tidy

#### Linux Ubuntu

The clang-tidy tool is available from the APT repository.

`$ sudo apt install clang-tidy`

### Run clang-tidy

If `run-clang-tidy` program is installed, a CMake target called `clang-tidy` is available.

In order to run `clang-tidy` analyzer on the MuditaOS repository, follow the steps:
```
$ cd <path/to/MuditaOS>
$ ./configure.sh <platform> <build_type>
$ cd <path/to/build/dir>
$ make clang-tidy
```

The results of the analysis are available under `$(pwd)/StaticAnalysis` directory.

A image/assets/images/dead_battery_W_G.vpi => image/assets/images/dead_battery_W_G.vpi +0 -0
M image/assets/lang/English.json => image/assets/lang/English.json +13 -1
@@ 352,7 352,6 @@
  "app_settings_network_sim_none": "No Sim",
  "app_settings_network_voice_over_lte" : "VoLTE (experimental)",
  "app_settings_network_apn_settings" : "APN settings",
  "app_settings_network_apn_settings_no_apns" : "<text align='center' color='9'>No APNs yet.<p>Press <b>left arrow</b> to add new.</p></text>",
  "app_settings_toggle_on": "ON",
  "app_settings_toggle_off": "OFF",
  "app_settings_security_lock_screen_passcode": "Lock screen passcode",


@@ 363,6 362,19 @@
  "app_settings_security_wrong_passcode": "Wrong passcode!",
  "app_settings_security_passcode_changed_successfully": "Passcode changed successfully!",
  "app_settings_security_passcode_disabled": "Passcode disabled!",
  "app_settings_apn_settings_no_apns" : "<text align='center' color='9'>No APNs yet.<p>Press <b>left arrow</b> to add new.</p></text>",
  "app_settings_apn_options" : "Options",
  "app_settings_apn_options_delete" : "Delete",
  "app_settings_apn_options_edit" : "Edit",
  "app_settings_apn_options_set_as_default" : "Set as default",
  "app_settings_new_edit_apn": "New/Edit APN",
  "app_settings_apn_name": "Name",
  "app_settings_apn_APN": "APN",
  "app_settings_apn_username": "UserName",
  "app_settings_apn_password": "Password",
  "app_settings_apn_authtype": "Authentication type",
  "app_settings_apn_apntype": "APN Type",
  "app_settings_apn_apnprotocol" : "APN Protocol",
  "app_phonebook_title_main": "Contacts",
  "app_phonebook_search_win_contacts": "Contacts",
  "common_search_uc": "Search",

M module-apps/Application.cpp => module-apps/Application.cpp +17 -6
@@ 70,10 70,12 @@ namespace app
                             uint32_t stackDepth,
                             sys::ServicePriority priority)
        : Service(std::move(name), std::move(parent), stackDepth, priority),
          default_window(gui::name::window::main_window), windowsStack(this), startInBackground{startInBackground},
          callbackStorage{std::make_unique<CallbackStorage>()}, settings(std::make_unique<settings::Settings>(this))
          default_window(gui::name::window::main_window), windowsStack(this),
          keyTranslator{std::make_unique<gui::KeyInputSimpleTranslation>()}, startInBackground{startInBackground},
          callbackStorage{std::make_unique<CallbackStorage>()}, topBarManager{std::make_unique<TopBarManager>()},
          settings(std::make_unique<settings::Settings>(this))
    {
        keyTranslator = std::make_unique<gui::KeyInputSimpleTranslation>();
        topBarManager->enableIndicators({gui::top_bar::Indicator::Time});
        busChannels.push_back(sys::BusChannels::ServiceCellularNotifications);

        longPressTimer = std::make_unique<sys::Timer>("LongPress", this, key_timer_ms);


@@ 82,13 84,16 @@ namespace app
        connect(typeid(AppRefreshMessage),
                [this](sys::Message *msg) -> sys::MessagePointer { return handleAppRefresh(msg); });

        settings->registerValueChange(settings::SystemProperties::timeFormat12,
                                      [this](std::string value) { timeFormatChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::timeFormat12,
            [this](std::string value) { timeFormatChanged(value); },
            settings::SettingsScope::Global);
    }

    Application::~Application() noexcept
    {
        windowsStack.windows.clear();
        settings->unregisterValueChange();
    }

    Application::State Application::getState()


@@ 496,7 501,8 @@ namespace app

        settings->registerValueChange(
            settings::SystemProperties::lockScreenPasscodeIsOn,
            [this](const std::string &value) { setLockScreenPasscodeOn(utils::getNumericValue<bool>(value)); });
            [this](const std::string &value) { setLockScreenPasscodeOn(utils::getNumericValue<bool>(value)); },
            settings::SettingsScope::Global);
        return sys::ReturnCodes::Success;
    }



@@ 693,6 699,11 @@ namespace app
        item->attachTimer(std::move(timer));
    }

    const gui::top_bar::Configuration &Application::getTopBarConfiguration() const noexcept
    {
        return topBarManager->getConfiguration();
    }

    void Application::addActionReceiver(manager::actions::ActionId actionId, OnActionReceived &&callback)
    {
        receivers.insert_or_assign(actionId, std::move(callback));

M module-apps/Application.hpp => module-apps/Application.hpp +4 -0
@@ 25,6 25,7 @@
#include <string>                                       // for string
#include <utility>                                      // for move, pair
#include <vector>                                       // for vector
#include "TopBarManager.hpp"
#include "WindowsFactory.hpp"
#include "WindowsStack.hpp"



@@ 369,6 370,8 @@ namespace app

        void addActionReceiver(manager::actions::ActionId actionId, OnActionReceived &&callback);

        std::unique_ptr<TopBarManager> topBarManager;

        /// application's settings
        std::unique_ptr<settings::Settings> settings;
        virtual void timeFormatChanged(std::string value);


@@ 378,6 381,7 @@ namespace app
        bool isTimeFormat12() const noexcept;
        void setLockScreenPasscodeOn(bool screenPasscodeOn) noexcept;
        bool isLockScreenPasscodeOn() const noexcept;
        const gui::top_bar::Configuration &getTopBarConfiguration() const noexcept;
    };

    /// Parameter pack used by application launch action.

M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +1 -0
@@ 15,6 15,7 @@ set( SOURCES
    "Application.cpp"
    "GuiTimer.cpp"
    "WindowsFactory.cpp"
    "TopBarManager.cpp"
    "AsyncTask.cpp"
    "CallbackStorage.cpp"
    "windows/AppWindow.cpp"

A module-apps/TopBarManager.cpp => module-apps/TopBarManager.cpp +17 -0
@@ 0,0 1,17 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "TopBarManager.hpp"

namespace app
{
    void TopBarManager::enableIndicators(const gui::top_bar::Indicators &indicators)
    {
        topBarConfiguration.enable(indicators);
    }

    auto TopBarManager::getConfiguration() const noexcept -> const gui::top_bar::Configuration &
    {
        return topBarConfiguration;
    }
} // namespace app

A module-apps/TopBarManager.hpp => module-apps/TopBarManager.hpp +19 -0
@@ 0,0 1,19 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <TopBar.hpp>

namespace app
{
    class TopBarManager
    {
      public:
        void enableIndicators(const gui::top_bar::Indicators &indicators);
        [[nodiscard]] auto getConfiguration() const noexcept -> const gui::top_bar::Configuration &;

      private:
        gui::top_bar::Configuration topBarConfiguration;
    };
} // namespace app

M module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp => module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp +0 -1
@@ 32,7 32,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::Switch));

M module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp => module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp +0 -3
@@ 18,9 18,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        topBar->setActive(gui::TopBar::Elements::SIM, false);
        topBar->setActive(gui::TopBar::Elements::NETWORK_ACCESS_TECHNOLOGY, false);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp => module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp +0 -1
@@ 21,7 21,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-antenna/windows/AlgoParamsWindow.cpp => module-apps/application-antenna/windows/AlgoParamsWindow.cpp +0 -4
@@ 39,10 39,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        lowBandBox  = new gui::VBox(this,

M module-apps/application-antenna/windows/AntennaMainWindow.cpp => module-apps/application-antenna/windows/AntennaMainWindow.cpp +0 -4
@@ 48,10 48,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        for (auto title : titlesText) {

M module-apps/application-antenna/windows/ScanModesWindow.cpp => module-apps/application-antenna/windows/ScanModesWindow.cpp +0 -4
@@ 37,10 37,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        modeButtonParams.insert(std::pair<uint32_t, std::string>(scanModes::Auto, "AUTO"));

M module-apps/application-calculator/data/CalculatorUtility.cpp => module-apps/application-calculator/data/CalculatorUtility.cpp +70 -0
@@ 15,6 15,9 @@ Result Calculator::calculate(std::string source)
    double result = te_interp(source.c_str(), &error);
    if (error == 0 && !std::isinf(result) && !std::isnan(result)) {
        auto output = utils::to_string(result);
        if (output.length() > CalculatorConstants::maxStringLength) {
            output = getValueThatFitsOnScreen(result);
        }
        if (utils::localize.get("app_calculator_decimal_separator") == style::calculator::symbols::strings::comma) {
            output.replace(output.find(style::calculator::symbols::strings::full_stop),
                           std::size(std::string_view(style::calculator::symbols::strings::full_stop)),


@@ 48,3 51,70 @@ std::string Calculator::replaceAllOccurrences(std::string input, const std::stri
    }
    return input;
}

std::string Calculator::getValueThatFitsOnScreen(double result)
{
    auto base   = static_cast<long long>(result);
    auto length = utils::to_string(base).length();
    if (base < 0) {
        length -= 1;
    }
    if (length > CalculatorConstants::expLength + 1) {
        return convertToNumberWithPositiveExponent(result, length - 1);
    }
    else if (length == CalculatorConstants::expLength + 1) {
        if (result < 0) {
            return utils::to_string(getCoefficient(result, CalculatorConstants::veryLowPrecision));
        }
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    else if (length == 1 && result < -1) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    else if (result > 1) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
    }
    else {
        return convertToNumberWithNegativeExponent(result, base);
    }
}

std::string Calculator::convertToNumberWithPositiveExponent(double result, uint32_t exponent)
{
    result /= pow(10, exponent);
    auto exponentLength = utils::to_string(exponent).length();
    auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::expLength;
    if (result < 0) {
        decimalPlace -= 1;
    }
    return utils::to_string(getCoefficient(result, decimalPlace)) + "e" + utils::to_string(exponent);
}

std::string Calculator::convertToNumberWithNegativeExponent(double result, long long base)
{
    double frac = (result - base) * pow(10, CalculatorConstants::highPrecision);
    if (result < 0) {
        frac *= -1;
    }
    auto fractionalPart = static_cast<unsigned long int>(round(frac));
    auto fracLength     = utils::to_string(fractionalPart).length();
    auto exponent       = CalculatorConstants::highPrecision - fracLength + 1;
    if (exponent > CalculatorConstants::minusExpLength + 1) {
        result *= pow(10, exponent);
        auto exponentLength = utils::to_string(exponent).length();
        auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::minusExpLength;
        if (result < 0) {
            decimalPlace -= 1;
        }
        return utils::to_string(getCoefficient(result, decimalPlace)) + "e-" + utils::to_string(exponent);
    }
    else if (result < 0) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
}

long double Calculator::getCoefficient(double result, uint32_t precision)
{
    return std::roundl(result * pow(10, precision)) / pow(10, precision);
}

M module-apps/application-calculator/data/CalculatorUtility.hpp => module-apps/application-calculator/data/CalculatorUtility.hpp +15 -0
@@ 4,6 4,17 @@
#pragma once
#include <string>

namespace CalculatorConstants
{
    inline constexpr auto veryLowPrecision = 4;
    inline constexpr auto lowPrecision     = 5;
    inline constexpr auto precision        = 6;
    inline constexpr auto highPrecision    = 8;
    inline constexpr auto expLength        = 1;
    inline constexpr auto minusExpLength   = 2;
    inline constexpr auto maxStringLength  = 7;
} // namespace CalculatorConstants

struct Result
{
    std::string equation;


@@ 18,6 29,10 @@ class Calculator
    /// @return: new string with replaced all occurrences of given string to the new one in whole input
    std::string replaceAllOccurrences(std::string input, const std::string &from, const std::string &to);
    std::string prepareEquationForParser(std::string input);
    std::string getValueThatFitsOnScreen(double result);
    long double getCoefficient(double result, uint32_t precision);
    std::string convertToNumberWithPositiveExponent(double result, uint32_t exponent);
    std::string convertToNumberWithNegativeExponent(double result, long long base);

  public:
    Result calculate(std::string source);

M module-apps/application-calculator/tests/CalculatorUtility_tests.cpp => module-apps/application-calculator/tests/CalculatorUtility_tests.cpp +47 -0
@@ 93,4 93,51 @@ TEST_CASE("Calculator utilities")
        REQUIRE(result.equation == "1.79769e+308*2");
        REQUIRE(result.isError);
    }

    SECTION("Round to fit in screen")
    {
        auto result = calculator.calculate("1.1234512345");
        REQUIRE(result.value == "1.123451");
        REQUIRE(!result.isError);

        result = calculator.calculate("0.0567891");
        REQUIRE(result.value == "0.056789");
        REQUIRE(!result.isError);

        result = calculator.calculate("-0.056789");
        REQUIRE(result.value == "-0.05679");
        REQUIRE(!result.isError);

        result = calculator.calculate("15.556789");
        REQUIRE(result.value == "15.55679");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (number > 0)")
    {
        auto result = calculator.calculate("12345.55555");
        REQUIRE(result.value == "1.2346e4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (number < 0)")
    {
        auto result = calculator.calculate("-12345.55555");
        REQUIRE(result.value == "-1.235e4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (0 < number < 1)")
    {
        auto result = calculator.calculate("0.000456712");
        REQUIRE(result.value == "4.567e-4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (-1 < number < 0)")
    {
        auto result = calculator.calculate("-0.000456712");
        REQUIRE(result.value == "-4.57e-4");
        REQUIRE(!result.isError);
    }
}

M module-apps/application-calculator/widgets/CalculatorStyle.hpp => module-apps/application-calculator/widgets/CalculatorStyle.hpp +1 -0
@@ 34,6 34,7 @@ namespace style::calculator
            inline constexpr auto full_stop      = 0x002E;
            inline constexpr auto comma          = 0x002C;
            inline constexpr auto equals         = 0x003D;
            inline constexpr auto zero           = 0x0030;
        } // namespace codes

        namespace strings

M module-apps/application-calculator/windows/CalculatorMainWindow.cpp => module-apps/application-calculator/windows/CalculatorMainWindow.cpp +42 -7
@@ 63,8 63,15 @@ namespace gui
            if (!event.isShortPress()) {
                return false;
            }
            if (event.is(gui::KeyCode::KEY_0) && mathOperationInput->getText() == "0") {
                return true;
            }
            auto lastChar         = mathOperationInput->getText()[mathOperationInput->getText().length() - 1];
            bool lastCharIsSymbol = isSymbol(lastChar);
            if (lastChar == style::calculator::symbols::codes::zero && isSymbol(getPenultimate()) &&
                !isDecimalSeparator(getPenultimate()) && event.is(gui::KeyCode::KEY_0)) {
                return true;
            }
            if (event.keyCode == gui::KeyCode::KEY_UP) {
                writeEquation(lastCharIsSymbol, style::calculator::symbols::strings::plus);
                return true;


@@ 89,6 96,15 @@ namespace gui
                }
                return true;
            }
            if (lastChar == style::calculator::symbols::codes::zero && isSymbol(getPenultimate()) &&
                !isDecimalSeparator(getPenultimate()) && !event.is(gui::KeyCode::KEY_0) &&
                !event.is(gui::KeyCode::KEY_PND) && !event.is(gui::KeyCode::KEY_ENTER)) {
                mathOperationInput->removeChar();
                return false;
            }
            if (!event.is(gui::KeyCode::KEY_0) && mathOperationInput->getText() == "0") {
                mathOperationInput->clear();
            }
            return false;
        };
    }


@@ 103,21 119,36 @@ namespace gui
               character == style::calculator::symbols::codes::full_stop;
    }

    bool CalculatorMainWindow::isDecimalSeparator(uint32_t character)
    {
        return character == style::calculator::symbols::codes::comma ||
               character == style::calculator::symbols::codes::full_stop;
    }

    uint32_t CalculatorMainWindow::getPenultimate()
    {
        if (mathOperationInput->getText().length() > 1) {
            return mathOperationInput->getText()[mathOperationInput->getText().length() - 2];
        }
        return 0;
    }

    void CalculatorMainWindow::writeEquation(bool lastCharIsSymbol, const UTF8 &symbol)
    {
        if (!mathOperationInput->getText().empty()) {

            if (lastCharIsSymbol && symbol != style::calculator::symbols::strings::minus) {
                mathOperationInput->setRichText(
                    std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1) +
                    symbol.c_str());
                if (!isSymbol(getPenultimate()) && mathOperationInput->getText().length() > 1) {
                    mathOperationInput->removeChar();
                    mathOperationInput->addText(symbol);
                }
            }
            else {
                mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
                mathOperationInput->addText(symbol);
            }
        }
        else if (symbol == style::calculator::symbols::strings::minus) {
            mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
            mathOperationInput->addText(symbol);
        }
    }



@@ 126,7 157,11 @@ namespace gui
        if (!mathOperationInput->getText().empty()) {
            std::vector<int> symbolsIndexes;
            auto input = std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1);
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::minus));
            auto exponentIndex = input.find_last_of('e');
            auto minusIndex    = input.find_last_of(style::calculator::symbols::strings::minus);
            if (minusIndex != exponentIndex + 1) {
                symbolsIndexes.push_back(minusIndex);
            }
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::plus));
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::division));
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::multiplication));


@@ 156,7 191,7 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
            auto result = Calculator().calculate(std::string(mathOperationInput->getText()));
            mathOperationInput->setRichText(result.value);
            mathOperationInput->setText(result.value);
            clearInput = result.isError;
            return true;
        }

M module-apps/application-calculator/windows/CalculatorMainWindow.hpp => module-apps/application-calculator/windows/CalculatorMainWindow.hpp +2 -0
@@ 22,6 22,8 @@ namespace gui
        void applyInputCallback();
        bool isPreviousNumberDecimal();
        bool isSymbol(uint32_t character);
        bool isDecimalSeparator(uint32_t character);
        uint32_t getPenultimate();

      public:
        CalculatorMainWindow(app::Application *app, std::string name);

M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +1 -1
@@ 147,7 147,7 @@ namespace app
    void ApplicationCalendar::destroyUserInterface()
    {}

    void ApplicationCalendar::switchToNoEventsWindow(const std::string &title, const TimePoint &dateFilter)
    void ApplicationCalendar::switchToNoEventsWindow(const std::string &title, const calendar::TimePoint &dateFilter)
    {
        if (equivalentWindow == EquivalentWindow::DayEventsWindow) {
            popToWindow(gui::name::window::main_window);

M module-apps/application-calendar/ApplicationCalendar.hpp => module-apps/application-calendar/ApplicationCalendar.hpp +2 -1
@@ 55,7 55,8 @@ namespace app
        }
        void createUserInterface() override;
        void destroyUserInterface() override;
        void switchToNoEventsWindow(const std::string &title = "", const TimePoint &dateFilter = TimePoint());
        void switchToNoEventsWindow(const std::string &title              = "",
                                    const calendar::TimePoint &dateFilter = calendar::TimePoint());

        static const std::map<Reminder, const char *> reminderOptions;
        static const std::map<Repeat, const char *> repeatOptions;

M module-apps/application-calendar/data/CalendarData.hpp => module-apps/application-calendar/data/CalendarData.hpp +3 -3
@@ 42,7 42,7 @@ class DayMonthData : public gui::SwitchData
{
  protected:
    std::string dayMonth;
    TimePoint dateFilter;
    calendar::TimePoint dateFilter;

  public:
    DayMonthData()          = default;


@@ 52,12 52,12 @@ class DayMonthData : public gui::SwitchData
        return dayMonth;
    };

    TimePoint getDateFilter()
    calendar::TimePoint getDateFilter()
    {
        return dateFilter;
    };

    virtual void setData(std::string dayMonthText, const TimePoint &dateNumb)
    virtual void setData(std::string dayMonthText, const calendar::TimePoint &dateNumb)
    {
        dayMonth   = dayMonthText;
        dateFilter = dateNumb;

M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +35 -35
@@ 9,13 9,13 @@
#include <Utils.hpp>
#include <random>

using namespace std::chrono;
using namespace std::chrono_literals;

using Clock            = system_clock;
using TimePoint        = time_point<Clock>;
using YearMonthDay     = date::year_month_day;
using YearMonthDayLast = date::year_month_day_last;
namespace calendar
{
    using Clock            = std::chrono::system_clock;
    using TimePoint        = std::chrono::time_point<Clock>;
    using YearMonthDay     = date::year_month_day;
    using YearMonthDayLast = date::year_month_day_last;
} // namespace calendar

inline constexpr auto max_month_day = 48;



@@ 43,7 43,7 @@ enum class Repeat
    yearly
};

inline constexpr TimePoint TIME_POINT_INVALID = date::sys_days{date::January / 1 / 1970};
inline constexpr calendar::TimePoint TIME_POINT_INVALID = date::sys_days{date::January / 1 / 1970};
inline constexpr uint32_t yearDigitsNumb = 4, monthDigitsNumb = 2, dayDigitsNumb = 2, HourDigitsNumb = 2,
                          MinDigitsNumb = 2, SecDigitsNumb = 2;



@@ 88,34 88,34 @@ inline time_t GetAsUTCTime(int year, int month, int day, int hour = 0, int minut
    return basetime + GetDiffLocalWithUTCTime();
}

inline TimePoint TimePointFromTimeT(const time_t &time)
inline calendar::TimePoint TimePointFromTimeT(const time_t &time)
{
    return system_clock::from_time_t(time);
    return std::chrono::system_clock::from_time_t(time);
}

inline time_t TimePointToTimeT(const TimePoint &tp)
inline time_t TimePointToTimeT(const calendar::TimePoint &tp)
{
    return system_clock::to_time_t(tp);
    return std::chrono::system_clock::to_time_t(tp);
}

inline TimePoint TimePointNow()
inline calendar::TimePoint TimePointNow()
{
    utils::time::Timestamp timestamp;
    return TimePointFromTimeT(timestamp.getTime());
}

inline std::string TimePointToString(const TimePoint &tp)
inline std::string TimePointToString(const calendar::TimePoint &tp)
{
    return date::format("%F %T", time_point_cast<seconds>(tp));
    return date::format("%F %T", std::chrono::time_point_cast<std::chrono::seconds>(tp));
}

inline auto TimePointToHourMinSec(const TimePoint &tp)
inline auto TimePointToHourMinSec(const calendar::TimePoint &tp)
{
    auto dp = date::floor<date::days>(tp);
    return date::make_time(tp - dp);
}

inline uint32_t TimePointToHour24H(const TimePoint &tp)
inline uint32_t TimePointToHour24H(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 123,7 123,7 @@ inline uint32_t TimePointToHour24H(const TimePoint &tp)
    return hour;
}

inline uint32_t TimePointToMinutes(const TimePoint &tp)
inline uint32_t TimePointToMinutes(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 131,7 131,7 @@ inline uint32_t TimePointToMinutes(const TimePoint &tp)
    return minute;
}

inline TimePoint getFirstWeekDay(const TimePoint &tp)
inline calendar::TimePoint getFirstWeekDay(const calendar::TimePoint &tp)
{
    date::year_month_day yearMonthDay = date::year_month_day{date::floor<date::days>(tp)};
    auto hourV                        = TimePointToHour24H(tp);


@@ 146,12 146,12 @@ inline TimePoint getFirstWeekDay(const TimePoint &tp)
    return finalDateTime;
}

inline std::string TimePointToString(const TimePoint &tp, date::months months)
inline std::string TimePointToString(const calendar::TimePoint &tp, date::months months)
{
    date::year_month_day yearMonthDay     = date::year_month_day{date::floor<date::days>(tp)};
    date::year_month_day yearMonthDayLast = yearMonthDay.year() / yearMonthDay.month() / date::last;

    TimePoint timePoint;
    calendar::TimePoint timePoint;

    if ((static_cast<unsigned>(yearMonthDay.month()) + months.count()) <= 12) {
        if (yearMonthDayLast.day() == yearMonthDay.day()) {


@@ 173,41 173,41 @@ inline std::string TimePointToString(const TimePoint &tp, date::months months)
            timePoint = date::sys_days{yearMonthDay.year() / yearMonthDay.month() / yearMonthDay.day()};
        }
    }
    return date::format("%F %T", time_point_cast<seconds>(timePoint));
    return date::format("%F %T", std::chrono::time_point_cast<std::chrono::seconds>(timePoint));
}

inline std::string TimePointToLocalizedDateString(const TimePoint &tp, const std::string format = "")
inline std::string TimePointToLocalizedDateString(const calendar::TimePoint &tp, const std::string format = "")
{
    auto time = TimePointToTimeT(tp);
    utils::time::Date timestamp(time);
    return timestamp.str(format);
}

inline std::string TimePointToLocalizedTimeString(const TimePoint &tp, const std::string format = "")
inline std::string TimePointToLocalizedTimeString(const calendar::TimePoint &tp, const std::string format = "")
{
    auto time = TimePointToTimeT(tp);
    utils::time::Time timestamp(time);
    return timestamp.str(format);
}

inline TimePoint TimePointFromString(const char *s1)
inline calendar::TimePoint TimePointFromString(const char *s1)
{
    TimePoint tp;
    calendar::TimePoint tp;
    std::istringstream(s1) >> date::parse("%F %T", tp);
    return tp;
}

inline YearMonthDay TimePointToYearMonthDay(const TimePoint &tp)
inline calendar::YearMonthDay TimePointToYearMonthDay(const calendar::TimePoint &tp)
{
    return date::year_month_day{date::floor<date::days>(tp)};
}

inline TimePoint TimePointFromYearMonthDay(const YearMonthDay &ymd)
inline calendar::TimePoint TimePointFromYearMonthDay(const calendar::YearMonthDay &ymd)
{
    return date::sys_days{ymd.year() / ymd.month() / ymd.day()};
}

inline time_t TimePointToMin(const TimePoint &tp)
inline time_t TimePointToMin(const calendar::TimePoint &tp)
{
    auto time     = TimePointToTimeT(tp);
    auto duration = new utils::time::Duration(time);


@@ 215,7 215,7 @@ inline time_t TimePointToMin(const TimePoint &tp)
    return minutes;
}

inline uint32_t TimePointToHour12H(const TimePoint &tp)
inline uint32_t TimePointToHour12H(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 226,7 226,7 @@ inline uint32_t TimePointToHour12H(const TimePoint &tp)
    return hour;
}

inline std::string TimePointToHourString12H(const TimePoint &tp)
inline std::string TimePointToHourString12H(const calendar::TimePoint &tp)
{
    auto hour =
        utils::time::Timestamp(TimePointToTimeT(tp)).get_UTC_date_time_sub_value(utils::time::GetParameters::Hour);


@@ 234,14 234,14 @@ inline std::string TimePointToHourString12H(const TimePoint &tp)
    return utils::to_string(hour12h);
}

inline std::string TimePointToHourString24H(const TimePoint &tp)
inline std::string TimePointToHourString24H(const calendar::TimePoint &tp)
{
    auto hour =
        utils::time::Timestamp(TimePointToTimeT(tp)).get_UTC_date_time_sub_value(utils::time::GetParameters::Hour);
    return utils::to_string(hour);
}

inline std::string TimePointToMinutesString(const TimePoint &tp)
inline std::string TimePointToMinutesString(const calendar::TimePoint &tp)
{
    auto minute       = TimePointToMinutes(tp);
    auto minuteString = std::to_string(minute);


@@ 252,9 252,9 @@ inline std::string TimePointToMinutesString(const TimePoint &tp)
}

// 0: Monday, 1: Tuesday ... 6: Sunday
inline unsigned int WeekdayIndexFromTimePoint(const TimePoint &tp)
inline unsigned int WeekdayIndexFromTimePoint(const calendar::TimePoint &tp)
{
    auto ymw = date::year_month_weekday{floor<date::days>(tp)};
    auto ymw = date::year_month_weekday{std::chrono::floor<date::days>(tp)};
    return ymw.weekday().iso_encoding() - 1;
}


M module-apps/application-calendar/models/AllEventsModel.cpp => module-apps/application-calendar/models/AllEventsModel.cpp +2 -2
@@ 83,8 83,8 @@ auto AllEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
    auto eventShift = app->getEventShift();
    if (eventShift) {
        for (auto &record : records) {
            record.date_from += hours(eventShift);
            record.date_till += hours(eventShift);
            record.date_from += std::chrono::hours(eventShift);
            record.date_till += std::chrono::hours(eventShift);
        }
    }
    return this->updateRecords(std::move(records));

M module-apps/application-calendar/models/DayEventsModel.cpp => module-apps/application-calendar/models/DayEventsModel.cpp +3 -3
@@ 82,8 82,8 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
            auto eventShift = app->getEventShift();
            if (eventShift) {
                for (auto &record : records) {
                    record.date_from += hours(eventShift);
                    record.date_till += hours(eventShift);
                    record.date_from += std::chrono::hours(eventShift);
                    record.date_till += std::chrono::hours(eventShift);
                }
            }
            return updateRecords(std::move(records));


@@ 95,7 95,7 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
    return false;
}

void DayEventsModel::setFilters(TimePoint from, TimePoint till, const std::string &dayMonth)
void DayEventsModel::setFilters(calendar::TimePoint from, calendar::TimePoint till, const std::string &dayMonth)
{
    this->filterFrom    = from;
    this->filterTill    = till;

M module-apps/application-calendar/models/DayEventsModel.hpp => module-apps/application-calendar/models/DayEventsModel.hpp +3 -3
@@ 15,13 15,13 @@ class DayEventsModel : public app::DatabaseModel<EventsRecord>,
{
    app::Application *application = nullptr;
    std::string dayMonthTitle;
    TimePoint filterFrom = TIME_POINT_INVALID;
    TimePoint filterTill = TIME_POINT_INVALID;
    calendar::TimePoint filterFrom = TIME_POINT_INVALID;
    calendar::TimePoint filterTill = TIME_POINT_INVALID;

  public:
    DayEventsModel(app::Application *app);

    void setFilters(TimePoint from, TimePoint till, const std::string &dayMonth);
    void setFilters(calendar::TimePoint from, calendar::TimePoint till, const std::string &dayMonth);

    bool updateRecords(std::vector<EventsRecord> records) override;
    auto handleQueryResponse(db::QueryResult *) -> bool;

M module-apps/application-calendar/widgets/EventDateItem.cpp => module-apps/application-calendar/widgets/EventDateItem.cpp +3 -3
@@ 149,7 149,7 @@ namespace gui
        return true;
    }

    YearMonthDay EventDateItem::validateDate()
    calendar::YearMonthDay EventDateItem::validateDate()
    {
        auto actualDate = TimePointToYearMonthDay(TimePointNow());
        uint32_t day;


@@ 185,7 185,7 @@ namespace gui
        }
        month = std::clamp(static_cast<unsigned>(month), 1u, static_cast<unsigned>(date::dec));

        YearMonthDayLast max_date = date::year(year) / date::month(month) / date::last;
        calendar::YearMonthDayLast max_date = date::year(year) / date::month(month) / date::last;
        if (day > static_cast<unsigned>(max_date.day())) {
            dayInput->setText(std::to_string(static_cast<unsigned>(max_date.day())));
        }


@@ 194,7 194,7 @@ namespace gui
        return date::year(year) / date::month(month) / date::day(day);
    }

    const YearMonthDay EventDateItem::getChosenDate()
    const calendar::YearMonthDay EventDateItem::getChosenDate()
    {
        return validateDate();
    }

M module-apps/application-calendar/widgets/EventDateItem.hpp => module-apps/application-calendar/widgets/EventDateItem.hpp +2 -2
@@ 24,12 24,12 @@ namespace gui
        void buildInterface();
        void applyItemSpecificProperties(gui::Text *item);
        void applyCallbacks();
        YearMonthDay validateDate();
        calendar::YearMonthDay validateDate();

      public:
        EventDateItem();

        const YearMonthDay getChosenDate();
        const calendar::YearMonthDay getChosenDate();
        // virtual methods from Item
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
    };

M module-apps/application-calendar/widgets/EventTimeItem.cpp => module-apps/application-calendar/widgets/EventTimeItem.cpp +3 -3
@@ 433,9 433,9 @@ namespace gui
        }
    }

    TimePoint EventTimeItem::calculateEventTime(YearMonthDay date,
                                                std::chrono::hours hours,
                                                std::chrono::minutes minutes)
    calendar::TimePoint EventTimeItem::calculateEventTime(calendar::YearMonthDay date,
                                                          std::chrono::hours hours,
                                                          std::chrono::minutes minutes)
    {
        return TimePointFromYearMonthDay(date) + hours + minutes;
    }

M module-apps/application-calendar/widgets/EventTimeItem.hpp => module-apps/application-calendar/widgets/EventTimeItem.hpp +3 -1
@@ 43,7 43,9 @@ namespace gui
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);
        TimePoint calculateEventTime(YearMonthDay date, std::chrono::hours hours, std::chrono::minutes minutes);
        calendar::TimePoint calculateEventTime(calendar::YearMonthDay date,
                                               std::chrono::hours hours,
                                               std::chrono::minutes minutes);

      public:
        EventTimeItem(const std::string &description,

M module-apps/application-calendar/widgets/MonthBox.cpp => module-apps/application-calendar/widgets/MonthBox.cpp +1 -1
@@ 58,7 58,7 @@ namespace gui
        auto mainWindow = dynamic_cast<CalendarMainWindow *>(parent);
        if (mainWindow->returnedFromWindow) {
            focusChangedCallback = [=](Item &item) {
                YearMonthDay date = monthFilterValue.year() / monthFilterValue.month() / date::last;
                calendar::YearMonthDay date = monthFilterValue.year() / monthFilterValue.month() / date::last;
                if (unsigned(date.day()) < mainWindow->dayFocusedBefore) {
                    setFocusOnElement(unsigned(date.day()) - 1);
                }

M module-apps/application-calendar/windows/AllEventsWindow.cpp => module-apps/application-calendar/windows/AllEventsWindow.cpp +0 -1
@@ 34,7 34,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));

M module-apps/application-calendar/windows/AllEventsWindow.hpp => module-apps/application-calendar/windows/AllEventsWindow.hpp +1 -1
@@ 16,7 16,7 @@ namespace gui
        gui::Image *leftArrowImage   = nullptr;
        gui::Image *newDayEventImage = nullptr;

        TimePoint dateFilter                           = TimePointNow();
        calendar::TimePoint dateFilter                 = TimePointNow();
        gui::ListView *allEventsList                   = nullptr;
        std::shared_ptr<AllEventsModel> allEventsModel = nullptr;


M module-apps/application-calendar/windows/CalendarMainWindow.cpp => module-apps/application-calendar/windows/CalendarMainWindow.cpp +8 -8
@@ 100,9 100,9 @@ namespace gui
            }
            case KeyCode::KEY_LEFT: {
                LOG_DEBUG("Call borderCallback -> go to the previous element");
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::prev(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::prev(it)));
                auto it = std::prev(monthBox->getNavigationFocusedItem());
                if (it != monthBox->children.end() && (*it)->isActive()) {
                    monthBox->setFocusItem(*it);
                }
                else {
                    monthBox->setFocusOnLastElement();


@@ 111,9 111,9 @@ namespace gui
            }
            case KeyCode::KEY_RIGHT: {
                LOG_DEBUG("Call borderCallback -> go to the next element");
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::next(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::next(it)));
                auto it = std::next(monthBox->getNavigationFocusedItem());
                if (it != monthBox->children.end() && (*it)->isActive()) {
                    monthBox->setFocusItem(*it);
                }
                else {
                    monthBox->setFocusOnElement(0);


@@ 197,8 197,8 @@ namespace gui

    void CalendarMainWindow::filterRequest()
    {
        YearMonthDay date_from = actualDate.year() / actualDate.month() / 1;
        YearMonthDay date_till = date_from + date::months{1};
        calendar::YearMonthDay date_from = actualDate.year() / actualDate.month() / 1;
        calendar::YearMonthDay date_till = date_from + date::months{1};
        auto filter_from       = TimePointFromYearMonthDay(date_from);
        auto filter_till       = TimePointFromYearMonthDay(date_till);
        LOG_DEBUG("filter:  %s", TimePointToString(filter_till).c_str());

M module-apps/application-calendar/windows/CustomRepeatWindow.cpp => module-apps/application-calendar/windows/CustomRepeatWindow.cpp +0 -1
@@ 28,7 28,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));


M module-apps/application-calendar/windows/DayEventsWindow.cpp => module-apps/application-calendar/windows/DayEventsWindow.cpp +0 -1
@@ 64,7 64,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));

M module-apps/application-calendar/windows/DayEventsWindow.hpp => module-apps/application-calendar/windows/DayEventsWindow.hpp +1 -1
@@ 19,7 19,7 @@ namespace gui
    class DayEventsWindow : public gui::AppWindow
    {
        std::string dayMonthTitle;
        TimePoint filterFrom;
        calendar::TimePoint filterFrom;
        gui::Image *leftArrowImage                               = nullptr;
        gui::Image *newDayEventImage                             = nullptr;
        gui::ListView *dayEventsList                             = nullptr;

M module-apps/application-calendar/windows/EventDetailWindow.cpp => module-apps/application-calendar/windows/EventDetailWindow.cpp +0 -1
@@ 28,7 28,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::LEFT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-calendar/windows/EventReminderWindow.cpp => module-apps/application-calendar/windows/EventReminderWindow.cpp +11 -4
@@ 38,14 38,21 @@ namespace gui
        buildInterface();
    }

    top_bar::Configuration EventReminderWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        using namespace top_bar;
        appConfiguration.enable({Indicator::Signal,
                                 Indicator::Time,
                                 Indicator::Battery,
                                 Indicator::SimCard,
                                 Indicator::NetworkAccessTechnology});
        return appConfiguration;
    }

    void EventReminderWindow::buildInterface()
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
        bottomBar->setBorderColor(ColorNoColor);

M module-apps/application-calendar/windows/EventReminderWindow.hpp => module-apps/application-calendar/windows/EventReminderWindow.hpp +1 -0
@@ 42,6 42,7 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;
        auto handleSwitchData(SwitchData *data) -> bool override;
    };


M module-apps/application-calendar/windows/NewEditEventWindow.cpp => module-apps/application-calendar/windows/NewEditEventWindow.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +6 -0
@@ 33,6 33,12 @@ namespace app
    ApplicationCall::ApplicationCall(std::string name, std::string parent, StartInBackground startInBackground)
        : Application(name, parent, startInBackground, app::call_stack_size)
    {
        using namespace gui::top_bar;
        topBarManager->enableIndicators({Indicator::Signal,
                                         Indicator::Time,
                                         Indicator::Battery,
                                         Indicator::SimCard,
                                         Indicator::NetworkAccessTechnology});
        addActionReceiver(manager::actions::Call, [this](auto &&data) {
            switchWindow(window::name_call, std::forward<decltype(data)>(data));
            return msgHandled();

M module-apps/application-call/windows/CallWindow.cpp => module-apps/application-call/windows/CallWindow.cpp +0 -4
@@ 58,10 58,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::BATTERY, true);
        topBar->setActive(gui::TopBar::Elements::SIGNAL, true);
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setActive(BottomBar::Side::RIGHT, true);


M module-apps/application-call/windows/EnterNumberWindow.cpp => module-apps/application-call/windows/EnterNumberWindow.cpp +0 -4
@@ 58,10 58,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("common_add"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get("app_call_clear"));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::TIME, true);

        numberLabel = new gui::Label(this, numberLabel::x, numberLabel::y, numberLabel::w, numberLabel::h);
        numberLabel->setPenWidth(numberLabel::borderW);
        numberLabel->setFont(style::window::font::largelight);

M module-apps/application-calllog/windows/CallLogDetailsWindow.cpp => module-apps/application-calllog/windows/CallLogDetailsWindow.cpp +0 -2
@@ 82,8 82,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::call));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        // NOTE: height of all labels is set using decorators

        // Information

M module-apps/application-calllog/windows/CallLogMainWindow.cpp => module-apps/application-calllog/windows/CallLogMainWindow.cpp +0 -2
@@ 47,8 47,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        list = new gui::ListView(this, mainWindow::x, mainWindow::y, mainWindow::w, mainWindow::h, calllogModel);

        setFocusItem(list);

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +24 -4
@@ 8,6 8,7 @@
#include "windows/MenuWindow.hpp"
#include "windows/PinLockWindow.hpp"
#include "windows/PowerOffWindow.hpp"
#include "windows/DeadBatteryWindow.hpp"
#include "windows/LockedInfoWindow.hpp"
#include "windows/Reboot.hpp"
#include "windows/Update.hpp"


@@ 37,6 38,12 @@ namespace app
    ApplicationDesktop::ApplicationDesktop(std::string name, std::string parent, StartInBackground startInBackground)
        : Application(name, parent, startInBackground), lockHandler(this)
    {
        using namespace gui::top_bar;
        topBarManager->enableIndicators({Indicator::Signal,
                                         Indicator::Time,
                                         Indicator::Battery,
                                         Indicator::SimCard,
                                         Indicator::NetworkAccessTechnology});
        busChannels.push_back(sys::BusChannels::ServiceDBNotifications);

        addActionReceiver(app::manager::actions::RequestPin, [this](auto &&data) {


@@ 88,6 95,11 @@ namespace app
            handleLowBatteryNotification(std::move(data));
            return msgHandled();
        });

        addActionReceiver(app::manager::actions::SystemBrownout, [this](auto &&data) {
            switchWindow(app::window::name::dead_battery, std::move(data));
            return msgHandled();
        });
    }

    ApplicationDesktop::~ApplicationDesktop()


@@ 317,11 329,15 @@ namespace app
            std::make_shared<sdesktop::UpdateOsMessage>(updateos::UpdateMessageType::UpdateCheckForUpdateOnce);
        sys::Bus::SendUnicast(msgToSend, service::name::service_desktop, this);

        settings->registerValueChange(settings::SystemProperties::activeSim,
                                      [this](std::string value) { activeSimChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::activeSim,
            [this](std::string value) { activeSimChanged(value); },
            settings::SettingsScope::Global);
        Store::GSM::get()->selected = Store::GSM::SIM::NONE;
        settings->registerValueChange(settings::SystemProperties::lockPassHash,
                                      [this](std::string value) { lockPassHashChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassHashChanged(value); },
            settings::SettingsScope::Global);

        return sys::ReturnCodes::Success;
    }


@@ 329,6 345,7 @@ namespace app
    sys::ReturnCodes ApplicationDesktop::DeinitHandler()
    {
        LOG_INFO("DeinitHandler");
        settings->unregisterValueChange();
        return sys::ReturnCodes::Success;
    }



@@ 347,6 364,9 @@ namespace app
        windowsFactory.attach(desktop_poweroff, [](Application *app, const std::string newname) {
            return std::make_unique<gui::PowerOffWindow>(app);
        });
        windowsFactory.attach(dead_battery, [](Application *app, const std::string newname) {
            return std::make_unique<gui::DeadBatteryWindow>(app);
        });
        windowsFactory.attach(desktop_locked, [](Application *app, const std::string newname) {
            return std::make_unique<gui::LockedInfoWindow>(app);
        });

M module-apps/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/ApplicationDesktop.hpp +2 -1
@@ 107,7 107,8 @@ namespace app
                     manager::actions::ShowMMIPush,
                     manager::actions::ShowMMIResult,
                     manager::actions::DisplayCMEError,
                     manager::actions::DisplayLowBatteryNotification}};
                     manager::actions::DisplayLowBatteryNotification,
                     manager::actions::SystemBrownout}};
        }
    };


M module-apps/application-desktop/CMakeLists.txt => module-apps/application-desktop/CMakeLists.txt +1 -0
@@ 27,6 27,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/MenuWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/PowerOffWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/DeadBatteryWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/LockedInfoWindow.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/windows/Reboot.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/Update.cpp"

A module-apps/application-desktop/windows/DeadBatteryWindow.cpp => module-apps/application-desktop/windows/DeadBatteryWindow.cpp +53 -0
@@ 0,0 1,53 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DeadBatteryWindow.hpp"
#include "InputEvent.hpp"
#include "gui/widgets/Image.hpp"
#include "gui/widgets/BottomBar.hpp"
#include "gui/widgets/TopBar.hpp"
#include "log/log.hpp"
#include <application-desktop/windows/Names.hpp>
#include <service-appmgr/model/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

namespace gui
{
    namespace
    {
        constexpr inline auto SHUTDOWN_TIMER_MS = 500;
        constexpr inline auto IMG_POS_X         = 176;
        constexpr inline auto IMG_POS_Y         = 250;
    } // namespace

    DeadBatteryWindow::DeadBatteryWindow(app::Application *app) : AppWindow(app, app::window::name::dead_battery)
    {
        buildInterface();
    }

    void DeadBatteryWindow::rebuild()
    {
        destroyInterface();
        buildInterface();
    }

    void DeadBatteryWindow::buildInterface()
    {
        AppWindow::buildInterface();
        bottomBar->setVisible(false);
        topBar->setVisible(false);

        image = new gui::Image(this, IMG_POS_X, IMG_POS_Y, 0, 0, "dead_battery_W_G");
    }

    void DeadBatteryWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        app::manager::Controller::sendAction(application, app::manager::actions::CloseSystem);
    }

    void DeadBatteryWindow::destroyInterface()
    {
        erase();
        image = nullptr;
    }
} /* namespace gui */

A module-apps/application-desktop/windows/DeadBatteryWindow.hpp => module-apps/application-desktop/windows/DeadBatteryWindow.hpp +24 -0
@@ 0,0 1,24 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <vector>
#include "AppWindow.hpp"

namespace gui
{
    class DeadBatteryWindow : public AppWindow
    {
      public:
        explicit DeadBatteryWindow(app::Application *app);
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        gui::Image *image = nullptr;
    };

} /* namespace gui */

M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +20 -6
@@ 35,8 35,6 @@ namespace gui
        AppWindow::buildInterface();

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        topBar->setActive(
            {{TopBar::Elements::SIGNAL, true}, {TopBar::Elements::LOCK, true}, {TopBar::Elements::BATTERY, true}});

        using namespace style::desktop;



@@ 75,6 73,20 @@ namespace gui
        notifications = nullptr;
    }

    top_bar::Configuration DesktopMainWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        auto app            = getAppDesktop();
        const auto isLocked = app->lockHandler.isScreenLocked();
        updateTopBarConfiguration(isLocked, appConfiguration);
        return appConfiguration;
    }

    void DesktopMainWindow::updateTopBarConfiguration(bool isScreenLocked, top_bar::Configuration &configuration)
    {
        configuration.set(top_bar::Indicator::Lock, isScreenLocked);
        configuration.set(top_bar::Indicator::Time, !isScreenLocked);
    }

    DesktopMainWindow::DesktopMainWindow(app::Application *app) : AppWindow(app, app::window::name::desktop_main_window)
    {
        buildInterface();


@@ 89,13 101,18 @@ namespace gui
    void DesktopMainWindow::setVisibleState()
    {
        auto app = getAppDesktop();
        applyToTopBar([isLocked = app->lockHandler.isScreenLocked()](top_bar::Configuration configuration) {
            updateTopBarConfiguration(isLocked, configuration);
            return configuration;
        });

        if (app->lockHandler.isScreenLocked()) {
            bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_desktop_unlock"));
            bottomBar->setActive(BottomBar::Side::RIGHT, false);
            bottomBar->setText(BottomBar::Side::LEFT,
                               utils::localize.get("app_desktop_emergency"),
                               app->lockHandler.isScreenBlocked());
            topBar->setActive(TopBar::Elements::LOCK, true);

            inputCallback = nullptr;
            setFocusItem(nullptr);
            buildNotifications(app);


@@ 104,8 121,6 @@ namespace gui
                std::make_shared<TimersProcessingStopMessage>(), service::name::service_time, application);
        }
        else {
            topBar->setActive(TopBar::Elements::LOCK, false);

            if (!buildNotifications(app)) {
                LOG_ERROR("Couldn't fit in all notifications");
            }


@@ 146,7 161,6 @@ namespace gui
            if (inputEvent.is(KeyCode::KEY_PND)) {
                app->lockHandler.lockScreen();
                setVisibleState();
                application->setSuspendFlag(true);
                return true;
            }
            // long press of '0' key is translated to '+'

M module-apps/application-desktop/windows/DesktopMainWindow.hpp => module-apps/application-desktop/windows/DesktopMainWindow.hpp +3 -0
@@ 81,11 81,14 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;

        bool updateTime(const UTF8 &timeStr) override;
        bool updateTime(const uint32_t &timestamp, bool mode24H) override;

      private:
        void invalidate() noexcept;
        static void updateTopBarConfiguration(bool isScreenLocked, top_bar::Configuration &configuration);

        gui::KeyInputMappedTranslation translator;
    };

M module-apps/application-desktop/windows/LockWindow.cpp => module-apps/application-desktop/windows/LockWindow.cpp +0 -1
@@ 14,7 14,6 @@ namespace gui
    void LockWindow::build()
    {
        buildBottomBar();
        buildTopBar();
        buildTitleBar();
        buildInfoTexts();
    }

M module-apps/application-desktop/windows/LockWindow.hpp => module-apps/application-desktop/windows/LockWindow.hpp +0 -1
@@ 58,7 58,6 @@ namespace gui
      protected:
        virtual void buildBottomBar();
        virtual void buildTitleBar() = 0;
        virtual void buildTopBar()   = 0;

      private:
        [[nodiscard]] auto getText(TextType type) noexcept -> gui::Text *;

M module-apps/application-desktop/windows/LockedInfoWindow.cpp => module-apps/application-desktop/windows/LockedInfoWindow.cpp +7 -4
@@ 34,10 34,6 @@ void LockedInfoWindow::setVisibleState()
    bottomBar->setActive(BottomBar::Side::LEFT, true);
    bottomBar->setActive(BottomBar::Side::CENTER, false);
    bottomBar->setActive(BottomBar::Side::RIGHT, true);

    topBar->setActive(TopBar::Elements::LOCK, true);
    topBar->setActive(TopBar::Elements::BATTERY, true);
    topBar->setActive(TopBar::Elements::SIGNAL, true);
}

bool LockedInfoWindow::onInput(const InputEvent &inputEvent)


@@ 61,6 57,13 @@ void LockedInfoWindow::rebuild()
    buildInterface();
}

top_bar::Configuration LockedInfoWindow::configureTopBar(top_bar::Configuration appConfiguration)
{
    appConfiguration.enable(top_bar::Indicator::Lock);
    appConfiguration.disable(top_bar::Indicator::Time);
    return appConfiguration;
}

void LockedInfoWindow::buildInterface()
{
    namespace lock_style = style::window::pin_lock;

M module-apps/application-desktop/windows/LockedInfoWindow.hpp => module-apps/application-desktop/windows/LockedInfoWindow.hpp +1 -0
@@ 25,5 25,6 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;
    };
} /* namespace gui */

M module-apps/application-desktop/windows/MenuWindow.cpp => module-apps/application-desktop/windows/MenuWindow.cpp +0 -3
@@ 149,9 149,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        auto app = dynamic_cast<app::ApplicationDesktop *>(application);
        assert(app);


M module-apps/application-desktop/windows/MmiPullWindow.cpp => module-apps/application-desktop/windows/MmiPullWindow.cpp +0 -2
@@ 37,8 37,6 @@ MmiPullWindow::MmiPullWindow(app::Application *app, const std::string &name) : g
{
    AppWindow::buildInterface();

    topBar->setActive(TopBar::Elements::TIME, true);
    topBar->setActive(TopBar::Elements::SIM, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_desktop_replay"));
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
    text = new Text(

M module-apps/application-desktop/windows/MmiPushWindow.cpp => module-apps/application-desktop/windows/MmiPushWindow.cpp +0 -2
@@ 30,8 30,6 @@ namespace style::desktop
MmiPushWindow::MmiPushWindow(app::Application *app, const std::string &name) : gui::AppWindow(app, name)
{
    AppWindow::buildInterface();
    topBar->setActive(TopBar::Elements::TIME, true);
    topBar->setActive(TopBar::Elements::SIM, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
    icon = new Image(this, style::desktop::image::x, style::desktop::image::y, "");
    icon->set("info_big_circle_W_G");

M module-apps/application-desktop/windows/Names.hpp => module-apps/application-desktop/windows/Names.hpp +9 -8
@@ 7,13 7,14 @@
namespace app::window::name
{
    inline constexpr auto desktop_main_window = gui::name::window::main_window;
    inline constexpr auto desktop_menu        = "MenuWindow";
    inline constexpr auto desktop_reboot      = "Reboot";
    inline constexpr auto desktop_poweroff    = "PowerOffWindow";
    inline constexpr auto desktop_pin_lock    = "PinLockWindow";
    inline constexpr auto desktop_locked      = "LockedInfoWindow";
    inline constexpr auto desktop_update      = "Update";
    inline constexpr auto desktop_mmi_pull    = "MmiPullWindow";
    inline constexpr auto desktop_mmi_push    = "MmiPushWindow";
    inline constexpr auto desktop_menu         = "MenuWindow";
    inline constexpr auto desktop_reboot       = "Reboot";
    inline constexpr auto desktop_poweroff     = "PowerOffWindow";
    inline constexpr auto dead_battery         = "DeadBatteryWindow";
    inline constexpr auto desktop_pin_lock     = "PinLockWindow";
    inline constexpr auto desktop_locked       = "LockedInfoWindow";
    inline constexpr auto desktop_update       = "Update";
    inline constexpr auto desktop_mmi_pull     = "MmiPullWindow";
    inline constexpr auto desktop_mmi_push     = "MmiPushWindow";
    inline constexpr auto desktop_mmi_internal = "MmiInternalMsgWindow";
}; // namespace app::window::name

M module-apps/application-desktop/windows/PinLockBaseWindow.cpp => module-apps/application-desktop/windows/PinLockBaseWindow.cpp +6 -7
@@ 32,7 32,12 @@ namespace gui
        }
        return std::string{};
    }

    top_bar::Configuration PinLockBaseWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        appConfiguration.enable(top_bar::Indicator::Lock);
        appConfiguration.disable(top_bar::Indicator::Time);
        return appConfiguration;
    }
    void PinLockBaseWindow::restore() noexcept
    {
        LockWindow::restore();


@@ 91,10 96,4 @@ namespace gui
        title->setPenWidth(2);
    }

    void PinLockBaseWindow::buildTopBar()
    {
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::LOCK, true);
    }
} // namespace gui

M module-apps/application-desktop/windows/PinLockBaseWindow.hpp => module-apps/application-desktop/windows/PinLockBaseWindow.hpp +3 -1
@@ 12,6 12,9 @@ namespace gui
      public:
        PinLockBaseWindow(app::Application *app, std::string name) : LockWindow(app, name)
        {}

        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;

        void buildImages(const std::string &lockImg, const std::string &infoImg);
        [[nodiscard]] auto getToken(Token token) const -> std::string;
        void restore() noexcept override;


@@ 25,6 28,5 @@ namespace gui
      private:
        void buildBottomBar() override;
        void buildTitleBar() override;
        void buildTopBar() override;
    };
} // namespace gui

M module-apps/application-desktop/windows/PowerOffWindow.cpp => module-apps/application-desktop/windows/PowerOffWindow.cpp +2 -19
@@ 4,7 4,6 @@
#include "InputEvent.hpp"
#include "gui/widgets/BottomBar.hpp"
#include "gui/widgets/TopBar.hpp"
#include "GuiTimer.hpp"
#include "log/log.hpp"

// module-utils


@@ 15,6 14,7 @@

// services
#include <service-appmgr/model/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

#include "service-cellular/ServiceCellular.hpp"
#include <Style.hpp>


@@ 142,7 142,7 @@ namespace gui
            infoLabel->setVisible(false);

            application->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
            scheduleSystemShutdown();
            app::manager::Controller::sendAction(application, app::manager::actions::CloseSystem);
            return true;
        };



@@ 160,23 160,6 @@ namespace gui
        };
    }

    // Temporary solution for shutting down the system.
    // The former solution removed from service-gui during its refactor.
    // To be reimplemented in SystemManager in upcoming commits.
    void PowerOffWindow::scheduleSystemShutdown()
    {
        constexpr auto SystemShutdownDelayInMs = 500;
        auto powerOffTimer                     = std::make_unique<app::GuiTimer>("PowerOffTimer", application);
        powerOffTimer->setInterval(SystemShutdownDelayInMs);
        timerCallback = [this](Item &, Timer &timer) {
            detachTimer(timer);
            sys::SystemManager::CloseSystem(application);
            return true;
        };
        powerOffTimer->start();
        application->connect(std::move(powerOffTimer), this);
    }

    void PowerOffWindow::destroyInterface()
    {
        erase();

M module-apps/application-desktop/windows/PowerOffWindow.hpp => module-apps/application-desktop/windows/PowerOffWindow.hpp +0 -3
@@ 27,9 27,6 @@ namespace gui
        gui::Image *powerImage     = nullptr;
        gui::Image *powerDownImage = nullptr;
        State state                = State::Return;

        void scheduleSystemShutdown();

      public:
        PowerOffWindow(app::Application *app);
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

M module-apps/application-meditation/windows/MeditationListViewWindows.cpp => module-apps/application-meditation/windows/MeditationListViewWindows.cpp +0 -2
@@ 64,7 64,6 @@ void MeditationOptionsWindow::buildInterface()
    MeditationListViewWindow::buildInterface();
    setTitle(utils::localize.get("common_options"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::Switch));
    topBar->setActive(TopBar::Elements::TIME, true);
}

PreparationTimeWindow::PreparationTimeWindow(app::Application *app)


@@ 79,5 78,4 @@ void PreparationTimeWindow::buildInterface()
    MeditationListViewWindow::buildInterface();
    setTitle(utils::localize.get("app_meditation_preparation_time"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
    topBar->setActive(TopBar::Elements::TIME, true);
}

M module-apps/application-meditation/windows/MeditationTimerWindow.cpp => module-apps/application-meditation/windows/MeditationTimerWindow.cpp +5 -1
@@ 112,7 112,11 @@ auto MeditationTimerWindow::onInput(const InputEvent &inputEvent) -> bool

void MeditationTimerWindow::setWidgetVisible(bool tBar, bool bBar, bool counter)
{
    topBar->setActive(TopBar::Elements::TIME, tBar);
    applyToTopBar([tBar](top_bar::Configuration configuration) {
        configuration.set(top_bar::Indicator::Time, tBar);
        return configuration;
    });

    title->setVisible(tBar);
    bottomBar->setActive(BottomBar::Side::CENTER, bBar);
    bottomBar->setActive(BottomBar::Side::LEFT, bBar);

M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +0 -2
@@ 64,8 64,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_messages_title_main"));

        leftArrowImage  = new gui::Image(this, 30, 62, 0, 0, "arrow_left");

M module-apps/application-messages/windows/NewMessage.cpp => module-apps/application-messages/windows/NewMessage.cpp +0 -3
@@ 188,9 188,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::SIGNAL, false);

        setTitle(utils::localize.get("sms_title_message"));


M module-apps/application-messages/windows/SMSTemplatesWindow.cpp => module-apps/application-messages/windows/SMSTemplatesWindow.cpp +0 -2
@@ 44,8 44,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::use));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        namespace style = style::messages::templates::list;

        list = new gui::ListView(this, style::x, style::y, style::w, style::h, smsTemplateModel);

M module-apps/application-messages/windows/SMSThreadViewWindow.cpp => module-apps/application-messages/windows/SMSThreadViewWindow.cpp +0 -1
@@ 29,7 29,6 @@ namespace gui
    {
        AppWindow::buildInterface();
        setTitle(utils::localize.get("app_messages_title_main"));
        topBar->setActive(TopBar::Elements::TIME, true);
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));


M module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp => module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp +0 -2
@@ 54,8 54,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_music_player_play"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        songsList = new gui::ListView(this,
                                      musicPlayerStyle::allSongsWindow::x,
                                      musicPlayerStyle::allSongsWindow::y,

M module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp => module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp +0 -2
@@ 33,8 33,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get("app_music_player_music_library"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get("app_music_player_quit"));

        topBar->setActive(TopBar::Elements::TIME, true);

        img = new gui::Image(this, noteImg::x, noteImg::y, "note");

        text = new Text(this, infoText::x, infoText::y, infoText::w, infoText::h);

M module-apps/application-notes/windows/NoteEditWindow.cpp => module-apps/application-notes/windows/NoteEditWindow.cpp +0 -2
@@ 85,8 85,6 @@ namespace app::notes
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));

        topBar->setActive(gui::TopBar::Elements::TIME, true);

        setFocusItem(edit);
    }


M module-apps/application-notes/windows/NoteMainWindow.cpp => module-apps/application-notes/windows/NoteMainWindow.cpp +0 -1
@@ 54,7 54,6 @@ namespace app::notes
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(::style::strings::common::open));
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        namespace windowStyle = app::notes::style::main_window;
        leftArrowImage        = new gui::Image(this,

M module-apps/application-notes/windows/NotePreviewWindow.cpp => module-apps/application-notes/windows/NotePreviewWindow.cpp +0 -2
@@ 79,8 79,6 @@ namespace app::notes
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));

        topBar->setActive(gui::TopBar::Elements::TIME, true);

        setFocusItem(note);
    }


M module-apps/application-phonebook/windows/PhonebookContactDetails.cpp => module-apps/application-phonebook/windows/PhonebookContactDetails.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    void PhonebookContactDetails::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::TIME, true);

        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-phonebook/windows/PhonebookIceContacts.cpp => module-apps/application-phonebook/windows/PhonebookIceContacts.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::TIME, true);
        setTitle(utils::localize.get("app_phonebook_ice_contacts_title"));

        contactsListIce = new gui::ListView(this,

M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp => module-apps/application-phonebook/windows/PhonebookMainWindow.cpp +0 -1
@@ 30,7 30,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::TIME, true);
        setTitle(utils::localize.get("app_phonebook_title_main"));
        leftArrowImage  = new gui::Image(this,
                                        phonebookStyle::mainWindow::leftArrowImage::x,

M module-apps/application-phonebook/windows/PhonebookSearch.cpp => module-apps/application-phonebook/windows/PhonebookSearch.cpp +0 -1
@@ 16,7 16,6 @@ namespace gui
    void PhonebookSearch::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_phonebook_title_main"));


M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp => module-apps/application-phonebook/windows/PhonebookSearchResults.cpp +0 -2
@@ 40,8 40,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("common_results_prefix"));
    }


M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +42 -15
@@ 5,7 5,8 @@

#include "windows/AddDeviceWindow.hpp"
#include "windows/AllDevicesWindow.hpp"
#include "windows/APNSettingsWindow.hpp"
#include "windows/ApnSettingsWindow.hpp"
#include "windows/ApnOptionsWindow.hpp"
#include "windows/BluetoothWindow.hpp"
#include "windows/SettingsMainWindow.hpp"
#include "windows/DisplayAndKeypadWindow.hpp"


@@ 28,6 29,7 @@
#include "windows/QuotesOptionsWindow.hpp"
#include "windows/ChangePasscodeWindow.hpp"
#include "windows/SystemMainWindow.hpp"
#include "windows/NewApnWindow.hpp"

#include "Dialog.hpp"



@@ 37,9 39,9 @@
#include <service-bluetooth/service-bluetooth/messages/Status.hpp>
#include <service-bluetooth/messages/BondedDevices.hpp>
#include <service-bluetooth/messages/DeviceName.hpp>
#include <application-settings-new/data/BondedDevicesData.hpp>
#include <application-settings-new/data/PhoneNameData.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>
#include <application-settings-new/data/ApnListData.hpp>
#include <application-settings-new/data/BondedDevicesData.hpp>
#include <application-settings-new/data/PhoneNameData.hpp>
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
#include <service-db/Settings.hpp>


@@ 66,17 68,10 @@ namespace app
            Store::GSM::get()->sim == selectedSim) {
            selectedSimNumber = CellularServiceAPI::GetOwnNumber(this);
        }
        settings->registerValueChange(settings::operators_on,
                                      [this](const std::string &value) { operatorOnChanged(value); });

        settings->registerValueChange(::settings::Cellular::volte_on,
                                      [this](const std::string &value) { volteChanged(value); });
    }

    ApplicationSettingsNew::~ApplicationSettingsNew()
    {
        settings->unregisterValueChange(settings::operators_on);
        settings->unregisterValueChange(::settings::Cellular::volte_on);
    }

    // Invoked upon receiving data message


@@ 152,13 147,29 @@ namespace app
            return sys::MessageNone{};
        });

        connect(typeid(CellularGetAPNResponse), [&](sys::Message *msg) {
            if (gui::window::name::apn_settings == getCurrentWindow()->getName()) {
                auto apns = dynamic_cast<CellularGetAPNResponse *>(msg);
                if (apns != nullptr) {
                    auto apnsData = std::make_unique<gui::ApnListData>(apns->getAPNs());
                    switchWindow(gui::window::name::apn_settings, std::move(apnsData));
                }
            }
            return sys::MessageNone{};
        });

        createUserInterface();

        setActiveWindow(gui::name::window::main_window);

        settings->registerValueChange(::settings::SystemProperties::lockPassHash, [this](std::string value) {
            lockPassHash = utils::getNumericValue<unsigned int>(value);
        });
        settings->registerValueChange(settings::operators_on,
                                      [this](const std::string &value) { operatorOnChanged(value); });
        settings->registerValueChange(::settings::Cellular::volte_on,
                                      [this](const std::string &value) { volteChanged(value); });
        settings->registerValueChange(
            ::settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassHash = utils::getNumericValue<unsigned int>(value); },
            ::settings::SettingsScope::Global);

        return ret;
    }


@@ 210,7 221,10 @@ namespace app
                app, static_cast<ApplicationSettingsNew *>(app), static_cast<ApplicationSettingsNew *>(app));
        });
        windowsFactory.attach(gui::window::name::apn_settings, [](Application *app, const std::string &name) {
            return std::make_unique<gui::APNSettingsWindow>(app);
            return std::make_unique<gui::ApnSettingsWindow>(app);
        });
        windowsFactory.attach(gui::window::name::apn_options, [](Application *app, const std::string &name) {
            return std::make_unique<gui::ApnOptionsWindow>(app);
        });
        windowsFactory.attach(gui::window::name::messages, [](Application *app, const std::string &name) {
            return std::make_unique<gui::MessagesWindow>(app);


@@ 233,9 247,18 @@ namespace app
        windowsFactory.attach(gui::window::name::security, [](Application *app, const std::string &name) {
            return std::make_unique<gui::SecurityMainWindow>(app);
        });
        windowsFactory.attach(gui::window::name::change_passcode, [](Application *app, const std::string &name) {
            return std::make_unique<gui::ChangePasscodeWindow>(app);
        });
        windowsFactory.attach(gui::window::name::dialog_confirm, [](Application *app, const std::string &name) {
            return std::make_unique<gui::DialogConfirm>(app, gui::window::name::dialog_confirm);
        });
        windowsFactory.attach(gui::window::name::system, [](Application *app, const std::string &name) {
            return std::make_unique<gui::SystemMainWindow>(app);
        });
        windowsFactory.attach(gui::window::name::new_apn, [](Application *app, const std::string &name) {
            return std::make_unique<gui::NewApnWindow>(app);
        });
    }

    void ApplicationSettingsNew::destroyUserInterface()


@@ 258,17 281,20 @@ namespace app

    void ApplicationSettingsNew::operatorOnChanged(const std::string &value)
    {
        LOG_DEBUG("[ApplicationSettingsNew::operatorOnChanged] value=%s", value.c_str());
        if (!value.empty()) {
            operatorsOn = utils::getNumericValue<bool>(value);
        }
    }
    bool ApplicationSettingsNew::getOperatorsOn() const noexcept
    {
        LOG_DEBUG("[ApplicationSettingsNew::getOperatorsOn] %d", operatorsOn);
        return operatorsOn;
    }
    void ApplicationSettingsNew::setOperatorsOn(bool value)
    {
        operatorsOn = value;
        LOG_DEBUG("[ApplicationSettingsNew::setOperatorsOn] to %d", operatorsOn);
        settings->setValue(settings::operators_on, std::to_string(value));
    }



@@ 293,7 319,8 @@ namespace app
    void ApplicationSettingsNew::setLockPassHash(unsigned int value)
    {
        lockPassHash = value;
        settings->setValue(::settings::SystemProperties::lockPassHash, std::to_string(value));
        settings->setValue(
            ::settings::SystemProperties::lockPassHash, std::to_string(value), ::settings::SettingsScope::Global);
    }

    auto ApplicationSettingsNew::getCurrentValues() -> settingsInterface::ScreenLightSettings::Values

M module-apps/application-settings-new/ApplicationSettings.hpp => module-apps/application-settings-new/ApplicationSettings.hpp +3 -0
@@ 17,6 17,7 @@ namespace gui::window::name

    inline constexpr auto network        = "Network";
    inline constexpr auto apn_settings   = "APNSettings";
    inline constexpr auto apn_options    = "APNOptions";
    inline constexpr auto phone_modes    = "PhoneModes";
    inline constexpr auto apps_and_tools = "AppsAndTools";
    inline constexpr auto security       = "Security";


@@ 55,6 56,8 @@ namespace gui::window::name
    inline constexpr auto about_your_pure = "AboutYourPure";
    inline constexpr auto certification   = "Certification";

    inline constexpr auto new_apn = "NewApn";

} // namespace gui::window::name

namespace app

M module-apps/application-settings-new/CMakeLists.txt => module-apps/application-settings-new/CMakeLists.txt +10 -1
@@ 15,13 15,17 @@ target_sources( ${PROJECT_NAME}

    PRIVATE
        ApplicationSettings.cpp
        models/ApnSettingsModel.cpp
        models/NewApnModel.cpp
        widgets/timeWidget.cpp
        widgets/ChangePasscodeLockHandler.cpp
        widgets/QuoteWidget.cpp
        widgets/ApnInputWidget.cpp
        windows/SettingsMainWindow.cpp
        windows/AddDeviceWindow.cpp
        windows/AllDevicesWindow.cpp
        windows/APNSettingsWindow.cpp
        windows/ApnSettingsWindow.cpp
        windows/ApnOptionsWindow.cpp
        windows/BaseSettingsWindow.cpp
        windows/BluetoothWindow.cpp
        windows/FontSizeWindow.cpp


@@ 42,12 46,16 @@ target_sources( ${PROJECT_NAME}
        windows/QuotesAddWindow.cpp
        windows/SecurityMainWindow.cpp
        windows/ChangePasscodeWindow.cpp
        windows/NewApnWindow.cpp
        widgets/SpinBox.cpp
        widgets/SpinBoxOptionSetting.cpp
        windows/SystemMainWindow.cpp

    PUBLIC
        ApplicationSettings.hpp
        widgets/ChangePasscodeLockHandler.hpp
        widgets/ApnInputWidget.hpp
        windows/NewApnWindow.hpp
        windows/SettingsMainWindow.hpp
        windows/BaseSettingsWindow.hpp
        windows/FontSizeWindow.hpp


@@ 61,6 69,7 @@ target_sources( ${PROJECT_NAME}
        widgets/SettingsStyle.hpp
        windows/AutolockWindow.hpp
        windows/WallpaperWindow.hpp
        windows/ChangePasscodeWindow.hpp
        windows/SystemMainWindow.hpp
)


A module-apps/application-settings-new/data/ApnListData.hpp => module-apps/application-settings-new/data/ApnListData.hpp +27 -0
@@ 0,0 1,27 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/PacketDataTypes.hpp>
#include <SwitchData.hpp>

#include <vector>

namespace gui
{

    class ApnListData : public SwitchData
    {
      public:
        explicit ApnListData(std::vector<std::shared_ptr<packet_data::APN::Config>> apns) : apns(std::move(apns))
        {}
        [[nodiscard]] auto getAPNs() const noexcept -> const std::vector<std::shared_ptr<packet_data::APN::Config>> &
        {
            return apns;
        }

      private:
        std::vector<std::shared_ptr<packet_data::APN::Config>> apns;
    };
} // namespace gui

M module-apps/application-settings-new/data/QuoteSwitchData.hpp => module-apps/application-settings-new/data/QuoteSwitchData.hpp +2 -2
@@ 3,9 3,9 @@

#pragma once

#include "application-settings-new/model/QuotesModel.hpp"
#include "application-settings-new/models/QuotesModel.hpp"

#include <module-gui/gui/SwitchData.hpp>
#include <SwitchData.hpp>
#include <json/json11.hpp>
#include <utility>


A module-apps/application-settings-new/data/SettingsInternals.hpp => module-apps/application-settings-new/data/SettingsInternals.hpp +30 -0
@@ 0,0 1,30 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <cstdint>

namespace settingsInternals
{
    enum class ListItemName
    {
        Name,
        APN,
        Proxy,
        Port,
        Username,
        Password,

        Server,
        MMSC,
        MmsProxy,
        MmsPort,
        MCC,
        MNC,
        AuthType,
        ApnType,
        ApnProtocol
    };

} // namespace settingsInternals

A module-apps/application-settings-new/data/SettingsItemData.hpp => module-apps/application-settings-new/data/SettingsItemData.hpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/service-cellular/PacketDataTypes.hpp>
#include <ListItem.hpp>
#include <SwitchData.hpp>

class ApnItemData : public gui::SwitchData
{
  public:
    ApnItemData(std::shared_ptr<packet_data::APN::Config> Apn) : apn(std::move(Apn)){};
    ApnItemData() : apn(nullptr){};

    auto getApn() -> std::shared_ptr<packet_data::APN::Config>
    {
        return apn;
    }

  private:
    std::shared_ptr<packet_data::APN::Config> apn;
};

A module-apps/application-settings-new/models/ApnSettingsModel.cpp => module-apps/application-settings-new/models/ApnSettingsModel.cpp +28 -0
@@ 0,0 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnSettingsModel.hpp"
#include <service-cellular/PacketDataCellularMessage.hpp>
#include <service-cellular/ServiceCellular.hpp>

ApnSettingsModel::ApnSettingsModel(app::Application *application) : application{application}
{}

void ApnSettingsModel::requestAPNList()
{
    sys::Bus::SendUnicast(std::make_shared<CellularGetAPNMessage>(), ServiceCellular::serviceName, application);
}

void ApnSettingsModel::saveAPN(std::shared_ptr<packet_data::APN::Config> apn)
{
    sys::Bus::SendUnicast(std::make_shared<CellularSetAPNMessage>(apn), ServiceCellular::serviceName, application);
}

void ApnSettingsModel::removeAPN(std::shared_ptr<packet_data::APN::Config> apn)
{}

void ApnSettingsModel::setAsDefaultAPN(std::shared_ptr<packet_data::APN::Config> apn)
{
    apn->apnType = packet_data::APN::APNType::Default;
    sys::Bus::SendUnicast(std::make_shared<CellularSetAPNMessage>(apn), ServiceCellular::serviceName, application);
}

A module-apps/application-settings-new/models/ApnSettingsModel.hpp => module-apps/application-settings-new/models/ApnSettingsModel.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/PacketDataTypes.hpp>
#include <module-apps/Application.hpp>

class ApnSettingsModel
{
  public:
    ApnSettingsModel(app::Application *application);

    void requestAPNList();
    void saveAPN(std::shared_ptr<packet_data::APN::Config> apn);
    void removeAPN(std::shared_ptr<packet_data::APN::Config> apn);
    void setAsDefaultAPN(std::shared_ptr<packet_data::APN::Config> apn);

  private:
    app::Application *application = nullptr;
};

A module-apps/application-settings-new/models/NewApnModel.cpp => module-apps/application-settings-new/models/NewApnModel.cpp +133 -0
@@ 0,0 1,133 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NewApnModel.hpp"

#include "application-settings-new/widgets/ApnInputWidget.hpp"

#include <ListView.hpp>
#include <time/ScopedTime.hpp>
#include <BottomBar.hpp>

NewApnModel::NewApnModel(app::Application *app) : application(app)
{}

auto NewApnModel::requestRecordsCount() -> unsigned int
{
    return internalData.size();
}

auto NewApnModel::getMinimalItemHeight() const -> unsigned int
{
    return style::settings::widget::apnInputWidget::h;
}

void NewApnModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    setupModel(offset, limit);
    list->onProviderDataUpdate();
}

auto NewApnModel::getItem(gui::Order order) -> gui::ListItem *
{
    return getRecord(order);
}

void NewApnModel::createData()
{
    auto app = application;

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Name,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::APN,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Username,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Password,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::AuthType,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::ApnType,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::ApnProtocol,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    for (auto item : internalData) {
        item->deleteByList = false;
    }
}

void NewApnModel::clearData()
{
    list->clear();

    eraseInternalData();

    createData();

    list->rebuildList();
}

void NewApnModel::saveData(std::shared_ptr<packet_data::APN::Config> apnRecord)
{
    for (auto item : internalData) {
        if (item->onSaveCallback) {
            item->onSaveCallback(apnRecord);
        }
    }
}

void NewApnModel::loadData(std::shared_ptr<packet_data::APN::Config> apnRecord)
{
    for (auto item : internalData) {
        if (item->onLoadCallback) {
            item->onLoadCallback(apnRecord);
        }
    }
}

void NewApnModel::apnDataChanged()
{
    for (auto item : internalData) {
        if (item->onEmptyCallback && !item->onEmptyCallback()) {
            application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::CENTER, true); // SAVE button
            return;
        }
    }
    application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::CENTER, false); // SAVE button
    return;
}

A module-apps/application-settings-new/models/NewApnModel.hpp => module-apps/application-settings-new/models/NewApnModel.hpp +35 -0
@@ 0,0 1,35 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsItemData.hpp"
#include "application-settings-new/widgets/ApnListItem.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "InternalModel.hpp"
#include "Application.hpp"

#include <ListItemProvider.hpp>

class NewApnModel : public app::InternalModel<gui::ApnListItem *>, public gui::ListItemProvider
{
    app::Application *application = nullptr;

  public:
    NewApnModel(app::Application *app);

    void clearData();
    void saveData(std::shared_ptr<packet_data::APN::Config> apnRecord);
    void loadData(std::shared_ptr<packet_data::APN::Config> apnRecord);

    void createData();

    [[nodiscard]] auto requestRecordsCount() -> unsigned int override;

    [[nodiscard]] auto getMinimalItemHeight() const -> unsigned int override;

    auto getItem(gui::Order order) -> gui::ListItem * override;

    void requestRecords(const uint32_t offset, const uint32_t limit) override;
    void apnDataChanged();
};

R module-apps/application-settings-new/model/QuotesModel.cpp => module-apps/application-settings-new/models/QuotesModel.cpp +2 -3
@@ 3,9 3,8 @@

#include "application-settings-new/windows/QuotesMainWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/model/QuotesRepository.hpp"
#include "application-settings-new/model/QuotesModel.hpp"
#include "application-settings-new/model/QuotesModel.hpp"
#include "QuotesRepository.hpp"
#include "QuotesModel.hpp"

#include <InputEvent.hpp>
#include <i18n/i18n.hpp>

R module-apps/application-settings-new/model/QuotesModel.hpp => module-apps/application-settings-new/models/QuotesModel.hpp +0 -0
R module-apps/application-settings-new/model/QuotesRepository.cpp => module-apps/application-settings-new/models/QuotesRepository.cpp +0 -3
@@ 1,9 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesRepository.hpp"

#include <module-utils/gsl/gsl_util>

R module-apps/application-settings-new/model/QuotesRepository.hpp => module-apps/application-settings-new/models/QuotesRepository.hpp +0 -0
A module-apps/application-settings-new/widgets/ApnInputWidget.cpp => module-apps/application-settings-new/widgets/ApnInputWidget.cpp +221 -0
@@ 0,0 1,221 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnInputWidget.hpp"
#include <Span.hpp>
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include <i18n/i18n.hpp>
#include <utility>

namespace gui
{
    ApnInputWidget::ApnInputWidget(settingsInternals::ListItemName listItemName,
                                   std::function<void(const UTF8 &)> bottomBarTemporaryMode,
                                   std::function<void()> bottomBarRestoreFromTemporaryMode,
                                   std::function<void()> selectSpecialCharacter,
                                   std::function<void()> contentChanged,
                                   unsigned int lines)
        : listItemName(listItemName), checkTextContent(std::move(contentChanged))
    {

        setMinimumSize(style::settings::widget::apnInputWidget::w,
                       style::settings::widget::apnInputWidget::title_label_h +
                           style::settings::widget::apnInputWidget::span_size +
                           style::settings::widget::apnInputWidget::input_text_h * lines);

        setMargins(gui::Margins(0, style::margins::huge, 0, 0));

        vBox = new VBox(this, 0, 0, 0, 0);
        vBox->setEdges(RectangleEdge::None);

        titleLabel = new Label(vBox);
        titleLabel->setMinimumSize(style::settings::widget::apnInputWidget::w,
                                   style::settings::widget::apnInputWidget::title_label_h);
        titleLabel->setEdges(RectangleEdge::None);
        titleLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top));
        titleLabel->setFont(style::window::font::verysmall);
        titleLabel->activeItem = false;

        inputText = new TextFixedSize(vBox, 0, 0, 0, 0);
        inputText->setMinimumSize(style::settings::widget::apnInputWidget::w,
                                  style::settings::widget::apnInputWidget::input_text_h * lines);
        inputText->setMargins(Margins(0, style::settings::widget::apnInputWidget::span_size, 0, 0));
        inputText->setUnderlinePadding(style::settings::widget::apnInputWidget::underline_padding);

        inputText->setEdges(RectangleEdge::None);
        inputText->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top));
        inputText->setFont(style::window::font::medium);
        inputText->setInputMode(new InputMode(
            {InputMode::ABC, InputMode::abc, InputMode::digit},
            [=](const UTF8 &text) { bottomBarTemporaryMode(text); },
            [=]() { bottomBarRestoreFromTemporaryMode(); },
            [=]() { selectSpecialCharacter(); }));
        inputText->setPenFocusWidth(style::window::default_border_focus_w);
        inputText->setPenWidth(style::window::default_border_no_focus_w);
        inputText->setEditMode(EditMode::Edit);

        applyItemNameSpecificSettings();

        focusChangedCallback = [&](Item &item) {
            setFocusItem(focus ? vBox : nullptr);

            auto tempText = inputText->getText();

            if (focus) {
                inputText->setFont(style::window::font::mediumbold);
                inputText->setText(tempText);
            }
            else {
                inputText->setFont(style::window::font::medium);
                inputText->setText(tempText);
            }
            return true;
        };

        inputCallback = [&](Item &item, const InputEvent &event) {
            auto result = inputText->onInput(event);
            if (checkTextContent != nullptr) {
                checkTextContent();
            }
            return result;
        };
        setEdges(RectangleEdge::None);
    }

    auto ApnInputWidget::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool
    {
        vBox->setPosition(0, 0);
        vBox->setSize(newDim.w, newDim.h);

        return true;
    }

    void ApnInputWidget::applyItemNameSpecificSettings()
    {
        switch (listItemName) {

        case settingsInternals::ListItemName::Name:
            nameHandler();
            break;

        case settingsInternals::ListItemName::APN:
            apnHandler();
            break;

        case settingsInternals::ListItemName::Username:
            usernameHandler();
            break;

        case settingsInternals::ListItemName::Password:
            passwordNumberHandler();
            break;

        case settingsInternals::ListItemName::AuthType:
            authtypeHandler();
            break;

        case settingsInternals::ListItemName::ApnType:
            apntypeHandler();
            break;

        case settingsInternals::ListItemName::ApnProtocol:
            protocolHandler();
            break;

        default:
            LOG_ERROR("Incorrect List Item Name!");
            break;
        }
    }

    void ApnInputWidget::nameHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_name"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->apn = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->apn);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::apnHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_APN"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->ip = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->ip);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::usernameHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_username"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->username = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->username);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::passwordNumberHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_password"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->password = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->password);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::authtypeHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_authtype"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setAuthMethod(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getAuthMethod());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::apntypeHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_apntype"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setApnType(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getApnType());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }
    void ApnInputWidget::protocolHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_apnprotocol"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setApnProtocol(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getApnProtocol());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

} /* namespace gui */

A module-apps/application-settings-new/widgets/ApnInputWidget.hpp => module-apps/application-settings-new/widgets/ApnInputWidget.hpp +44 -0
@@ 0,0 1,44 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsInternals.hpp"
#include "application-settings-new//widgets/ApnListItem.hpp"

#include <ListItem.hpp>
#include <Text.hpp>
#include <TextFixedSize.hpp>

namespace gui
{
    class ApnInputWidget : public ApnListItem
    {
        settingsInternals::ListItemName listItemName;

      public:
        ApnInputWidget(settingsInternals::ListItemName listItemName,
                       std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr,
                       std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr,
                       std::function<void()> selectSpecialCharacter                 = nullptr,
                       std::function<void()> contentChanged                         = nullptr,
                       unsigned int lines                                           = 1);

      private:
        VBox *vBox                             = nullptr;
        Label *titleLabel                      = nullptr;
        TextFixedSize *inputText               = nullptr;
        std::function<void()> checkTextContent = nullptr;

        void applyItemNameSpecificSettings();
        auto onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool override;
        void nameHandler();
        void apnHandler();
        void usernameHandler();
        void passwordNumberHandler();
        void authtypeHandler();
        void apntypeHandler();
        void protocolHandler();
    };

} /* namespace gui */

A module-apps/application-settings-new/widgets/ApnListItem.hpp => module-apps/application-settings-new/widgets/ApnListItem.hpp +18 -0
@@ 0,0 1,18 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsItemData.hpp"

namespace gui
{
    class ApnListItem : public ListItem
    {
      public:
        std::function<void(std::shared_ptr<packet_data::APN::Config> apnRecord)> onSaveCallback = nullptr;
        std::function<void(std::shared_ptr<packet_data::APN::Config> apnRecord)> onLoadCallback = nullptr;
        std::function<bool()> onEmptyCallback                                                   = nullptr;
    };

} /* namespace gui */

M module-apps/application-settings-new/widgets/SettingsStyle.hpp => module-apps/application-settings-new/widgets/SettingsStyle.hpp +20 -0
@@ 28,7 28,18 @@ namespace style
                inline constexpr auto before_noon             = "AM";
                inline constexpr auto after_noon              = "PM";
            } // namespace time

            namespace apnInputWidget
            {
                inline constexpr uint32_t w                = style::window::default_body_width;
                inline constexpr uint32_t h                = 63;
                inline constexpr uint32_t title_label_h    = 20;
                inline constexpr uint32_t input_text_h     = 37;
                inline constexpr uint32_t span_size        = 6;
                inline constexpr int32_t underline_padding = 4;
            } // namespace apnInputWidget
        }     // namespace widget

        namespace window
        {
            namespace leftArrowImage


@@ 70,6 81,15 @@ namespace style

                inline constexpr auto separator_h = 55;
            } // namespace nightshift

            namespace newApn
            {
                inline constexpr uint32_t x = style::window::default_left_margin;
                inline constexpr uint32_t y = style::header::height;
                inline constexpr uint32_t w = style::listview::body_width_with_scroll;
                inline constexpr uint32_t h = style::window_height - y - style::footer::height;
            } // namespace newApn

        }     // namespace window
    };        // namespace settings
} // namespace style

D module-apps/application-settings-new/windows/APNSettingsWindow.cpp => module-apps/application-settings-new/windows/APNSettingsWindow.cpp +0 -61
@@ 1,61 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "APNSettingsWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "OptionSetting.hpp"

#include <InputEvent.hpp>

namespace gui
{

    APNSettingsWindow::APNSettingsWindow(app::Application *app) : OptionWindow(app, gui::window::name::apn_settings)
    {
        buildInterface();
    }

    auto APNSettingsWindow::onInput(const InputEvent &inputEvent) -> bool
    {

        if (inputEvent.isShortPress()) {
            if (inputEvent.is(KeyCode::KEY_LEFT)) {
                // switch to new/edit APN window
            }
        }

        return AppWindow::onInput(inputEvent);
    }
    void APNSettingsWindow::buildInterface()
    {
        setTitle(utils::localize.get("app_settings_network_apn_settings"));

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,
                                        style::settings::window::leftArrowImage::w,
                                        style::settings::window::leftArrowImage::h,
                                        "arrow_left");
        crossImage     = new gui::Image(this,
                                    style::settings::window::crossImage::x,
                                    style::settings::window::crossImage::y,
                                    style::settings::window::crossImage::w,
                                    style::settings::window::crossImage::h,
                                    "cross");
        emptyListIcon  = new Icon(this,
                                 0,
                                 style::header::height,
                                 style::window_width,
                                 style::window_height - style::header::height - style::footer::height,
                                 "phonebook_empty_grey_circle_W_G",
                                 utils::localize.get("app_settings_network_apn_settings_no_apns"));

        bottomBar->setActive(gui::BottomBar::Side::CENTER, false);
    }

} // namespace gui

M module-apps/application-settings-new/windows/AllDevicesWindow.cpp => module-apps/application-settings-new/windows/AllDevicesWindow.cpp +0 -4
@@ 71,10 71,6 @@ namespace gui
                gui::option::SettingRightItem::Bt));
        }

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,

A module-apps/application-settings-new/windows/ApnOptionsWindow.cpp => module-apps/application-settings-new/windows/ApnOptionsWindow.cpp +73 -0
@@ 0,0 1,73 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnOptionsWindow.hpp"

#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/SettingsItemData.hpp"
#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "OptionSetting.hpp"

namespace gui
{
    ApnOptionsWindow::ApnOptionsWindow(app::Application *app) : BaseSettingsWindow(app, window::name::apn_options)
    {
        setTitle(utils::localize.get("app_settings_apn_options"));
        apnSettingsModel = new ApnSettingsModel(application);
    }

    auto ApnOptionsWindow::buildOptionsList() -> std::list<gui::Option>
    {
        std::list<gui::Option> optionsList;

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_edit"),
            [=](gui::Item &item) {
                std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apn);
                application->switchWindow(gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
                return true;
            },
            nullptr,
            this));

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_delete"),
            [=](gui::Item &item) {
                apnSettingsModel->removeAPN(apn);
                return true;
            },
            nullptr,
            this));

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_set_as_default"),
            [=](gui::Item &item) {
                apnSettingsModel->setAsDefaultAPN(apn);
                return true;
            },
            nullptr,
            this));

        return optionsList;
    }

    auto ApnOptionsWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            return false;
        }

        auto item = dynamic_cast<ApnItemData *>(data);
        if (item == nullptr) {
            return false;
        }

        apn = item->getApn();
        if (apn == nullptr) {
            apn = std::make_shared<packet_data::APN::Config>();
            return true;
        }

        return true;
    }
} // namespace gui

A module-apps/application-settings-new/windows/ApnOptionsWindow.hpp => module-apps/application-settings-new/windows/ApnOptionsWindow.hpp +25 -0
@@ 0,0 1,25 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "BaseSettingsWindow.hpp"

#include <service-cellular/PacketDataTypes.hpp>

namespace gui
{

    class ApnOptionsWindow : public BaseSettingsWindow
    {
      public:
        ApnOptionsWindow(app::Application *app);

      private:
        auto buildOptionsList() -> std::list<gui::Option> override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        std::shared_ptr<packet_data::APN::Config> apn;
        ApnSettingsModel *apnSettingsModel = nullptr;
    };
} // namespace gui

A module-apps/application-settings-new/windows/ApnSettingsWindow.cpp => module-apps/application-settings-new/windows/ApnSettingsWindow.cpp +135 -0
@@ 0,0 1,135 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnSettingsWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/ApnListData.hpp"
#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "application-settings-new/data/SettingsItemData.hpp"
#include "OptionSetting.hpp"

#include <InputEvent.hpp>

namespace gui
{

    ApnSettingsWindow::ApnSettingsWindow(app::Application *app) : OptionWindow(app, gui::window::name::apn_settings)
    {
        buildInterface();
    }

    void ApnSettingsWindow::buildInterface()
    {
        setTitle(utils::localize.get("app_settings_network_apn_settings"));

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,
                                        style::settings::window::leftArrowImage::w,
                                        style::settings::window::leftArrowImage::h,
                                        "arrow_left");
        crossImage     = new gui::Image(this,
                                    style::settings::window::crossImage::x,
                                    style::settings::window::crossImage::y,
                                    style::settings::window::crossImage::w,
                                    style::settings::window::crossImage::h,
                                    "cross");
        emptyListIcon  = new Icon(this,
                                 0,
                                 style::header::height,
                                 style::window_width,
                                 style::window_height - style::header::height - style::footer::height,
                                 "phonebook_empty_grey_circle_W_G",
                                 utils::localize.get("app_settings_apn_settings_no_apns"));

        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));

        auto apnSettingsModel = new ApnSettingsModel(application);
        apnSettingsModel->requestAPNList();
    }
    auto ApnSettingsWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            LOG_ERROR("Received nullptr");
            return false;
        }

        const auto newData = dynamic_cast<ApnListData *>(data);
        if (newData == nullptr) {
            LOG_ERROR("Received nullptr");
            return false;
        }

        apns = newData->getAPNs();
        if (apns.empty()) {
            emptyListIcon->setVisible(true);
            return false;
        }

        return true;
    }

    void ApnSettingsWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        clearOptions();
        bottomBar->setActive(gui::BottomBar::Side::LEFT, false);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, false);
        emptyListIcon->setVisible(false);

        if (apns.empty()) {
            return;
        }

        addOptions(optionsList(apns));
        bottomBar->setActive(gui::BottomBar::Side::LEFT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
    }

    auto ApnSettingsWindow::onInput(const InputEvent &inputEvent) -> bool
    {
        if (AppWindow::onInput(inputEvent)) {
            return true;
        }
        if (!inputEvent.isShortPress()) {
            return false;
        }
        if (inputEvent.is(gui::KeyCode::KEY_LEFT)) {
            auto apnRecord                        = std::make_shared<packet_data::APN::Config>();
            std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apnRecord);
            application->switchWindow(gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;
        }
        if (inputEvent.is(gui::KeyCode::KEY_LF)) {
            auto apnRecord                        = std::make_shared<packet_data::APN::Config>();
            std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apnRecord);
            application->switchWindow(gui::window::name::apn_options, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;
        }

        return false;
    }

    auto ApnSettingsWindow::optionsList(std::vector<std::shared_ptr<packet_data::APN::Config>> apnsList)
        -> std::list<Option>
    {
        std::list<gui::Option> optionsList;

        for (const auto &apn : apnsList) {
            optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
                (apn->apnType == packet_data::APN::APNType::Default) ? "<b>" + apn->apn + "</b>" : apn->apn,
                [=](gui::Item &item) {
                    LOG_DEBUG("APN: %s", apn->apn.c_str());
                    std::unique_ptr<gui::SwitchData> apnData = std::make_unique<ApnItemData>(apn);
                    application->switchWindow(
                        gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(apnData));
                    return true;
                },
                nullptr,
                nullptr));
        }

        return optionsList;
    }

} // namespace gui

R module-apps/application-settings-new/windows/APNSettingsWindow.hpp => module-apps/application-settings-new/windows/ApnSettingsWindow.hpp +7 -2
@@ 5,20 5,25 @@

#include "OptionWindow.hpp"
#include <Icon.hpp>
#include <service-cellular/PacketDataTypes.hpp>

namespace gui
{
    class APNSettingsWindow : public OptionWindow
    class ApnSettingsWindow : public OptionWindow
    {
      public:
        APNSettingsWindow(app::Application *app);
        ApnSettingsWindow(app::Application *app);

      private:
        void buildInterface() override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        auto onInput(const InputEvent &inputEvent) -> bool override;
        auto optionsList(std::vector<std::shared_ptr<packet_data::APN::Config>> vector) -> std::list<Option>;

        Image *leftArrowImage = nullptr;
        Image *crossImage     = nullptr;
        Icon *emptyListIcon   = nullptr;
        std::vector<std::shared_ptr<packet_data::APN::Config>> apns;
    };
}; // namespace gui

M module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp => module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp +0 -4
@@ 33,10 33,6 @@ namespace gui
                                                gui::option::Arrow::Enabled});
        };

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        addMenu(i18("app_settings_apps_messages"), gui::window::name::messages);
        addMenu(i18("app_settings_apps_torch"), gui::window::name::torch);


M module-apps/application-settings-new/windows/BaseSettingsWindow.cpp => module-apps/application-settings-new/windows/BaseSettingsWindow.cpp +0 -3
@@ 16,9 16,6 @@ namespace gui

        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);
    }

    void BaseSettingsWindow::destroyInterface()

M module-apps/application-settings-new/windows/BluetoothWindow.cpp => module-apps/application-settings-new/windows/BluetoothWindow.cpp +0 -2
@@ 15,8 15,6 @@ namespace gui

    BluetoothWindow::BluetoothWindow(app::Application *app) : OptionWindow(app, gui::window::name::bluetooth)
    {
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        sys::Bus::SendUnicast(
            std::make_shared<::message::bluetooth::RequestStatus>(), service::name::bluetooth, application);
    }

M module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp => module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp +0 -8
@@ 76,14 76,6 @@ namespace gui
        setTitle(utils::localize.get("app_settings_security_change_passcode"));
    }

    void ChangePasscodeWindow::buildTopBar()
    {
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::LOCK, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::TIME, true);
    }

    void ChangePasscodeWindow::destroyInterface()
    {
        erase();

M module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp => module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp +0 -1
@@ 21,7 21,6 @@ namespace gui
        void buildBottomBar() override;
        void buildInterface() override;
        void buildTitleBar() override;
        void buildTopBar() override;
        void destroyInterface() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void processPasscode();

M module-apps/application-settings-new/windows/DisplayLightWindow.cpp => module-apps/application-settings-new/windows/DisplayLightWindow.cpp +2 -3
@@ 13,14 13,13 @@

namespace gui
{

    DisplayLightWindow::DisplayLightWindow(app::Application *app, app::settingsInterface::ScreenLightSettings *settings)
        : BaseSettingsWindow(app, window::name::display_light), screenLightSettings(settings)
    {
        auto values = screenLightSettings->getCurrentValues();

        isDisplayLightSwitchOn = values.lightOn;
        isAutoLightSwitchOn    = values.mode;
        isAutoLightSwitchOn    = values.mode == screen_light_control::ScreenLightMode::Automatic;
        brightnessValue        = values.parameters.manualModeBrightness;

        setTitle(utils::localize.get("app_settings_display_display_light"));


@@ 85,7 84,7 @@ namespace gui
        };

        auto spinner = std::make_unique<gui::SpinBoxOptionSettings>(
            utils::translateI18("app_settings_display_light_brightness") + " " + std::to_string(brightnessStep),
            utils::translateI18("app_settings_display_light_brightness") + " " + utils::to_string(brightnessStep),
            brightnessValue * brightnessStep,
            std::ceil(screen_light_control::Parameters::MAX_BRIGHTNESS / brightnessStep),
            setBrightness,

M module-apps/application-settings-new/windows/MessagesWindow.cpp => module-apps/application-settings-new/windows/MessagesWindow.cpp +0 -3
@@ 64,9 64,6 @@ namespace gui
        };

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        addMenuSwitch(utils::translateI18("app_settings_show_unread_first"), "");
        addMenu(utils::translateI18("app_settings_Templates"), gui::window::name::templates);

M module-apps/application-settings-new/windows/NetworkWindow.cpp => module-apps/application-settings-new/windows/NetworkWindow.cpp +0 -3
@@ 122,9 122,6 @@ namespace gui

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        return optList;
    }
    void NetworkWindow::rebuild()

A module-apps/application-settings-new/windows/NewApnWindow.cpp => module-apps/application-settings-new/windows/NewApnWindow.cpp +119 -0
@@ 0,0 1,119 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NewApnWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"

#include <Dialog.hpp>
#include <messages/DialogMetadataMessage.hpp>

namespace gui
{

    NewApnWindow::NewApnWindow(app::Application *app)
        : AppWindow(app, gui::window::name::new_apn), newApnModel{std::make_shared<NewApnModel>(app)}
    {
        buildInterface();
    }

    void NewApnWindow::rebuild()
    {
        destroyInterface();
        buildInterface();
    }

    void NewApnWindow::buildInterface()
    {
        AppWindow::buildInterface();

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::save));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        setTitle(utils::localize.get("app_settings_new_edit_apn"));

        list = new gui::ListView(this,
                                 style::settings::window::newApn::x,
                                 style::settings::window::newApn::y,
                                 style::settings::window::newApn::w,
                                 style::settings::window::newApn::h,
                                 newApnModel);
        setFocusItem(list);
        apnSettingsModel = new ApnSettingsModel(application);
    }

    void NewApnWindow::destroyInterface()
    {
        erase();
    }

    void NewApnWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        if (mode != ShowMode::GUI_SHOW_RETURN) {
            newApnModel->clearData();
        }

        if (mode == ShowMode::GUI_SHOW_INIT) {
            list->rebuildList();
        }

        if (apn != nullptr) {
            newApnModel->loadData(apn);
        }
    }

    auto NewApnWindow::handleSwitchData(SwitchData *data) -> bool
    {
        setSaveButtonVisible(false);

        if (data == nullptr) {
            return false;
        }

        auto *item = dynamic_cast<ApnItemData *>(data);
        if (item == nullptr) {
            return false;
        }

        apn = item->getApn();
        if (apn == nullptr) {
            apn = std::make_shared<packet_data::APN::Config>();
            return true;
        }

        return true;
    }

    void NewApnWindow::setSaveButtonVisible(bool visible)
    {
        bottomBar->setActive(BottomBar::Side::CENTER, visible);
    }

    auto NewApnWindow::onInput(const InputEvent &inputEvent) -> bool
    {
        if (!inputEvent.isShortPress()) {
            return false;
        }
        if (inputEvent.is(gui::KeyCode::KEY_ENTER)) {
            if (apn != nullptr) {
                newApnModel->saveData(apn);
            }
            verifyAndSave();
            return true;
        }

        return AppWindow::onInput(inputEvent);
    }

    auto NewApnWindow::verifyAndSave() -> bool
    {
        if (apn == nullptr) {
            LOG_DEBUG("APN record not found");
            return false;
        }
        apnSettingsModel->saveAPN(apn);
        LOG_DEBUG("APN record  saved : \"%s\" ", apn->apn.c_str());

        return true;
    }

} // namespace gui

A module-apps/application-settings-new/windows/NewApnWindow.hpp => module-apps/application-settings-new/windows/NewApnWindow.hpp +35 -0
@@ 0,0 1,35 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "application-settings-new/models/NewApnModel.hpp"

#include <AppWindow.hpp>
#include <ListView.hpp>
#include <Text.hpp>

namespace gui
{
    class NewApnWindow : public AppWindow
    {
      public:
        NewApnWindow(app::Application *app);

      private:
        auto onInput(const InputEvent &inputEvent) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        auto verifyAndSave() -> bool;
        void setSaveButtonVisible(bool visible);
        std::shared_ptr<packet_data::APN::Config> apn;
        std::shared_ptr<NewApnModel> newApnModel;
        ApnSettingsModel *apnSettingsModel = nullptr;
        gui::ListView *list                = nullptr;
    };

} /* namespace gui */

M module-apps/application-settings-new/windows/NightshiftWindow.cpp => module-apps/application-settings-new/windows/NightshiftWindow.cpp +0 -3
@@ 16,9 16,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_settings_title_nightshift"));

        body = new gui::VBox(this,

M module-apps/application-settings-new/windows/PhoneNameWindow.cpp => module-apps/application-settings-new/windows/PhoneNameWindow.cpp +0 -2
@@ 22,8 22,6 @@ namespace gui
    void PhoneNameWindow::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_settings_bluetooth_phone_name"));


M module-apps/application-settings-new/windows/QuotesAddWindow.cpp => module-apps/application-settings-new/windows/QuotesAddWindow.cpp +1 -1
@@ 6,7 6,7 @@

#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/QuoteSwitchData.hpp"
#include "application-settings-new/model/QuotesRepository.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"

#include <i18n/i18n.hpp>
#include <widgets/Text.hpp>

M module-apps/application-settings-new/windows/QuotesAddWindow.hpp => module-apps/application-settings-new/windows/QuotesAddWindow.hpp +1 -1
@@ 5,7 5,7 @@

#include "BaseSettingsWindow.hpp"
#include "QuotesMainWindow.hpp"
#include "application-settings-new/model/QuotesModel.hpp"
#include "application-settings-new/models/QuotesModel.hpp"

namespace gui
{

M module-apps/application-settings-new/windows/QuotesMainWindow.cpp => module-apps/application-settings-new/windows/QuotesMainWindow.cpp +2 -2
@@ 2,8 2,8 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesMainWindow.hpp"
#include "application-settings-new/model/QuotesRepository.hpp"
#include "application-settings-new/model/QuotesModel.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/models/QuotesModel.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "OptionSetting.hpp"

M module-apps/application-settings-new/windows/QuotesMainWindow.hpp => module-apps/application-settings-new/windows/QuotesMainWindow.hpp +1 -1
@@ 5,7 5,7 @@

#include "BaseSettingsWindow.hpp"
#include "application-settings-new/widgets/QuoteWidget.hpp"
#include "application-settings-new/model/QuotesModel.hpp"
#include "application-settings-new/models/QuotesModel.hpp"

#include <purefs/filesystem_paths.hpp>
#include <module-gui/gui/widgets/ListView.hpp>

M module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp => module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp +2 -2
@@ 3,11 3,11 @@

#include "QuotesOptionsWindow.hpp"
#include "OptionSetting.hpp"
#include "application-settings-new/model/QuotesRepository.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "DialogMetadataMessage.hpp"
#include "QuotesMainWindow.hpp"
#include "application-settings-new/model/QuotesRepository.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/QuoteWidget.hpp"


M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +12 -8
@@ 47,16 47,10 @@ namespace app
            switchWindow(app::sim_select);
            return msgHandled();
        });
        settings->registerValueChange(settings::SystemProperties::lockPassHash,
                                      [this](std::string value) { lockPassChanged(value); });
        settings->registerValueChange(settings::SystemProperties::timeDateFormat,
                                      [this](std::string value) { timeDateChanged(value); });
    }

    ApplicationSettings::~ApplicationSettings()
    {
        settings->unregisterValueChange(settings::SystemProperties::lockPassHash);
        settings->unregisterValueChange(settings::SystemProperties::timeDateFormat);
    }

    // Invoked upon receiving data message


@@ 104,6 98,15 @@ namespace app
        if (ret != sys::ReturnCodes::Success)
            return ret;

        settings->registerValueChange(
            settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::timeDateFormat,
            [this](std::string value) { timeDateChanged(value); },
            settings::SettingsScope::Global);

        createUserInterface();

        setActiveWindow(gui::name::window::main_window);


@@ 173,13 176,14 @@ namespace app

    void ApplicationSettings::setPin(unsigned int value)
    {
        settings->setValue(settings::SystemProperties::lockPassHash, std::to_string(value));
        settings->setValue(
            settings::SystemProperties::lockPassHash, std::to_string(value), settings::SettingsScope::Global);
        lockPassHash = value;
    }

    void ApplicationSettings::clearPin()
    {
        settings->setValue(settings::SystemProperties::lockPassHash, "");
        settings->setValue(settings::SystemProperties::lockPassHash, "", settings::SettingsScope::Global);
        lockPassHash = 0U;
    }


M module-apps/application-settings/windows/BtScanWindow.cpp => module-apps/application-settings/windows/BtScanWindow.cpp +0 -2
@@ 57,8 57,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("BT_scan_results"));


M module-apps/application-settings/windows/BtWindow.cpp => module-apps/application-settings/windows/BtWindow.cpp +0 -2
@@ 59,8 59,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_bt"));


M module-apps/application-settings/windows/CellularPassthroughWindow.cpp => module-apps/application-settings/windows/CellularPassthroughWindow.cpp +0 -2
@@ 31,8 31,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_cellular_passthrough"));


M module-apps/application-settings/windows/CellularPassthroughWindow.hpp => module-apps/application-settings/windows/CellularPassthroughWindow.hpp +1 -3
@@ 30,8 30,6 @@ namespace gui
        } // namespace cellular_passthrough
    }     // namespace window

    using namespace bsp::cellular::USB;

    class CellularPassthroughWindow : public AppWindow
    {
      private:


@@ 76,7 74,7 @@ namespace gui

        CellularPassthroughWindow::State getInitialState();

        bool set(PassthroughState pass_to_set, BootPinState dfu_to_set);
        bool set(bsp::cellular::USB::PassthroughState pass_to_set, bsp::cellular::USB::BootPinState dfu_to_set);

        void setWindowState(State state);


M module-apps/application-settings/windows/DateTimeWindow.cpp => module-apps/application-settings/windows/DateTimeWindow.cpp +0 -3
@@ 52,9 52,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_date_and_time"));

        // create date widgets

M module-apps/application-settings/windows/EinkModeWindow.cpp => module-apps/application-settings/windows/EinkModeWindow.cpp +0 -2
@@ 27,8 27,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle("Change eink mode");
        auto label               = new Label(this, 100, 200, 300, 50, "Change mode on click");

M module-apps/application-settings/windows/FotaWindow.cpp => module-apps/application-settings/windows/FotaWindow.cpp +0 -3
@@ 37,9 37,6 @@ namespace gui
        AppWindow::buildInterface();
        setTitle("Modem Firmware update (FOTA)");

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("Go"));

M module-apps/application-settings/windows/Info.cpp => module-apps/application-settings/windows/Info.cpp +0 -2
@@ 36,8 36,6 @@ namespace gui
        AppWindow::buildInterface();
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle("Info");


M module-apps/application-settings/windows/LanguageWindow.cpp => module-apps/application-settings/windows/LanguageWindow.cpp +0 -3
@@ 49,9 49,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_title_languages"));
        const auto &langList = loader.getAvailableDisplayLanguages();
        for (const auto &lang : langList) {

M module-apps/application-settings/windows/TestMessageWindow.cpp => module-apps/application-settings/windows/TestMessageWindow.cpp +0 -3
@@ 61,9 61,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        receivedLabel = new gui::Label(this, 10, 50, 480 - 20, 50, "Received SMS");
        receivedLabel->setAlignment(
            gui::Alignment(gui::Alignment::Vertical::Center, gui::Alignment::Horizontal::Center));

M module-apps/application-special-input/windows/SpecialInputMainWindow.cpp => module-apps/application-special-input/windows/SpecialInputMainWindow.cpp +0 -2
@@ 36,8 36,6 @@ void SpecialInputMainWindow::buildInterface()
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
    bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::emoji));

    topBar->setActive(TopBar::Elements::TIME, true);

    charList = new gui::ListView(this,
                                 specialInputStyle::specialInputListView::x,
                                 specialInputStyle::specialInputListView::y,

M module-apps/windows/AppWindow.cpp => module-apps/windows/AppWindow.cpp +16 -4
@@ 49,10 49,22 @@ namespace gui
        title->setEllipsis(Ellipsis::Right);
        title->visible = false;

        topBar = new gui::TopBar(this, 0, 0, 480, 50);
        topBar->setActive(TopBar::Elements::LOCK, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIGNAL, false);
        auto config = configureTopBar(application->getTopBarConfiguration());
        topBar      = new gui::top_bar::TopBar(this, 0, 0, 480, 50);
        topBar->configure(std::move(config));
    }

    top_bar::Configuration AppWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        return appConfiguration;
    }

    void AppWindow::applyToTopBar(TopBarConfigurationChangeFunction configChange)
    {
        if (configChange) {
            auto newConfiguration = configChange(topBar->getConfiguration());
            topBar->configure(std::move(newConfiguration));
        }
    }

    bool AppWindow::setSIM()

M module-apps/windows/AppWindow.hpp => module-apps/windows/AppWindow.hpp +21 -5
@@ 40,12 40,17 @@ namespace gui
        /**
         * Information bar for signal, battery and lock icon on the top of the screen.
         */
        gui::TopBar *topBar = nullptr;
        gui::top_bar::TopBar *topBar = nullptr;
        /**
         * Pointer to the application object that owns the window.
         */
        app::Application *application = nullptr;

        /**
         * A function that applies configuration changes to the current top bar configuration.
         */
        using TopBarConfigurationChangeFunction = std::function<top_bar::Configuration(top_bar::Configuration)>;

      public:
        AppWindow() = delete;
        AppWindow(app::Application *app, std::string name);


@@ 54,10 59,7 @@ namespace gui
        {
            return application;
        };
        void setApplication(app::Application *app)
        {
            application = app;
        };

        virtual bool onDatabaseMessage(sys::Message *msg);

        bool updateBatteryCharger(bool charging);


@@ 76,6 78,20 @@ namespace gui
        void destroyInterface() override;
        bool onInput(const InputEvent &inputEvent) override;
        void accept(GuiVisitor &visitor) override;

        /**
         * Configure the top bar using window-specific configuration.
         * @param appConfiguration      Application-wide top bar configuration that it to be modified.
         * @return window-specific configuration of the top bar.
         */
        virtual top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration);

        /**
         * Applies configuration change on the current top bar configuration.
         * @param configChange  The function that contains the top bar configuration changes.
         */
        void applyToTopBar(TopBarConfigurationChangeFunction configChange);

        /// Setting bottom bar temporary text
        /// @param text - bottomBar text
        /// @param overwriteOthers - set or not other bottomBar texts to "" (default true)

M module-apps/windows/Dialog.cpp => module-apps/windows/Dialog.cpp +0 -6
@@ 50,7 50,6 @@ Dialog::Dialog(app::Application *app, const std::string &name) : gui::AppWindow(
{
    AppWindow::buildInterface();

    topBar->setActive(TopBar::Elements::TIME, true);
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

    setTitle("");


@@ 77,9 76,6 @@ void Dialog::onBeforeShow(ShowMode mode, SwitchData *data)

DialogConfirm::DialogConfirm(app::Application *app, const std::string &name) : Dialog(app, name)
{
    topBar->setActive(TopBar::Elements::BATTERY, true);
    topBar->setActive(TopBar::Elements::SIGNAL, true);

    bottomBar->setActive(BottomBar::Side::RIGHT, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
    setFocusItem(icon);


@@ 169,8 165,6 @@ void DialogYesNoIconTxt::onBeforeShow(ShowMode mode, SwitchData *data)
    if (auto metadata = dynamic_cast<DialogMetadataMessage *>(data); metadata != nullptr) {
        DialogYesNo::onBeforeShow(mode, metadata);
        iconText->setText(metadata->get().iconText);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        setFocusItem(no);
    }
}

M module-apps/windows/OptionWindow.cpp => module-apps/windows/OptionWindow.cpp +0 -2
@@ 63,8 63,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        setTitle(name);

        optionsList = new gui::ListView(this,

M module-audio/Audio/StreamQueuedEventsListener.cpp => module-audio/Audio/StreamQueuedEventsListener.cpp +2 -1
@@ 5,7 5,8 @@

using namespace audio;

StreamQueuedEventsListener::StreamQueuedEventsListener(std::shared_ptr<Queue> eventsQueue) : queue(eventsQueue)
StreamQueuedEventsListener::StreamQueuedEventsListener(std::shared_ptr<cpp_freertos::Queue> eventsQueue)
    : queue(eventsQueue)
{}

void StreamQueuedEventsListener::onEvent(Stream *stream, Stream::Event event, Stream::EventSourceMode source)

M module-audio/Audio/StreamQueuedEventsListener.hpp => module-audio/Audio/StreamQueuedEventsListener.hpp +2 -4
@@ 13,8 13,6 @@

namespace audio
{
    using namespace cpp_freertos;

    class StreamQueuedEventsListener : public Stream::EventListener
    {
      private:


@@ 29,7 27,7 @@ namespace audio
        using queuedEvent                         = std::pair<Stream *, Stream::Event>;
        static constexpr auto listenerElementSize = sizeof(EventStorage);

        StreamQueuedEventsListener(std::shared_ptr<Queue> eventsQueue);
        StreamQueuedEventsListener(std::shared_ptr<cpp_freertos::Queue> eventsQueue);

        void onEvent(Stream *stream, Stream::Event event, Stream::EventSourceMode source);



@@ 39,7 37,7 @@ namespace audio
        std::size_t getEventsCount() const;

      private:
        std::shared_ptr<Queue> queue;
        std::shared_ptr<cpp_freertos::Queue> queue;
    };

}; // namespace audio

M module-bsp/board/linux/battery-charger/battery_charger.cpp => module-bsp/board/linux/battery-charger/battery_charger.cpp +81 -95
@@ 1,21 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 * battery_charger.cpp
 *
 *  Created on: Jul 1, 2019
 *      Author: kuba
 */
#include <stdint.h>

extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

#include <sys/stat.h>
#include <fcntl.h>
#include <module-utils/common_data/EventStore.hpp>


@@ 23,114 7,116 @@ extern "C"
#include "board.h"
#include "bsp/battery-charger/battery_charger.hpp"

#define BSP_BATTERY_CHARGER_I2C_ADDR (0xD2 >> 1)
#define BSP_FUEL_GAUGE_I2C_ADDR      (0x6C >> 1)
#define BSP_TOP_CONTROLLER_I2C_ADDR  (0xCC >> 1)

static xQueueHandle qHandleIrq            = NULL;
static TaskHandle_t battery_worker_handle = NULL;

static uint8_t battLevel = 100;
static bool plugged      = false;
namespace bsp
namespace bsp::battery_charger
{
    namespace
    {
        xQueueHandle IRQQueueHandle         = nullptr;
        TaskHandle_t batteryWorkerHandle    = nullptr;
        constexpr auto batteryFIFO          = "/tmp/fifoBattKeys";
        constexpr auto fifoFileAccessRights = 0666;
        constexpr auto fifoBuffSize         = 10;
        constexpr auto queueTimeoutTicks    = 100;
        constexpr auto taskDelay            = 50;

        StateOfCharge battLevel             = 100;
        constexpr StateOfCharge fullBattery = 100;
        bool plugged                        = false;

        constexpr auto chargerPlugStateChange = 'p';
        constexpr auto batteryLevelUp         = ']';
        constexpr auto batteryLevelDown       = '[';

        void battery_worker(void *parameters)
        {
            mkfifo(batteryFIFO, fifoFileAccessRights);

            // Open FIFO for write only
            int fd = open(batteryFIFO, O_RDONLY | O_NONBLOCK);

            while (true) {
                std::uint8_t buff[fifoBuffSize];
                std::int32_t readBytes = read(fd, buff, fifoBuffSize);

                if (readBytes > 0) {
                    std::uint8_t notification = 0;
                    switch (static_cast<char>(buff[0])) {
                    case chargerPlugStateChange:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INOKB);
                        plugged      = !plugged;
                        break;
                    case batteryLevelUp:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INTB);
                        if (battLevel < fullBattery)
                            battLevel++;
                        else {
                            // second 100% in a row
                            if (plugged && Store::Battery::get().level == fullBattery) {
                                Store::Battery::modify().state = Store::Battery::State::PluggedNotCharging;
                            }
                        }
                        break;
                    case batteryLevelDown:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INTB);
                        if (battLevel >= 1)
                            battLevel--;
                        if (plugged && Store::Battery::get().level == fullBattery) {
                            // charging but not 100% anymore
                            Store::Battery::modify().state = Store::Battery::State::Charging;
                        }
                        break;
                    }
                    xQueueSend(IRQQueueHandle, &notification, queueTimeoutTicks);
                }
                vTaskDelay(taskDelay);
            }
        }
    } // namespace

    static void battery_worker(void *pvp);

    int battery_Init(xQueueHandle qHandle)
    int init(xQueueHandle queueHandle)
    {
        qHandleIrq = qHandle;
        if (xTaskCreate(battery_worker, "battery", 512, qHandle, 0, &battery_worker_handle) != pdPASS) {
        IRQQueueHandle = queueHandle;
        if (xTaskCreate(battery_worker, "battery", 512, queueHandle, 0, &batteryWorkerHandle) != pdPASS) {
            return 1;
        }
        Store::Battery::modify().level = battLevel;
        return 0;
    }

    void battery_Deinit(void)
    void deinit()
    {
        qHandleIrq = NULL;
        vTaskDelete(battery_worker_handle);
        IRQQueueHandle = nullptr;
        vTaskDelete(batteryWorkerHandle);
    }
    void battery_getBatteryLevel(uint8_t &levelPercent)

    StateOfCharge getBatteryLevel()
    {
        levelPercent                   = battLevel;
        Store::Battery::modify().level = battLevel;
        return battLevel;
    }

    void battery_getChargeStatus(bool &status)
    bool getChargeStatus()
    {
        status = plugged;
        bool status = plugged;
        if (status) {
            Store::Battery::modify().state = Store::Battery::State::Charging;
        }
        else {
            Store::Battery::modify().state = Store::Battery::State::Discharging;
        }
        return status;
    }

    // TODO function unused in linux driver, left for compatibility with target driver
    void battery_ClearAllIRQs(void)
    void clearAllIRQs()
    {}
    // TODO function unused in linux driver, left for compatibility with target driver
    void battery_clearFuelGuageIRQ(void)
    void clearFuelGuageIRQ()
    {}

    static void battery_worker(void *pvp)
    {

        const char *myfifo = "/tmp/fifoBattKeys";

        // Creating the named file(FIFO)
        // mkfifo(<pathname>, <permission>)
        mkfifo(myfifo, 0666);

        // Open FIFO for write only
        int fd;
        fd = open(myfifo, O_RDONLY | O_NONBLOCK);

        while (1) {
            uint8_t buff[10];
            int32_t readedBytes = read(fd, buff, 10);

            if (readedBytes > 0) {

                uint8_t notification = 0;
                switch (buff[0]) {
                case 'p':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INOKB);
                    plugged      = 1 - plugged;
                    break;
                case ']':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
                    if (battLevel < 100)
                        battLevel++;
                    else {
                        // second 100% in a row
                        if (plugged && Store::Battery::get().level == 100) {
                            Store::Battery::modify().state = Store::Battery::State::PluggedNotCharging;
                        }
                    }
                    break;
                case '[':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
                    if (battLevel >= 1)
                        battLevel--;
                    if (plugged && Store::Battery::get().level == 100) {
                        // charging but not 100% anymore
                        Store::Battery::modify().state = Store::Battery::State::Charging;
                    }
                    break;
                }
                xQueueSend(qHandleIrq, &notification, 100);
            }
            vTaskDelay(50);
        }
    }

    std::uint16_t battery_getStatusRegister()
    std::uint16_t getStatusRegister()
    {
        return static_cast<std::uint16_t>(batteryINTBSource::SOCOnePercentChange);
    }

} // namespace bsp
} // namespace bsp::battery_charger

M module-bsp/board/linux/usb_cdc/usb_cdc.cpp => module-bsp/board/linux/usb_cdc/usb_cdc.cpp +1 -2
@@ 32,7 32,6 @@ namespace bsp
    {
        LOG_INFO("[ServiceDesktop:BSP_Driver] Start reading on fd:%d", fd);
        char inputData[SERIAL_BUFFER_LEN];
        static std::string receiveMsg;

        while (1) {
            if (uxQueueSpacesAvailable(USBReceiveQueue) != 0) {


@@ 61,7 60,7 @@ namespace bsp
                        continue;
                    }
#endif
                    receiveMsg = std::string(inputData, inputData + length);
                    std::string *receiveMsg = new std::string(inputData, inputData + length);
                    xQueueSend(USBReceiveQueue, &receiveMsg, portMAX_DELAY);
                }
                else {

A module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp => module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp +160 -0
@@ 0,0 1,160 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once

namespace bsp::battery_charger
{

    constexpr inline auto BATTERY_CHARGER_I2C_ADDR = 0xD2 >> 1;
    constexpr inline auto FUEL_GAUGE_I2C_ADDR      = 0x6C >> 1;
    constexpr inline auto TOP_CONTROLLER_I2C_ADDR  = 0xCC >> 1;

    enum class Registers
    {
        TOP_CONTROLL_PMIC_ID_REG  = 0x20,
        TOP_CONTROLL_PMIC_VER_REG = 0x21,
        TOP_CONTROLL_IRQ_SRC_REG  = 0x22,
        TOP_CONTROLL_IRQ_MASK_REG = 0x23,
        SYSTEM_IRQ_REG            = 0x24,

        STATUS_REG     = 0x00,
        VALRT_Th_REG   = 0x01,
        TALRT_Th_REG   = 0x02,
        SALRT_Th_REG   = 0x03,
        AtRate_REG     = 0x04,
        RepCap_REG     = 0x05,
        RepSOC_REG     = 0x06,
        Age_REG        = 0x07,
        TEMP_REG       = 0x08,
        VCELL_REG      = 0x09,
        Current_REG    = 0x0A,
        AvgCurrent_REG = 0x0B,
        QResidual_REG  = 0x0C,
        MixSOC_REG     = 0x0D,
        AvSOC_REG      = 0x0E,
        MixCap_REG     = 0x0F,

        FullCAP_REG    = 0x10,
        TTE_REG        = 0x11,
        QRtable00_REG  = 0x12,
        FullSOCthr_REG = 0x13,
        RSLOW_REG      = 0x14,
        AvgTA_REG      = 0x16,
        Cycles_REG     = 0x17,
        DesignCap_REG  = 0x18,
        AvgVCELL_REG   = 0x19,
        MaxMinTemp_REG = 0x1A,
        MaxMinVolt_REG = 0x1B,
        MaxMinCurr_REG = 0x1C,
        CONFIG_REG     = 0x1D,
        CONFIG2_REG    = 0xBB,
        ICHGTERM_REG   = 0x1E,
        AvCap_REG      = 0x1F,

        TTF_REG        = 0x20,
        DevName_REG    = 0x21,
        QRtable10_REG  = 0x22,
        FullCAPNom_REG = 0x23,
        TempNom_REG    = 0x24,
        TempLim_REG    = 0x25,
        AIN0_REG       = 0x27,
        LearnCFG_REG   = 0x28,
        FilterCFG_REG  = 0x29,
        RelaxCFG_REG   = 0x2A,
        MiscCFG_REG    = 0x2B,
        TGAIN_REG      = 0x2C,
        TOFF_REG       = 0x2D,
        CGAIN_REG      = 0x2E,
        COFF_REG       = 0x2F,

        QRtable20_REG  = 0x32,
        AtTTF_REG      = 0x33,
        FullCapRep_REG = 0x35,
        lavgEmpty_REG  = 0x36,
        FCTC_REG       = 0x37,
        RCOMP0_REG     = 0x38,
        TempCo_REG     = 0x39,
        VEmpty_REG     = 0x3A,
        TIMER_REG      = 0x3E,
        SHDNTIMER_REG  = 0x3F,

        QRtable30_REG = 0x42,
        dQ_acc_REG    = 0x45,
        dP_acc_REG    = 0x46,
        ConvgCfg_REG  = 0x49,
        VFRemCap_REG  = 0x4A,
        QH_REG        = 0x4D,
        CHG_INT_REG   = 0xb0,
        CHG_INT_OK    = 0xb2
    };

    // STATUS register bits
    enum STATUS
    {
        Inm    = (1 << 0),
        POR    = (1 << 1),
        SPR_2  = (1 << 2),
        BST    = (1 << 3),
        Isysmx = (1 << 4),
        SPR_5  = (1 << 5),
        ThmHot = (1 << 6),
        dSOCi  = (1 << 7),
        Vmn    = (1 << 8),
        Tmn    = (1 << 9),
        Smn    = (1 << 10),
        Bi     = (1 << 11),
        Vmx    = (1 << 12),
        Tmx    = (1 << 13),
        Smx    = (1 << 14),
        Br     = (1 << 15),
    };

    /// CHG_INT registers from documentation
    enum class CHG_INT
    {
        BYP_I   = (1 << 0),
        RSVD    = (1 << 1),
        BATP_I  = (1 << 2),
        BAT_I   = (1 << 3),
        CHG_I   = (1 << 4),
        WCIN_I  = (1 << 5),
        CHGIN_I = (1 << 6),
        AICL_I  = (1 << 7),
    };

    // CONFIG register bits
    enum class CONFIG
    {
        Ber    = 1 << 0,
        Bei    = 1 << 1,
        Aen    = 1 << 2,
        FTHRM  = 1 << 3,
        ETHRM  = 1 << 4,
        SPR_5  = 1 << 5,
        I2CSH  = 1 << 6,
        SHDN   = 1 << 7,
        Tex    = 1 << 8,
        Ten    = 1 << 9,
        AINSH  = 1 << 10,
        SPR_11 = 1 << 11,
        Vs     = 1 << 12,
        Ts     = 1 << 13,
        Ss     = 1 << 14,
        SPR_15 = 1 << 15
    };

    // CONFIG2 register bits
    enum class CONFIG2
    {
        ISysNCurr    = 1 << 0,
        OCVQen       = 1 << 4,
        LdMdl        = 1 << 5,
        TAlrtEn      = 1 << 6,
        dSOCen       = 1 << 7,
        ThmHotAlrtEn = 1 << 8,
        ThmHotEn     = 1 << 9,
        FCThmHot     = 1 << 10,
        SPR          = 1 << 11
    };

} // namespace bsp::battery_charger

M module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp => module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp +339 -481
@@ 1,586 1,444 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 * battery_charger.cpp
 *
 *  Created on: Jun 28, 2019
 *      Author: kuba
 */

extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

#include "bsp/battery-charger/battery_charger.hpp"
#include "MAX77818.hpp"
#include <purefs/filesystem_paths.hpp>

#include "bsp/BoardDefinitions.hpp"
#include "common_data/EventStore.hpp"
#include "drivers/gpio/DriverGPIO.hpp"
#include "drivers/i2c/DriverI2C.hpp"
#include <cstdio>
#include <purefs/filesystem_paths.hpp>
#include "fsl_common.h"
#define BSP_BATTERY_CHARGER_I2C_ADDR (0xD2 >> 1)
#define BSP_FUEL_GAUGE_I2C_ADDR      (0x6C >> 1)
#define BSP_TOP_CONTROLLER_I2C_ADDR  (0xCC >> 1)

static const uint32_t i2cSubaddresSize = 1;
#include <utility>

namespace configs
namespace bsp::battery_charger
{
    const auto battery_cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
    const auto battery_cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";
} // namespace configs
    namespace
    {
        constexpr std::uint32_t i2cSubaddresSize = 1;

static const uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
    0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
static const uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
    0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
static const uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
    0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
static const uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
    0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
static const uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;
        const auto cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
        const auto cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";

static const uint16_t battery_nominalCapacitymAh = 3000;
        constexpr std::uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
            0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
        constexpr std::uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
            0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
        constexpr std::uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
            0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
        constexpr std::uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
            0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
        constexpr std::uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;

static const uint8_t battery_fullyChargedPercent = 100;
static const uint8_t battery_DischargedPercent   = 15;
        constexpr auto ENABLE_ALL_IRQ_MASK = 0xf8;

static const uint8_t battery_maxTemperatureDegrees = 50;
static const uint8_t battery_minTemperatureDegrees = 5;
        constexpr std::uint16_t nominalCapacitymAh = 3000;

static constexpr inline uint16_t battery_maxVoltagemV = 4200;
static constexpr inline uint16_t battery_minVoltagemV = 3600;
        constexpr std::uint8_t fullyChargedPercent = 100;
        constexpr std::uint8_t DischargedPercent   = 15;

using namespace drivers;
        constexpr std::uint8_t maxTemperatureDegrees = 50;
        constexpr std::uint8_t minTemperatureDegrees = 5;

static std::shared_ptr<drivers::DriverI2C> i2c;
static std::shared_ptr<drivers::DriverGPIO> gpio;
        constexpr std::uint16_t maxVoltagemV = 4200;
        constexpr std::uint16_t minVoltagemV = 3600;

static bsp::batteryRetval battery_loadConfiguration(void);
        std::shared_ptr<drivers::DriverI2C> i2c;
        std::shared_ptr<drivers::DriverGPIO> gpio;

static bsp::batteryRetval battery_storeConfiguration(void);
        drivers::I2CAddress fuelGaugeAddress      = {FUEL_GAUGE_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress batteryChargerAddress = {BATTERY_CHARGER_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress topControllerAddress  = {TOP_CONTROLLER_I2C_ADDR, 0, i2cSubaddresSize};

static int battery_fuelGaugeWrite(bsp::batteryChargerRegisters registerAddress, uint16_t value);
        xQueueHandle IRQQueueHandle = nullptr;

static int battery_fuelGaugeRead(bsp::batteryChargerRegisters registerAddress, uint16_t *value);
        int fuelGaugeWrite(Registers registerAddress, std::uint16_t value)
        {
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint16_t));

static int battery_chargerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value);
            if (ret != sizeof(std::uint16_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static int battery_chargerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value);
        std::pair<int, std::uint16_t> fuelGaugeRead(Registers registerAddress)
        {
            std::uint16_t value;
            int status                  = kStatus_Success;
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Read(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint16_t));

            if (ret != sizeof(std::uint16_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static int battery_chargerTopControllerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value);
        int chargerWrite(Registers registerAddress, std::uint8_t value)
        {
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret =
                i2c->Write(batteryChargerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint8_t));

static int battery_chargerTopControllerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value);
            if (ret != sizeof(std::uint8_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static bsp::batteryRetval battery_setAvgCalcPeriods(void);
        std::pair<int, std::uint8_t> chargerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                       = kStatus_Success;
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret                         = i2c->Read(batteryChargerAddress, &value, sizeof(std::uint8_t));

            if (ret != sizeof(std::uint8_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static bsp::batteryRetval battery_setAvgCalcPeriods(void);
        int chargerTopControllerWrite(Registers registerAddress, std::uint8_t value)
        {
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(topControllerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint8_t));

static bsp::batteryRetval battery_setNominalBatteryCapacity(uint16_t capacity);
            if (ret != sizeof(std::uint8_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static bsp::batteryRetval battery_setChargingDischargingThresholds(uint8_t chargedThresholdPercent,
                                                                   uint8_t dischargedThresholdPercent);
        std::pair<int, std::uint8_t> chargerTopControllerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                      = kStatus_Success;
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret                        = i2c->Read(topControllerAddress, &value, sizeof(std::uint8_t));
            if (ret != sizeof(std::uint8_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static bsp::batteryRetval battery_setTemperatureThresholds(uint8_t maxTemperatureDegrees,
                                                           uint8_t minTemperatureDegrees);
        batteryRetval loadConfiguration()
        {
            auto fd = std::fopen(cfgFile.c_str(), "r");
            if (fd == nullptr) {
                LOG_WARN("Configuration file [%s] could not be opened. Trying to open file [%s]",
                         cfgFile.c_str(),
                         cfgFilePrev.c_str());
                fd = std::fopen(cfgFilePrev.c_str(), "r");
                if (fd == nullptr) {
                    LOG_WARN("Configuration file [%s] could not be opened.", cfgFilePrev.c_str());
                    return batteryRetval::ChargerError;
                }
            }

            std::uint16_t regValue = 0;
            for (auto i = 0; i < 0xff; ++i) {
                if (std::fread(&regValue, sizeof(regValue), 1, fd) != sizeof(regValue)) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }

                if (fuelGaugeWrite(static_cast<Registers>(i), regValue) != kStatus_Success) {
                    LOG_ERROR("Writing register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }
            }

static bsp::batteryRetval battery_setServiceVoltageThresholds(uint16_t maxVoltage_mV, uint16_t minVoltage_mV);
            std::fclose(fd);
            return batteryRetval::OK;
        }

static bsp::batteryRetval battery_enableFuelGuageIRQs(void);
        batteryRetval storeConfiguration()
        {
            // TODO:M.P procedure below seems to crash system, it should be fixed.
            if (ff_rename(cfgFile.c_str(), cfgFilePrev.c_str(), false) != 0) {
                LOG_ERROR("Could not move configuration file");
                return batteryRetval::ChargerError;
            }

            auto fd = std::fopen(cfgFile.c_str(), "w");
            if (fd == nullptr) {
                LOG_ERROR("Could not open configuration file");
                return batteryRetval::ChargerError;
            }

            for (unsigned int i = 0; i < 0xff; ++i) {
                auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                if (regVal.first != kStatus_Success) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }

                if (std::fwrite(&regVal.second, sizeof(regVal.second), 1, fd) != sizeof(regVal.second)) {
                    LOG_ERROR("Storing register 0x%x failed.", i);
                    std::fclose(fd);
                    std::remove(cfgFile.c_str());
                    return batteryRetval::ChargerError;
                }
            }

static bsp::batteryRetval battery_enableTopIRQs(void);
            std::fclose(fd);
            return batteryRetval::OK;
        }

static bsp::batteryRetval battery_configureAlerts();
        batteryRetval setAvgCalcPeriods()
        {
            std::uint16_t regVal = 0;
            regVal |= (BATT_SERVICE_AVG_CURRENT_PERIOD << 0);
            regVal |= (BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD << 4);
            regVal |= (BATT_SERVICE_AVG_MIXING_PERIOD << 7);
            regVal |= (BATT_SERVICE_AVG_TEMP_PERIOD << 11);
            regVal |= (BATT_SERVICE_AVG_NEMPTY_PERIOD << 14);

            if (fuelGaugeWrite(Registers::FilterCFG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setAvgCalcPeriods failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

static void s_BSP_BatteryChargerIrqPinsInit();
        batteryRetval setNominalBatteryCapacity(std::uint16_t capacity)
        {
            std::uint16_t regVal = capacity * 2;

static xQueueHandle qHandleIrq = NULL;
            if (fuelGaugeWrite(Registers::DesignCap_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setNominalBatteryCapacity failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

namespace bsp
{
        batteryRetval setChargingDischargingThresholds(std::uint8_t chargedThresholdPercent,
                                                       std::uint8_t dischargedThresholdPercent)
        {
            uint16_t regVal = (chargedThresholdPercent << 8) | dischargedThresholdPercent;

    // STATUS register bits
    enum B_STATUS
    {
        Inm    = (1 << 0),
        POR    = (1 << 1),
        SPR_2  = (1 << 2),
        BST    = (1 << 3),
        Isysmx = (1 << 4),
        SPR_5  = (1 << 5),
        ThmHot = (1 << 6),
        dSOCi  = (1 << 7),
        Vmn    = (1 << 8),
        Tmn    = (1 << 9),
        Smn    = (1 << 10),
        Bi     = (1 << 11),
        Vmx    = (1 << 12),
        Tmx    = (1 << 13),
        Smx    = (1 << 14),
        Br     = (1 << 15),
    };

    /// CHG_INT registers from documentation
    enum B_CHG_INT
    {
        BYP_I   = (1 << 0),
        RSVD    = (1 << 1),
        BATP_I  = (1 << 2),
        BAT_I   = (1 << 3),
        CHG_I   = (1 << 4),
        WCIN_I  = (1 << 5),
        CHGIN_I = (1 << 6),
        AICL_I  = (1 << 7),
    };

    // CONFIG register bits
    enum class B_CONFIG
    {
        Ber    = 1 << 0,
        Bei    = 1 << 1,
        Aen    = 1 << 2,
        FTHRM  = 1 << 3,
        ETHRM  = 1 << 4,
        SPR_5  = 1 << 5,
        I2CSH  = 1 << 6,
        SHDN   = 1 << 7,
        Tex    = 1 << 8,
        Ten    = 1 << 9,
        AINSH  = 1 << 10,
        SPR_11 = 1 << 11,
        Vs     = 1 << 12,
        Ts     = 1 << 13,
        Ss     = 1 << 14,
        SPR_15 = 1 << 15
    };

    uint16_t battery_get_CHG_INT_OK();

    int battery_Init(xQueueHandle qHandle)
            if (fuelGaugeWrite(Registers::SALRT_Th_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setChargingDischargingThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval setTemperatureThresholds(std::uint8_t maxTemperatureDegrees, std::uint8_t minTemperatureDegrees)
        {
            std::uint16_t regVal = (maxTemperatureDegrees << 8) | minTemperatureDegrees;

            if (fuelGaugeWrite(Registers::TALRT_Th_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setTemperatureThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval setServiceVoltageThresholds(std::uint16_t maxVoltage_mV, std::uint16_t minVoltage_mV)
        {
            std::uint16_t regVal = ((maxVoltage_mV / 20) << 8) | (minVoltage_mV / 20);

            if (fuelGaugeWrite(Registers::VALRT_Th_REG, regVal) != kStatus_Success) {

                LOG_ERROR("setServiceVoltageThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval enableFuelGuageIRQs()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG2::dSOCen);

            if (fuelGaugeWrite(Registers::CONFIG2_REG, regVal) != kStatus_Success) {
                LOG_ERROR("enableFuelGuageIRQs failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval configureAlerts()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG::Aen);

            if (fuelGaugeWrite(Registers::CONFIG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("configureAlerts failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval enableTopIRQs()
        {
            std::uint8_t val = ENABLE_ALL_IRQ_MASK;

            if (chargerTopControllerWrite(Registers::TOP_CONTROLL_IRQ_MASK_REG, val) != kStatus_Success) {
                LOG_ERROR("enableIRQs read failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        void IRQPinsInit()
        {
            gpio =
                drivers::DriverGPIO::Create(static_cast<drivers::GPIOInstances>(BoardDefinitions::BATTERY_CHARGER_GPIO),
                                            drivers::DriverGPIOParams{});

            drivers::DriverGPIOPinParams INOKBPinConfig;
            INOKBPinConfig.dir      = drivers::DriverGPIOPinParams::Direction::Input;
            INOKBPinConfig.irqMode  = drivers::DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge;
            INOKBPinConfig.defLogic = 0;
            INOKBPinConfig.pin      = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN);
            gpio->ConfPin(INOKBPinConfig);

            drivers::DriverGPIOPinParams INTBPinConfig;
            INTBPinConfig.dir      = drivers::DriverGPIOPinParams::Direction::Input;
            INTBPinConfig.irqMode  = drivers::DriverGPIOPinParams::InterruptMode::IntFallingEdge;
            INTBPinConfig.defLogic = 0;
            INTBPinConfig.pin      = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN);
            gpio->ConfPin(INTBPinConfig);

            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
        }
    } // namespace

    int init(xQueueHandle queueHandle)
    {
        i2c = DriverI2C::Create(
            static_cast<I2CInstances>(BoardDefinitions::BATTERY_CHARGER_I2C),
            DriverI2CParams{.baudrate = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_I2C_BAUDRATE)});
        drivers::DriverI2CParams i2cParams;
        i2cParams.baudrate = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_I2C_BAUDRATE);
        i2c = drivers::DriverI2C::Create(static_cast<drivers::I2CInstances>(BoardDefinitions::BATTERY_CHARGER_I2C),
                                         i2cParams);

        qHandleIrq = qHandle;
        IRQQueueHandle = queueHandle;

        // check Power-On reset bit
        uint16_t status        = 0;
        const uint16_t porMask = 0x0002;
        battery_fuelGaugeRead(bsp::batteryChargerRegisters::STATUS_REG, &status);
        std::uint16_t status = fuelGaugeRead(Registers::STATUS_REG).second;

        if (status & porMask) {
        if (status & static_cast<std::uint16_t>(STATUS::POR)) {
            LOG_INFO("Initializing battery charger");
            battery_loadConfiguration();
            battery_setAvgCalcPeriods();
            battery_setNominalBatteryCapacity(battery_nominalCapacitymAh);
            battery_setChargingDischargingThresholds(battery_fullyChargedPercent, battery_DischargedPercent);
            battery_setTemperatureThresholds(battery_maxTemperatureDegrees, battery_minTemperatureDegrees);
            battery_setServiceVoltageThresholds(battery_maxVoltagemV, battery_minVoltagemV);
            loadConfiguration();
            setAvgCalcPeriods();
            setNominalBatteryCapacity(nominalCapacitymAh);
            setChargingDischargingThresholds(fullyChargedPercent, DischargedPercent);
            setTemperatureThresholds(maxTemperatureDegrees, minTemperatureDegrees);
            setServiceVoltageThresholds(maxVoltagemV, minVoltagemV);
        }

        battery_configureAlerts();
        battery_enableFuelGuageIRQs();
        configureAlerts();
        enableFuelGuageIRQs();

        uint8_t level = 0;
        bool charging = false;
        battery_getBatteryLevel(level);
        battery_getChargeStatus(charging);
        StateOfCharge level = getBatteryLevel();
        bool charging       = getChargeStatus();
        LOG_INFO("Phone battery start state: %d %d", level, charging);

        battery_ClearAllIRQs();
        battery_enableTopIRQs();
        clearAllIRQs();
        enableTopIRQs();

        s_BSP_BatteryChargerIrqPinsInit();
        IRQPinsInit();

        return 0;
    }

    void battery_Deinit(void)
    void deinit()
    {
        battery_storeConfiguration();
        storeConfiguration();

        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB));

        qHandleIrq = NULL;
        IRQQueueHandle = nullptr;

        i2c.reset();
        gpio.reset();
    }

    void battery_getBatteryLevel(uint8_t &levelPercent)
    StateOfCharge getBatteryLevel()
    {
        uint16_t val = 0;
        if (battery_fuelGaugeRead(bsp::batteryChargerRegisters::RepSOC_REG, &val) != kStatus_Success) {
        auto readout = fuelGaugeRead(Registers::RepSOC_REG);
        if (readout.first != kStatus_Success) {
            LOG_ERROR("failed to get battery percent");
        }
        levelPercent                   = (val & 0xff00) >> 8;
        StateOfCharge levelPercent     = (readout.second & 0xff00) >> 8;
        Store::Battery::modify().level = levelPercent;
        return levelPercent;
    }

    void battery_getChargeStatus(bool &status)
    bool getChargeStatus()
    {
        uint8_t val = 0;
        std::uint8_t val = 0;
        // read clears state
        if (battery_chargerRead(bsp::batteryChargerRegisters::CHG_INT_OK, &val) != kStatus_Success) {
        auto value = chargerRead(Registers::CHG_INT_OK);
        if (value.first != kStatus_Success) {
            LOG_ERROR("failed to read charge status");
        }
        status = val & B_CHG_INT::CHGIN_I;
        bool status = value.second & static_cast<std::uint8_t>(CHG_INT::CHGIN_I);
        if (status) {
            Store::Battery::modify().state = Store::Battery::State::Charging;
        }
        else {
            Store::Battery::modify().state = Store::Battery::State::Discharging;
        }
        return status;
    }

    std::uint16_t battery_getStatusRegister()
    std::uint16_t getStatusRegister()
    {
        uint16_t status = 0;
        battery_fuelGaugeRead(bsp::batteryChargerRegisters::STATUS_REG, &status);
        return status;
        auto status = fuelGaugeRead(Registers::STATUS_REG);
        return status.second;
    }

    void battery_ClearAllIRQs(void)
    void clearAllIRQs()
    {
        uint8_t val = 0;
        battery_chargerRead(bsp::batteryChargerRegisters::CHG_INT_REG, &val);
        if (val != 0) {
        auto value = chargerRead(Registers::CHG_INT_REG);
        if (value.second != 0) {
            // write zero to clear irq source
            battery_chargerWrite(bsp::batteryChargerRegisters::CHG_INT_REG, 0);
            chargerWrite(Registers::CHG_INT_REG, 0);
        }

        uint16_t status = battery_getStatusRegister();
        std::uint16_t status = getStatusRegister();
        if (status != 0) {
            // write zero to clear irq source
            battery_fuelGaugeWrite(bsp::batteryChargerRegisters::STATUS_REG, 0);
            fuelGaugeWrite(Registers::STATUS_REG, 0);
        }
    }

    void battery_clearFuelGuageIRQ(void)
    void clearFuelGuageIRQ()
    {
        // write zero to clear interrupt source
        battery_fuelGaugeWrite(bsp::batteryChargerRegisters::STATUS_REG, 0x0000);
        fuelGaugeWrite(Registers::STATUS_REG, 0x0000);
    }

} // namespace bsp

static int battery_fuelGaugeWrite(bsp::batteryChargerRegisters registerAddress, uint16_t value)
{
    I2CAddress addr{.deviceAddress  = BSP_FUEL_GAUGE_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint16_t));

    if (ret != sizeof(uint16_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_fuelGaugeRead(bsp::batteryChargerRegisters registerAddress, uint16_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_FUEL_GAUGE_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, reinterpret_cast<uint8_t *>(value), sizeof(uint16_t));

    if (ret != sizeof(uint16_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value)
{

    I2CAddress addr{.deviceAddress  = BSP_BATTERY_CHARGER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint8_t));

    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_BATTERY_CHARGER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, value, sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerTopControllerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value)
{

    I2CAddress addr{.deviceAddress  = BSP_TOP_CONTROLLER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerTopControllerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value)
    __attribute__((used));
static int battery_chargerTopControllerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_TOP_CONTROLLER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, reinterpret_cast<uint8_t *>(value), sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static bsp::batteryRetval battery_loadConfiguration(void)
{
    auto fd = std::fopen(configs::battery_cfgFile.c_str(), "r");
    if (fd == NULL) {
        LOG_WARN("Configuration file [%s] not found. Searching for file [%s]",
                 configs::battery_cfgFile.c_str(),
                 configs::battery_cfgFilePrev.c_str());
        fd = std::fopen(configs::battery_cfgFilePrev.c_str(), "r");
        if (fd == NULL) {
            LOG_WARN("Configuration file [%s] not found.", configs::battery_cfgFilePrev.c_str());
            return bsp::batteryRetval::battery_ChargerError;
        }
    }

    uint16_t regValue = 0;
    for (uint8_t i = 0; i < 0xff; ++i) {
        if (std::fread(&regValue, sizeof(regValue), 1, fd) != sizeof(regValue)) {
            LOG_ERROR("Reading register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
        }

        if (battery_fuelGaugeWrite(static_cast<bsp::batteryChargerRegisters>(i), regValue) != kStatus_Success) {
            LOG_ERROR("Writing register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
    BaseType_t INOKB_IRQHandler()
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        if (IRQQueueHandle != nullptr) {
            std::uint8_t val = static_cast<std::uint8_t>(batteryIRQSource::INOKB);
            xQueueSendFromISR(IRQQueueHandle, &val, &xHigherPriorityTaskWoken);
        }
        return xHigherPriorityTaskWoken;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_storeConfiguration(void)
{
    // TODO:M.P procedure below seems to crash system, it should be fixed.
    if (rename(configs::battery_cfgFile.c_str(), configs::battery_cfgFilePrev.c_str()) != 0) {
        LOG_ERROR("Could not move configuration file");
        return bsp::batteryRetval::battery_ChargerError;
    }

    auto fd = std::fopen(configs::battery_cfgFile.c_str(), "w");
    if (fd == NULL) {
        LOG_ERROR("Could not open configuration file");
        return bsp::batteryRetval::battery_ChargerError;
    }

    uint16_t regVal = 0;
    for (unsigned int i = 0; i < 0xff; ++i) {
        if (battery_fuelGaugeRead(static_cast<bsp::batteryChargerRegisters>(i), &regVal) != kStatus_Success) {
            LOG_ERROR("Reading register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
        }

        if (std::fwrite(&regVal, sizeof(regVal), 1, fd) != sizeof(regVal)) {
            LOG_ERROR("Storing register 0x%x failed.", i);
            std::fclose(fd);
            std::remove(configs::battery_cfgFile.c_str());
            return bsp::batteryRetval::battery_ChargerError;
    BaseType_t INTB_IRQHandler()
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        if (IRQQueueHandle != nullptr) {
            std::uint8_t val = static_cast<std::uint8_t>(batteryIRQSource::INTB);
            xQueueSendFromISR(IRQQueueHandle, &val, &xHigherPriorityTaskWoken);
        }
        return xHigherPriorityTaskWoken;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setAvgCalcPeriods(void)
{
    uint16_t regVal = 0;
    regVal |= (BATT_SERVICE_AVG_CURRENT_PERIOD << 0);
    regVal |= (BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD << 4);
    regVal |= (BATT_SERVICE_AVG_MIXING_PERIOD << 7);
    regVal |= (BATT_SERVICE_AVG_TEMP_PERIOD << 11);
    regVal |= (BATT_SERVICE_AVG_NEMPTY_PERIOD << 14);

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::FilterCFG_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setAvgCalcPeriods failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setNominalBatteryCapacity(uint16_t capacity)
{
    uint16_t regVal = capacity * 2;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::DesignCap_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setNominalBatteryCapacity failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setChargingDischargingThresholds(uint8_t chargedThresholdPercent,
                                                                   uint8_t dischargedThresholdPercent)
{
    uint16_t regVal = (chargedThresholdPercent << 8) | dischargedThresholdPercent;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::SALRT_Th_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setChargingDischargingThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setTemperatureThresholds(uint8_t maxTemperatureDegrees, uint8_t minTemperatureDegrees)
{
    uint16_t regVal = (maxTemperatureDegrees << 8) | minTemperatureDegrees;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::TALRT_Th_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setTemperatureThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setServiceVoltageThresholds(uint16_t maxVoltage_mV, uint16_t minVoltage_mV)
{
    uint16_t regVal = ((maxVoltage_mV / 20) << 8) | (minVoltage_mV / 20);

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::VALRT_Th_REG, regVal) != kStatus_Success) {

        LOG_ERROR("battery_setServiceVoltageThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_enableFuelGuageIRQs(void)
{
    uint16_t regVal = 0;
    // set dSOCen bit
    regVal |= (1 << 7);
    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::CONFIG2_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_enableFuelGuageIRQs failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_configureAlerts()
{
    auto regVal = static_cast<std::uint16_t>(bsp::B_CONFIG::Aen); // Enable alerts

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::CONFIG_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_configureAlerts failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_enableTopIRQs(void)
{
    uint8_t val = 0xf8;

    if (battery_chargerTopControllerWrite(bsp::batteryChargerRegisters::TOP_CONTROLL_IRQ_MASK_REG, val) !=
        kStatus_Success) {
        LOG_ERROR("battery_enableIRQs read failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

BaseType_t BSP_BatteryChargerINOKB_IRQHandler()
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (qHandleIrq != NULL) {
        uint8_t val = static_cast<uint8_t>(bsp::batteryIRQSource::INOKB);
        xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
    }
    return xHigherPriorityTaskWoken;
}

BaseType_t BSP_BatteryChargerINTB_IRQHandler()
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (qHandleIrq != NULL) {
        uint8_t val = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
        xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
    }
    return xHigherPriorityTaskWoken;
}

static void s_BSP_BatteryChargerIrqPinsInit()
{

    gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::BATTERY_CHARGER_GPIO), DriverGPIOParams{});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN)});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB)});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN)});

    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB));
    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
}
} // namespace bsp::battery_charger

M module-bsp/board/rt1051/common/irq/irq_gpio.cpp => module-bsp/board/rt1051/common/irq/irq_gpio.cpp +2 -3
@@ 19,7 19,6 @@
#if 0 // TODO:M.P implement the rest of BSP drivers

#include "bsp_cellular.h"
#include "bsp_battery_charger.h"

#include "bsp_usbc.h"
#include "log.h"


@@ 114,13 113,13 @@ namespace bsp
            }

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_INOKB_PIN)) {
                xHigherPriorityTaskWoken |= BSP_BatteryChargerINOKB_IRQHandler();
                xHigherPriorityTaskWoken |= bsp::battery_charger::INOKB_IRQHandler();
            }

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_WCINOKB_PIN)) {}

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_INTB_PIN)) {
                xHigherPriorityTaskWoken |= BSP_BatteryChargerINTB_IRQHandler();
                xHigherPriorityTaskWoken |= bsp::battery_charger::INTB_IRQHandler();
            }

            if (irq_mask & (1 << BSP_CELLULAR_SIM_TRAY_INSERTED_PIN)) {

M module-bsp/bsp/battery-charger/battery_charger.hpp => module-bsp/bsp/battery-charger/battery_charger.hpp +28 -102
@@ 1,99 1,25 @@
/*
 * battery_charger.hpp
 *
 *  Created on: Jun 28, 2019
 *      Author: kuba
 */
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#define MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#pragma once

#include <cstdint>
namespace bsp{

	enum class batteryChargerRegisters{
		TOP_CONTROLL_PMIC_ID_REG = 0x20,
		TOP_CONTROLL_PMIC_VER_REG = 0x21,
		TOP_CONTROLL_IRQ_SRC_REG = 0x22,
		TOP_CONTROLL_IRQ_MASK_REG = 0x23,
		SYSTEM_IRQ_REG = 0x24,

		STATUS_REG = 0x00,
		VALRT_Th_REG = 0x01,
		TALRT_Th_REG = 0x02,
		SALRT_Th_REG = 0x03,
		AtRate_REG = 0x04,
		RepCap_REG = 0x05,
		RepSOC_REG = 0x06,
		Age_REG = 0x07,
		TEMP_REG = 0x08,
		VCELL_REG = 0x09,
		Current_REG = 0x0A,
		AvgCurrent_REG = 0x0B,
		QResidual_REG = 0x0C,
		MixSOC_REG = 0x0D,
		AvSOC_REG = 0x0E,
		MixCap_REG = 0x0F,

		FullCAP_REG = 0x10,
		TTE_REG = 0x11,
		QRtable00_REG = 0x12,
		FullSOCthr_REG = 0x13,
		RSLOW_REG = 0x14,
		AvgTA_REG = 0x16,
		Cycles_REG = 0x17,
		DesignCap_REG = 0x18,
		AvgVCELL_REG = 0x19,
		MaxMinTemp_REG = 0x1A,
		MaxMinVolt_REG = 0x1B,
		MaxMinCurr_REG = 0x1C,
		CONFIG_REG = 0x1D,
		CONFIG2_REG = 0xBB,
		ICHGTERM_REG = 0x1E,
		AvCap_REG = 0x1F,

		TTF_REG = 0x20,
		DevName_REG = 0x21,
		QRtable10_REG = 0x22,
		FullCAPNom_REG = 0x23,
		TempNom_REG = 0x24,
		TempLim_REG = 0x25,
		AIN0_REG = 0x27,
		LearnCFG_REG = 0x28,
		FilterCFG_REG = 0x29,
		RelaxCFG_REG = 0x2A,
		MiscCFG_REG = 0x2B,
		TGAIN_REG = 0x2C,
		TOFF_REG = 0x2D,
		CGAIN_REG = 0x2E,
		COFF_REG = 0x2F,

		QRtable20_REG = 0x32,
		AtTTF_REG = 0x33,
		FullCapRep_REG = 0x35,
		lavgEmpty_REG = 0x36,
		FCTC_REG = 0x37,
		RCOMP0_REG = 0x38,
		TempCo_REG = 0x39,
		VEmpty_REG = 0x3A,
		TIMER_REG = 0x3E,
		SHDNTIMER_REG = 0x3F,

		QRtable30_REG = 0x42,
		dQ_acc_REG = 0x45,
		dP_acc_REG = 0x46,
		ConvgCfg_REG = 0x49,
		VFRemCap_REG = 0x4A,
		QH_REG = 0x4D,
		CHG_INT_REG = 0xb0,
		CHG_INT_OK = 0xb2
	};
extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

namespace bsp::battery_charger
{
	using StateOfCharge = std::uint8_t;

	enum class batteryRetval{
		battery_OK = 0,
		battery_ChargerError,
		battery_ChargerNotCharging,
		battery_ChargerCharging
		OK,
		ChargerError,
		ChargerNotCharging,
		ChargerCharging
	};

	enum class batteryIRQSource{


@@ 107,24 33,24 @@ namespace bsp{
		SOCOnePercentChange = 1 << 7
	};

	int battery_Init(xQueueHandle qHandle);
	int init(xQueueHandle queueHandle);

	void battery_Deinit(void);
	void deinit();

	void battery_getBatteryLevel(uint8_t& levelPercent);
	StateOfCharge getBatteryLevel();

	void battery_getChargeStatus( bool& status);
	bool getChargeStatus();

	void battery_ClearAllIRQs(void);
	void clearAllIRQs();

	void battery_clearFuelGuageIRQ(void);
	void clearFuelGuageIRQ();

	std::uint16_t battery_getStatusRegister();
}
	std::uint16_t getStatusRegister();

	BaseType_t INOKB_IRQHandler();

BaseType_t BSP_BatteryChargerINOKB_IRQHandler();
	BaseType_t INTB_IRQHandler();
} // bsp::battery_charger

BaseType_t BSP_BatteryChargerINTB_IRQHandler();


#endif /* MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_*/

M module-db/Common/Query.cpp => module-db/Common/Query.cpp +1 -1
@@ 21,7 21,7 @@ bool QueryCallback::handleQueryResponse(QueryResult *response)
    return callback(response);
}

EndpointListener::EndpointListener(EndpointQueryCallbackFunction &&_callback, Context &_context)
EndpointListener::EndpointListener(EndpointQueryCallbackFunction &&_callback, parserFSM::Context &_context)
    : callback{std::move(_callback)}, context{_context}
{}


M module-db/Common/Query.hpp => module-db/Common/Query.hpp +3 -5
@@ 9,13 9,11 @@
#include <log/log.hpp>
#include <module-services/service-desktop/endpoints/Context.hpp>

using namespace parserFSM;

namespace db
{
    class QueryResult; // Forward declaration
    using QueryCallbackFunction         = std::function<bool(db::QueryResult *)>;
    using EndpointQueryCallbackFunction = std::function<bool(db::QueryResult *, Context &)>;
    using EndpointQueryCallbackFunction = std::function<bool(db::QueryResult *, parserFSM::Context &)>;

    class QueryListener
    {


@@ 42,13 40,13 @@ namespace db
    {
      public:
        EndpointListener() = default;
        EndpointListener(EndpointQueryCallbackFunction &&_callback, Context &_context);
        EndpointListener(EndpointQueryCallbackFunction &&_callback, parserFSM::Context &_context);

        bool handleQueryResponse(db::QueryResult *result) override;

      private:
        EndpointQueryCallbackFunction callback;
        Context context;
        parserFSM::Context context;
    };

    /// virtual query input interface

M module-db/Interface/AlarmsRecord.hpp => module-db/Interface/AlarmsRecord.hpp +1 -1
@@ 28,7 28,7 @@ namespace db::query::alarms

struct AlarmsRecord : public Record
{
    TimePoint time     = TIME_POINT_INVALID;
    calendar::TimePoint time = TIME_POINT_INVALID;
    uint32_t snooze    = 0;
    AlarmStatus status = AlarmStatus::On;
    uint32_t repeat    = 0;

M module-db/Interface/EventsRecord.cpp => module-db/Interface/EventsRecord.cpp +5 -4
@@ 70,8 70,8 @@ bool EventsRecordInterface::Add(const EventsRecord &rec)
    return false;
}

std::vector<EventsRecord> EventsRecordInterface::Select(TimePoint filter_from,
                                                        TimePoint filter_till,
std::vector<EventsRecord> EventsRecordInterface::Select(calendar::TimePoint filter_from,
                                                        calendar::TimePoint filter_till,
                                                        uint32_t offset,
                                                        uint32_t limit)
{


@@ 265,12 265,13 @@ uint32_t EventsRecordInterface::GetCount()
    return eventsDb->events.count();
}

uint32_t EventsRecordInterface::GetCountFiltered(TimePoint from, TimePoint till)
uint32_t EventsRecordInterface::GetCountFiltered(calendar::TimePoint from, calendar::TimePoint till)
{
    return eventsDb->events.countFromFilter(from, till);
}

std::vector<EventsRecord> EventsRecordInterface::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
std::vector<EventsRecord> EventsRecordInterface::SelectFirstUpcoming(calendar::TimePoint filter_from,
                                                                     calendar::TimePoint filter_till)
{
    auto rows = eventsDb->events.SelectFirstUpcoming(filter_from, filter_till);


M module-db/Interface/EventsRecord.hpp => module-db/Interface/EventsRecord.hpp +9 -6
@@ 41,11 41,11 @@ struct EventsRecord : public Record
{
    std::string UID;
    std::string title;
    TimePoint date_from;
    TimePoint date_till;
    calendar::TimePoint date_from;
    calendar::TimePoint date_till;
    uint32_t reminder = 0;
    uint32_t repeat   = 0;
    TimePoint reminder_fired;
    calendar::TimePoint reminder_fired;
    std::string provider_type;
    std::string provider_id;
    std::string provider_iCalUid;


@@ 77,15 77,18 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF
    EventsRecord GetByID(uint32_t id) override final;
    EventsRecord GetByUID(const std::string &uid);
    uint32_t GetCount() override final;
    uint32_t GetCountFiltered(TimePoint from, TimePoint till);
    std::vector<EventsRecord> Select(TimePoint filter_from, TimePoint filter_till, uint32_t offset, uint32_t limit);
    uint32_t GetCountFiltered(calendar::TimePoint from, calendar::TimePoint till);
    std::vector<EventsRecord> Select(calendar::TimePoint filter_from,
                                     calendar::TimePoint filter_till,
                                     uint32_t offset,
                                     uint32_t limit);
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffset(uint32_t offset, uint32_t limit) override final;
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffsetByField(uint32_t offset,
                                                                     uint32_t limit,
                                                                     EventsRecordField field,
                                                                     const char *str) override final;
    std::vector<EventsRecord> GetLimitOffsetByDate(uint32_t offset, uint32_t limit);
    std::vector<EventsRecord> SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
    std::vector<EventsRecord> SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);

    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;


M module-db/Tables/AlarmsTable.cpp => module-db/Tables/AlarmsTable.cpp +1 -1
@@ 9,7 9,7 @@ AlarmsTableRow::AlarmsTableRow(const AlarmsRecord &rec)
{}

AlarmsTableRow::AlarmsTableRow(
    uint32_t id, TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path)
    uint32_t id, calendar::TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path)
    : Record{id}, time{time}, snooze{snooze}, status{status}, repeat{repeat}, path{std::move(path)}
{}


M module-db/Tables/AlarmsTable.hpp => module-db/Tables/AlarmsTable.hpp +3 -2
@@ 25,14 25,15 @@ enum class AlarmStatus

struct AlarmsTableRow : public Record
{
    TimePoint time     = TIME_POINT_INVALID;
    calendar::TimePoint time = TIME_POINT_INVALID;
    uint32_t snooze    = 0;
    AlarmStatus status = AlarmStatus::On;
    uint32_t repeat    = 0;
    UTF8 path;

    AlarmsTableRow() = default;
    AlarmsTableRow(uint32_t id, TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path);
    AlarmsTableRow(
        uint32_t id, calendar::TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path);
    explicit AlarmsTableRow(const AlarmsRecord &rec);
    explicit AlarmsTableRow(const QueryResult &result);
};

M module-db/Tables/EventsTable.cpp => module-db/Tables/EventsTable.cpp +5 -4
@@ 643,8 643,8 @@ EventsTableRow EventsTable::getByUID(const std::string &UID)
    };
}

std::vector<EventsTableRow> EventsTable::selectByDatePeriod(TimePoint date_filter,
                                                            TimePoint filter_till,
std::vector<EventsTableRow> EventsTable::selectByDatePeriod(calendar::TimePoint date_filter,
                                                            calendar::TimePoint filter_till,
                                                            uint32_t offset,
                                                            uint32_t limit)
{


@@ 770,7 770,7 @@ uint32_t EventsTable::count()
    return (*queryRet)[0].getUInt32();
}

uint32_t EventsTable::countFromFilter(TimePoint from, TimePoint till)
uint32_t EventsTable::countFromFilter(calendar::TimePoint from, calendar::TimePoint till)
{
    auto queryRet = db->query(
        "SELECT COUNT(*) FROM events WHERE date_from >= date('%q') AND date_from < date('%q', 'start of day');",


@@ 791,7 791,8 @@ uint32_t EventsTable::countByFieldId(const char *field, uint32_t id)
    return 0;
}

std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(calendar::TimePoint filter_from,
                                                             calendar::TimePoint filter_till)
{
    auto retQuery = db->query("SELECT DATETIME(date_from, '-' || reminder || ' minutes') AS calc_dt, * "
                              "FROM events "

M module-db/Tables/EventsTable.hpp => module-db/Tables/EventsTable.hpp +7 -7
@@ 14,11 14,11 @@ struct EventsTableRow : public Record
{
    std::string UID;
    std::string title;
    TimePoint date_from      = TIME_POINT_INVALID;
    TimePoint date_till      = TIME_POINT_INVALID;
    calendar::TimePoint date_from      = TIME_POINT_INVALID;
    calendar::TimePoint date_till      = TIME_POINT_INVALID;
    uint32_t reminder        = 0;
    uint32_t repeat          = 0;
    TimePoint reminder_fired = TIME_POINT_INVALID;
    calendar::TimePoint reminder_fired = TIME_POINT_INVALID;
    std::string provider_type;
    std::string provider_id;
    std::string provider_iCalUid;


@@ 53,12 53,12 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
    bool drop();
    EventsTableRow getByUID(const std::string &UID);
    EventsTableRow getById(uint32_t id) override final;
    std::vector<EventsTableRow> selectByDatePeriod(TimePoint filter_from,
                                                   TimePoint filter_till,
    std::vector<EventsTableRow> selectByDatePeriod(calendar::TimePoint filter_from,
                                                   calendar::TimePoint filter_till,
                                                   uint32_t offset,
                                                   uint32_t limit);
    uint32_t count() override final;
    uint32_t countFromFilter(TimePoint from, TimePoint till);
    uint32_t countFromFilter(calendar::TimePoint from, calendar::TimePoint till);
    uint32_t countByFieldId(const char *field, uint32_t id) override final;
    std::vector<EventsTableRow> getLimitOffset(uint32_t offset, uint32_t limit) override final;
    std::vector<EventsTableRow> getLimitOffsetByField(uint32_t offset,


@@ 67,7 67,7 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
                                                      const char *str) override final;

    std::vector<EventsTableRow> getLimitOffsetByDate(uint32_t offset, uint32_t limit);
    std::vector<EventsTableRow> SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
    std::vector<EventsTableRow> SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);

  private:
    const char *createTableQuery = "CREATE TABLE IF NOT EXISTS events("

M module-db/queries/calendar/QueryEventsGetFiltered.cpp => module-db/queries/calendar/QueryEventsGetFiltered.cpp +4 -1
@@ 5,7 5,10 @@

namespace db::query::events
{
    GetFiltered::GetFiltered(TimePoint filter_from, TimePoint filter_till, uint32_t offset, uint32_t limit)
    GetFiltered::GetFiltered(calendar::TimePoint filter_from,
                             calendar::TimePoint filter_till,
                             uint32_t offset,
                             uint32_t limit)
        : Query(Query::Type::Read), filter_from(filter_from), filter_till(filter_till), offset(offset), limit(limit)
    {}


M module-db/queries/calendar/QueryEventsGetFiltered.hpp => module-db/queries/calendar/QueryEventsGetFiltered.hpp +6 -3
@@ 13,11 13,14 @@ namespace db::query::events
    class GetFiltered : public Query
    {
      public:
        GetFiltered(TimePoint filter_from, TimePoint filter_till, uint32_t offset = 0, uint32_t limit = UINT32_MAX);
        GetFiltered(calendar::TimePoint filter_from,
                    calendar::TimePoint filter_till,
                    uint32_t offset = 0,
                    uint32_t limit  = UINT32_MAX);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        TimePoint filter_from;
        TimePoint filter_till;
        calendar::TimePoint filter_from;
        calendar::TimePoint filter_till;
        uint32_t offset;
        uint32_t limit;
    };

M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp => module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp +1 -1
@@ 5,7 5,7 @@

namespace db::query::events
{
    SelectFirstUpcoming::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
    SelectFirstUpcoming::SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till)
        : Query(Query::Type::Read), filter_from(filter_from), filter_till(filter_till)
    {}


M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp => module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp +3 -3
@@ 14,11 14,11 @@ namespace db::query::events
    class SelectFirstUpcoming : public Query
    {
      public:
        SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
        SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        TimePoint filter_from;
        TimePoint filter_till;
        calendar::TimePoint filter_from;
        calendar::TimePoint filter_till;
    };

    /// Result of SelectFirstUpcoming query

M module-db/tests/AlarmsRecord_tests.cpp => module-db/tests/AlarmsRecord_tests.cpp +1 -1
@@ 183,7 183,7 @@ TEST_CASE("Alarms Record tests")
    }

    auto getQuery = [&](uint32_t id,
                        TimePoint alarmTime,
                        calendar::TimePoint alarmTime,
                        uint32_t snooze,
                        AlarmStatus status,
                        uint32_t repeat,

M module-db/tests/AlarmsTable_tests.cpp => module-db/tests/AlarmsTable_tests.cpp +5 -5
@@ 138,11 138,11 @@ TEST_CASE("Alarms Table tests")
        REQUIRE(alarmsTbl.add(
            AlarmsTableRow(5, TimePointFromString("2020-12-11 07:15:00"), 1, AlarmStatus::On, 1, "file2.mp3")));

        const std::array<TimePoint, 5> paramTime{TimePointFromString("2020-12-11 07:15:00"),
                                                 TimePointFromString("2020-11-11 15:10:00"),
                                                 TimePointFromString("2020-11-11 15:15:00"),
                                                 TimePointFromString("2020-11-12 17:10:00"),
                                                 TimePointFromString("2020-11-11 19:25:00")};
        const std::array<calendar::TimePoint, 5> paramTime{TimePointFromString("2020-12-11 07:15:00"),
                                                           TimePointFromString("2020-11-11 15:10:00"),
                                                           TimePointFromString("2020-11-11 15:15:00"),
                                                           TimePointFromString("2020-11-12 17:10:00"),
                                                           TimePointFromString("2020-11-11 19:25:00")};

        REQUIRE(alarmsTbl.count() == 5);
        auto entries   = alarmsTbl.getLimitOffset(0, 5);

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +8 -3
@@ 22,6 22,8 @@
#include <filesystem>
#include <iostream>

using namespace std::chrono_literals;

static auto remove_events(EventsDB &db) -> bool
{
    auto count   = db.events.count();


@@ 728,7 730,7 @@ TEST_CASE("Events Record tests")

    SECTION("Select first upcoming event")
    {
        TimePoint start_date = TimePointFromString("2019-10-19 14:24:00");
        calendar::TimePoint start_date = TimePointFromString("2019-10-19 14:24:00");
        auto nextUpcoming    = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date);
        REQUIRE(nextUpcoming.size() == 1);
        EventsRecord nextEventsRecord = nextUpcoming.at(0);


@@ 797,7 799,9 @@ TEST_CASE("Events Record tests")
        getAll(expectedRecords, numberOfEvents);
    }

    auto getFiltered = [&](TimePoint filter_from, TimePoint filter_till, std::vector<EventsRecord> expected_records) {
    auto getFiltered = [&](calendar::TimePoint filter_from,
                           calendar::TimePoint filter_till,
                           std::vector<EventsRecord> expected_records) {
        auto query  = std::make_shared<db::query::events::GetFiltered>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::GetFilteredResult *>(ret.get());


@@ 1009,7 1013,8 @@ TEST_CASE("Events Record tests")
        EditQueryICS(testRecord6.UID, testRecord6);
    }

    [[maybe_unused]] auto selectFirstUpcomingEvent = [&](TimePoint filter_from, TimePoint filter_till) {
    [[maybe_unused]] auto selectFirstUpcomingEvent = [&](calendar::TimePoint filter_from,
                                                         calendar::TimePoint filter_till) {
        auto query  = std::make_shared<db::query::events::SelectFirstUpcoming>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::SelectFirstUpcomingResult *>(ret.get());

M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +50 -45
@@ 7,12 7,16 @@
#include "Databases/EventsDB.hpp"
#include "Tables/EventsTable.hpp"

#include <cstdint>
#include <filesystem>
#include <vfs.hpp>
#include <stdint.h>
#include <string>
#include <algorithm>
#include <iostream>
#include <purefs/filesystem_paths.hpp>
#include <unistd.h>

using namespace std::chrono_literals;

static auto remove_events(EventsDB &db) -> bool
{
    auto count   = db.events.count();


@@ 29,12 33,10 @@ TEST_CASE("Events Table tests")

    Database::initialize();

    const auto eventsPath = (std::filesystem::path{"user"} / "events.db");
    if (std::filesystem::exists(eventsPath)) {
        REQUIRE(std::filesystem::remove(eventsPath));
    }
    const auto eventsPath = (purefs::dir::getUserDiskPath() / "events.db").c_str();
    std::filesystem::remove(eventsPath);

    EventsDB eventsDb{eventsPath.c_str()};
    EventsDB eventsDb{eventsPath};
    REQUIRE(eventsDb.isInitialized());

    auto &eventsTbl = eventsDb.events;


@@ 164,8 166,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 7;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addDaily(testRow1));


@@ 199,8 201,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addWeekly(testRow1));


@@ 234,8 236,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addTwoWeeks(testRow1));


@@ 269,7 271,7 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 12;
        const std::array<TimePoint, 24> dates{
        const std::array<calendar::TimePoint, 24> dates{
            TimePointFromString("2019-01-20 14:30:00"), TimePointFromString("2019-01-20 15:30:00"),
            TimePointFromString("2019-02-20 14:30:00"), TimePointFromString("2019-02-20 15:30:00"),
            TimePointFromString("2019-03-20 14:30:00"), TimePointFromString("2019-03-20 15:30:00"),


@@ 295,6 297,8 @@ TEST_CASE("Events Table tests")
        uint32_t index = 0;
        for (auto entry : entries) {
            CHECK(entry.title == testRow1.title);
            CHECK(TimePointToString(entry.date_from) == TimePointToString(dates[index]));
            CHECK(TimePointToString(entry.date_till) == TimePointToString(dates[index + 1]));
            CHECK(entry.reminder == testRow1.reminder);
            CHECK(entry.repeat == testRow1.repeat);
            CHECK(entry.reminder_fired == testRow1.reminder_fired);


@@ 314,14 318,14 @@ TEST_CASE("Events Table tests")
        REQUIRE(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        std::array<TimePoint, 8> dates{TimePointFromString("2019-02-20 14:30:00"),
                                       TimePointFromString("2019-02-20 15:30:00"),
                                       TimePointFromString("2020-02-20 14:30:00"),
                                       TimePointFromString("2020-02-20 15:30:00"),
                                       TimePointFromString("2021-02-20 14:30:00"),
                                       TimePointFromString("2021-02-20 15:30:00"),
                                       TimePointFromString("2022-02-20 14:30:00"),
                                       TimePointFromString("2022-02-20 15:30:00")};
        std::array<calendar::TimePoint, 8> dates{TimePointFromString("2019-02-20 14:30:00"),
                                                 TimePointFromString("2019-02-20 15:30:00"),
                                                 TimePointFromString("2020-02-20 14:30:00"),
                                                 TimePointFromString("2020-02-20 15:30:00"),
                                                 TimePointFromString("2021-02-20 14:30:00"),
                                                 TimePointFromString("2021-02-20 15:30:00"),
                                                 TimePointFromString("2022-02-20 14:30:00"),
                                                 TimePointFromString("2022-02-20 15:30:00")};

        testRow1.date_from = dates[0];
        testRow1.date_till = dates[1];


@@ 335,6 339,8 @@ TEST_CASE("Events Table tests")
        uint32_t index = 0;
        for (auto entry : entries) {
            CHECK(entry.title == testRow1.title);
            CHECK(TimePointToString(entry.date_from) == TimePointToString(dates[index]));
            CHECK(TimePointToString(entry.date_till) == TimePointToString(dates[index + 1]));
            CHECK(entry.reminder == testRow1.reminder);
            CHECK(entry.repeat == testRow1.repeat);
            CHECK(entry.reminder_fired == testRow1.reminder_fired);


@@ 344,7 350,6 @@ TEST_CASE("Events Table tests")
            CHECK(entry.isValid());
            index += 2;
        }
        REQUIRE(index == 2 * numberOfEvents);
    }

    enum class weekDayOption


@@ 362,8 367,8 @@ TEST_CASE("Events Table tests")
    {
        auto check_custom_repeat = [&](uint32_t customRepeatOption,
                                       uint32_t numberOfEvents,
                                       TimePoint originalStartDate,
                                       TimePoint originalEndDate) {
                                       calendar::TimePoint originalStartDate,
                                       calendar::TimePoint originalEndDate) {
            if (eventsTbl.count() > 0) {
                REQUIRE(remove_events(eventsDb));
            }


@@ 391,8 396,8 @@ TEST_CASE("Events Table tests")
                }
            }

            TimePoint expectedStartDate = TimePointFromString("2020-12-07 15:30:00"); // monday
            TimePoint expectedEndDate   = TimePointFromString("2020-12-07 16:30:00"); // monday
            calendar::TimePoint expectedStartDate = TimePointFromString("2020-12-07 14:30:00"); // monday
            calendar::TimePoint expectedEndDate   = TimePointFromString("2020-12-07 15:30:00"); // monday

            uint32_t i = 0;
            for (uint32_t l = 0; l < numberOfWeeks; l++) {


@@ 434,8 439,8 @@ TEST_CASE("Events Table tests")
            uint32_t customRepeatOption =
                static_cast<uint32_t>(weekDayOption::monday) + static_cast<uint32_t>(weekDayOption::wednesday);
            uint32_t numberOfEvents     = 9;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 446,8 451,8 @@ TEST_CASE("Events Table tests")
                static_cast<uint32_t>(weekDayOption::monday) + static_cast<uint32_t>(weekDayOption::wednesday) +
                static_cast<uint32_t>(weekDayOption::tuesday) + static_cast<uint32_t>(weekDayOption::sunday);
            uint32_t numberOfEvents     = 17;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 456,8 461,8 @@ TEST_CASE("Events Table tests")
        {
            uint32_t customRepeatOption = static_cast<uint32_t>(weekDayOption::saturday);
            uint32_t numberOfEvents     = 5;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 465,8 470,8 @@ TEST_CASE("Events Table tests")

    SECTION("Check count from filter")
    {
        TimePoint from = TimePointFromString("2019-10-20 14:30:00");
        TimePoint till = TimePointFromString("2019-10-24 14:20:00");
        calendar::TimePoint from = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint till = TimePointFromString("2019-10-24 14:20:00");

        CHECK(eventsTbl.countFromFilter(from, till) == 4);
    }


@@ 511,8 516,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 6);

        std::string newTitle = "Updated Title", newProviderID = "PurePhoneUpdated";
        TimePoint newDateFrom    = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill    = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder     = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption = static_cast<uint32_t>(Repeat::biweekly);



@@ 567,8 572,8 @@ TEST_CASE("Events Table tests")

        std::string newTitle = "Updated Title", newProviderType = "PurePhoneUpdate", newProviderID = "newID",
                    newProvideriCalUid = "new iCalUid";
        TimePoint newDateFrom          = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill          = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder           = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption       = static_cast<uint32_t>(Repeat::biweekly);



@@ 625,8 630,8 @@ TEST_CASE("Events Table tests")

        std::string newTitle = "Updated Title", newProviderType = "PurePhoneUpdate", newProviderID = "newID",
                    newProvideriCalUid = "new iCalUid";
        TimePoint newDateFrom          = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill          = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder           = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption       = static_cast<uint32_t>(Repeat::biweekly);



@@ 724,11 729,11 @@ TEST_CASE("Events Table tests")
        }
        CHECK(eventsTbl.count() == 0);

        TimePoint startDate1 = TimePointFromString("2018-10-20 14:24:00");
        TimePoint startDate2 = TimePointFromString("2020-10-20 14:24:00");
        calendar::TimePoint startDate1 = TimePointFromString("2018-10-20 14:24:00");
        calendar::TimePoint startDate2 = TimePointFromString("2020-10-20 14:24:00");

        TimePoint tillDate  = TimePointFromString("2030-10-20 15:24:00");
        TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");
        calendar::TimePoint tillDate  = TimePointFromString("2030-10-20 15:24:00");
        calendar::TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");

        EventsTableRow testEvent1 = {{1},
                                     .UID              = "test1",

M module-db/tests/QueryInterface.cpp => module-db/tests/QueryInterface.cpp +2 -2
@@ 75,9 75,9 @@ TEST_CASE("Query interface")
        auto msgJson = json11::Json::parse(testMessage, err);
        REQUIRE(err.empty());

        Context context(msgJson);
        parserFSM::Context context(msgJson);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context &context) {
            [=](db::QueryResult *result, parserFSM::Context &context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetCountResult *>(result)) {
                    auto id   = SMSResult->getResults();
                    auto body = json11::Json::object{{"count", static_cast<int>(id)}};

M module-gui/gui/dom/Item2JsonSerializingVisitor.cpp => module-gui/gui/dom/Item2JsonSerializingVisitor.cpp +1 -1
@@ 85,7 85,7 @@ void Item2JsonSerializingVisitor::visit(gui::BottomBar &item)
    visit(static_cast<gui::Item &>(item));
}

void Item2JsonSerializingVisitor::visit(gui::TopBar &item)
void Item2JsonSerializingVisitor::visit(gui::top_bar::TopBar &item)
{
    if (itemName.empty()) {
        itemName = magic_enum::enum_name(visitor::Names::TopBar);

M module-gui/gui/dom/Item2JsonSerializingVisitor.hpp => module-gui/gui/dom/Item2JsonSerializingVisitor.hpp +1 -1
@@ 29,7 29,7 @@ namespace gui
        void visit(gui::Window &item) override;
        void visit(gui::Label &item) override;
        void visit(gui::BottomBar &item) override;
        void visit(gui::TopBar &item) override;
        void visit(gui::top_bar::TopBar &item) override;

      public:
        /// retrieves current state of the `sink`. The state of the `sink` after call is default-initialized

M module-gui/gui/widgets/BoxLayout.cpp => module-gui/gui/widgets/BoxLayout.cpp +6 -6
@@ 110,7 110,7 @@ namespace gui
                /// this if back / front is crappy :|
                if (previous) {
                    for (auto el = children.rbegin(); el != children.rend(); ++el) {
                        if ((*el)->visible && (*el)->activeItem) {
                        if ((*el)->isActive()) {
                            setFocusItem(*el);
                            break;
                        }


@@ 118,7 118,7 @@ namespace gui
                }
                else {
                    for (auto &el : children) {
                        if (el->visible && el->activeItem) {
                        if (el->isActive()) {
                            setFocusItem(el);
                            break;
                        }


@@ 375,7 375,7 @@ namespace gui
    std::list<Item *>::iterator BoxLayout::nextNavigationItem(std::list<Item *>::iterator from)
    {
        return std::find_if(from, this->children.end(), [](auto &el) -> bool {
            if (el->visible && el->activeItem) {
            if (el->isActive()) {
                return true;
            }
            return false;


@@ 474,7 474,7 @@ namespace gui
        bool success   = false;

        for (auto child : children) {
            if (child->activeItem && child->visible) {
            if (child->isActive()) {

                if (elementNumber == i) {
                    child->setFocus(true);


@@ 496,7 496,7 @@ namespace gui
        auto last = true;
        for (auto child = children.rbegin(); child != children.rend(); child++) {

            if ((*child)->activeItem && (*child)->visible && last) {
            if ((*child)->isActive() && last) {
                (*child)->setFocus(true);
                focusItem = (*child);
                last      = false;


@@ 516,7 516,7 @@ namespace gui
            if (child == focusItem) {
                break;
            }
            if (child->activeItem && child->visible) {
            if (child->isActive()) {
                index++;
            }
        }

M module-gui/gui/widgets/GridLayout.cpp => module-gui/gui/widgets/GridLayout.cpp +44 -47
@@ 22,25 22,34 @@ GridLayout::GridLayout(

        auto it       = this->getNavigationFocusedItem();
        auto distance = std::distance(children.begin(), it);

        switch (inputEvent.keyCode) {
        case KeyCode::KEY_UP: {
            auto realRowSize = calculateRowSizeForBorderTransition(distance);
            this->setFocusItem((*std::next(it, (realRowSize - 1) * this->colSize)));
            auto col   = static_cast<uint32_t>(distance % colSize);
            Item *item = getFirstActiveItem(getLastColumnIndex(col), (-1) * static_cast<int>(colSize));
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_DOWN: {
            auto realRowSize = calculateRowSizeForBorderTransition(distance);
            this->setFocusItem((*std::prev(it, (realRowSize - 1) * this->colSize)));
            auto col   = static_cast<uint32_t>(distance % colSize);
            Item *item = getFirstActiveItem(col, static_cast<int>(colSize));
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_LEFT: {
            auto realColSize = calculateColumnSizeForBorderTransition(distance);
            this->setFocusItem((*std::next(it, realColSize - 1)));
            auto row   = static_cast<uint32_t>(distance / colSize);
            Item *item = getFirstActiveItem(getLastRowIndex(row), -1);
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_RIGHT: {
            auto realColSize = calculateColumnSizeForBorderTransition(distance);
            this->setFocusItem((*std::prev(it, realColSize - 1)));
            auto row   = static_cast<uint32_t>(distance / colSize);
            Item *item = getFirstActiveItem(colSize * row, 1);
            if (item)
                this->setFocusItem(item);
            return true;
        }
        default: {


@@ 50,25 59,6 @@ GridLayout::GridLayout(
    };
}

uint32_t GridLayout::calculateColumnSizeForBorderTransition(const uint32_t currentPosition)
{
    auto realColSize = colSize;
    if (elementsInIncompletedLastRow) {
        if (((currentPosition / colSize) + 1) >= rowSize)
            realColSize = elementsInIncompletedLastRow;
    }
    return realColSize;
}
uint32_t GridLayout::calculateRowSizeForBorderTransition(const uint32_t currentPosition)
{
    auto realRowSize = rowSize;
    if (elementsInIncompletedLastRow) {
        if (((currentPosition % (colSize)) + 1) > elementsInIncompletedLastRow)
            realRowSize--;
    }
    return realRowSize;
}

void GridLayout::handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea)
{
    for (auto i = maxItemsInArea; i < children.size(); i++) {


@@ 88,16 78,6 @@ void GridLayout::resizeItems()
    uint32_t el_in_x = area().w / grid.x;
    uint32_t el_in_y = area().h / grid.y;

    elementsInIncompletedLastRow = 0;
    colSize = children.size() < area().w / grid.x ? children.size() : area().w / grid.x;
    rowSize                      = colSize != 0 ? (children.size() / colSize) : 1;
    if (colSize > 1 && (static_cast<double>(children.size()) / colSize) > 1.0) {
        elementsInIncompletedLastRow = children.size() % colSize;
    }
    if (elementsInIncompletedLastRow > 0) {
        rowSize++;
    }

    uint32_t strech_x     = 0;
    uint32_t strech_y     = 0;
    uint32_t max_elements = el_in_x * el_in_y;


@@ 113,6 93,13 @@ void GridLayout::resizeItems()
        handleItemsOutOfGridLayoutArea(max_elements);
        return;
    }

    colSize = children.size() < area().w / grid.x ? children.size() : area().w / grid.x;
    rowSize = colSize != 0 ? (children.size() / colSize) : 1;
    if (colSize > 1 && (static_cast<double>(children.size()) / colSize) > 1.0 && (children.size() % colSize)) {
        rowSize++;
    }

    if (el_in_x > 2)
        strech_x = (area().w - grid.x * el_in_x) / (el_in_x - 1);
    if (el_in_y > 2)


@@ 149,28 136,38 @@ void GridLayout::setNavigation()
    for (auto it = children.begin(); it != children.end(); ++it, ++i) {

        if (it != children.begin() && (i + 1) % colSize != 1) {
            (*it)->setNavigationItem(NavigationDirection::LEFT, nextNavigationItem(std::prev(it)));
            (*it)->setNavigationItem(NavigationDirection::LEFT, getFirstActiveItem(i - 1, -1));
        }

        if (it != std::prev(children.end()) && (i + 1) % colSize != 0) {
            (*it)->setNavigationItem(NavigationDirection::RIGHT, nextNavigationItem(std::next(it)));
            (*it)->setNavigationItem(NavigationDirection::RIGHT, getFirstActiveItem(i + 1, 1));
        }

        if ((i - offset) >= 0) {
            (*it)->setNavigationItem(NavigationDirection::UP, nextNavigationItem(std::prev(it, offset)));
            (*it)->setNavigationItem(NavigationDirection::UP, getFirstActiveItem(i - offset, (-1) * offset));
        }
        if ((i + offset) < static_cast<int>(children.size())) {
            (*it)->setNavigationItem(NavigationDirection::DOWN, nextNavigationItem(std::next(it, offset)));
            (*it)->setNavigationItem(NavigationDirection::DOWN, getFirstActiveItem(i + offset, offset));
        }
    }
}

Item *GridLayout::nextNavigationItem(std::list<Item *>::iterator it)
Item *GridLayout::getFirstActiveItem(uint32_t startposition, int step)
{
    if (it != this->children.end() && (*it)->visible && (*it)->activeItem) {
        return *it;
    }
    else {
        return nullptr;
    Item *retItem = nullptr;
    int index     = static_cast<int>(startposition);
    uint32_t row  = startposition / colSize;
    while (index >= 0 && index < static_cast<int>(children.size())) {
        ///> condition for movement along row (+1,-1 step)
        if ((step == 1 || step == -1) && (index / colSize != row)) {
            break;
        }
        std::list<Item *>::iterator tmpit = std::next(children.begin(), index);
        if ((*tmpit)->isActive()) {
            retItem = *tmpit;
            break;
        }
        index += step;
    }
    return retItem;
}

M module-gui/gui/widgets/GridLayout.hpp => module-gui/gui/widgets/GridLayout.hpp +15 -9
@@ 26,23 26,29 @@ namespace gui
        {}
        GridLayout() : GridLayout(0, 0, 0, 0, {0, 0})
        {}
        /// when reached top -> start from bottom. When reached left, start from right.
        bool navigationRotate = true;
        void resizeItems() override;
        void setNavigation() override;
        Item *nextNavigationItem(std::list<Item *>::iterator it);

        uint32_t rowSize = 0;
        uint32_t colSize = 0;
        ///> elementsInIncompletedLastRow describes how many items has been put to last row,
        /// in case when items for last row is not equal to colSize
        uint32_t elementsInIncompletedLastRow = 0;

      private:
        uint32_t calculateColumnSizeForBorderTransition(const uint32_t currentPosition);
        uint32_t calculateRowSizeForBorderTransition(const uint32_t currentPosition);

        void handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea);
        Item *getFirstActiveItem(uint32_t startposition, int step);
        inline uint32_t getLastColumnIndex(uint32_t col)
        {
            auto lastcolumnindex = col;
            while ((lastcolumnindex + colSize) < children.size())
                lastcolumnindex += colSize;
            return lastcolumnindex;
        }
        inline uint32_t getLastRowIndex(uint32_t row)
        {
            uint32_t lastrowindex = colSize * row + (colSize - 1);
            while (lastrowindex >= children.size())
                lastrowindex--;
            return lastrowindex;
        }
    };

}; // namespace gui

M module-gui/gui/widgets/Item.hpp => module-gui/gui/widgets/Item.hpp +5 -0
@@ 344,6 344,11 @@ namespace gui
        /// remove timer from item and as a result - destory it
        void detachTimer(Timer &timer);

        /// simple check function to determine if item is active && visible
        inline bool isActive()
        {
            return (activeItem && visible);
        }
        virtual void accept(GuiVisitor &visitor);

      protected:

M module-gui/gui/widgets/TopBar.cpp => module-gui/gui/widgets/TopBar.cpp +90 -46
@@ 11,7 11,7 @@

#include "common_data/EventStore.hpp"

namespace gui
namespace gui::top_bar
{
    namespace networkTechnology
    {


@@ 20,14 20,47 @@ namespace gui
        constexpr uint32_t w = 130;
        constexpr uint32_t h = 20;
    } // namespace networkTechnology
    const uint32_t TopBar::signalOffset    = 35;
    const uint32_t TopBar::batteryOffset   = 413;
    gui::TopBar::TimeMode TopBar::timeMode = TimeMode::TIME_24H;

    static constexpr uint32_t signalOffset  = 35;
    static constexpr uint32_t batteryOffset = 413;

    TopBar::TimeMode TopBar::timeMode      = TimeMode::TIME_24H;
    uint32_t TopBar::time                  = 0;

    TopBar::TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h) : Rect{parent, x, y, w, h}
    void Configuration::enable(Indicator indicator)
    {
        set(indicator, true);
    }

    void Configuration::enable(const Indicators &indicators)
    {
        for (auto indicator : indicators) {
            enable(indicator);
        }
    }

    void Configuration::disable(Indicator indicator)
    {
        set(indicator, false);
    }

    void Configuration::set(Indicator indicator, bool enabled)
    {
        indicatorStatuses[indicator] = enabled;
    }

    auto Configuration::isEnabled(Indicator indicator) const -> bool
    {
        return indicatorStatuses.at(indicator);
    }

    auto Configuration::getIndicatorsConfiguration() const noexcept -> const IndicatorStatuses &
    {
        return indicatorStatuses;
    }

    TopBar::TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h) : Rect{parent, x, y, w, h}
    {
        prepareWidget();

        setFillColor(ColorFullWhite);


@@ 48,7 81,7 @@ namespace gui
            val = batteryBars.size();
        }
        for (unsigned int i = 0; i < batteryBars.size(); ++i) {
            if (elements.battery) {
            if (configuration.isEnabled(Indicator::Battery)) {
                batteryBars[i]->setVisible(i == val);
            }
            else {


@@ 59,7 92,6 @@ namespace gui

    void TopBar::prepareWidget()
    {

        signal[0] = new gui::Image(this, signalOffset, 17, 0, 0, "signal0");
        signal[1] = new gui::Image(this, signalOffset, 17, 0, 0, "signal1");
        signal[2] = new gui::Image(this, signalOffset, 17, 0, 0, "signal2");


@@ 111,48 143,56 @@ namespace gui
        updateNetworkAccessTechnology();
    }

    void TopBar::setActive(std::list<std::pair<TopBar::Elements, bool>> elements)
    auto TopBar::getConfiguration() const noexcept -> const Configuration &
    {
        return configuration;
    }

    void TopBar::configure(Configuration &&config)
    {
        for (auto el : elements) {
            setActive(el.first, el.second);
        if (config.isEnabled(Indicator::Lock)) {
            // In current implementation, lock and time indicators are mutually exclusive.
            // I.e. enabling the lock indicator disables the time indicator.
            config.disable(Indicator::Time);
        }

        for (auto [indicator, enabled] : config.getIndicatorsConfiguration()) {
            setIndicatorStatus(indicator, enabled);
        }
        configuration = std::move(config);
    }

    void TopBar::setActive(TopBar::Elements element, bool active)
    void TopBar::setIndicatorStatus(Indicator indicator, bool enabled)
    {
        switch (element) {
        case Elements::BATTERY: {
            elements.battery = active;
            showBattery(elements.battery);
        } break;
        case Elements::LOCK: {
            elements.lock = active;
            lock->setVisible(active);
            if (active)
                timeLabel->setVisible(false);
        } break;
        case Elements::SIGNAL: {
            elements.signal = active;
        switch (indicator) {
        case Indicator::Signal:
            updateSignalStrength();
        } break;
        case Elements::TIME: {
            elements.time = active;
            timeLabel->setVisible(active);
            if (active)
            break;
        case Indicator::Time:
            timeLabel->setVisible(enabled);
            if (enabled) {
                lock->setVisible(false);
        } break;
        case Elements::SIM:
            elements.sim = active;
            }
            break;
        case Indicator::Lock:
            lock->setVisible(enabled);
            if (enabled) {
                timeLabel->setVisible(false);
            }
            break;
        case Indicator::Battery:
            showBattery(enabled);
            break;
        case Indicator::SimCard:
            simSet();
            break;
        case Elements::NETWORK_ACCESS_TECHNOLOGY:
            elements.networkAccessTechnology = active;
        case Indicator::NetworkAccessTechnology:
            updateNetworkAccessTechnology();
            break;
        };
        }
    }

    uint32_t calculateBatteryBars(uint32_t percentage)
    uint32_t TopBar::calculateBatteryBars(uint32_t percentage)
    {
        uint32_t level = 0;
        if (percentage <= 5) // level critical


@@ 177,13 217,13 @@ namespace gui

    bool TopBar::updateBattery(uint32_t percent)
    {
        showBattery(elements.battery);
        showBattery(configuration.isEnabled(Indicator::Battery));
        return true;
    }

    bool TopBar::updateBattery(bool plugged)
    {
        showBattery(elements.battery);
        showBattery(configuration.isEnabled(Indicator::Battery));
        return true;
    }



@@ 216,7 256,7 @@ namespace gui
        for (uint32_t i = 0; i < signalImgCount; i++) {
            signal[i]->setVisible(false);
        }
        if (elements.signal) {
        if (configuration.isEnabled(Indicator::Signal)) {
            auto rssiBar = Store::GSM::get()->getSignalStrength().rssiBar;
            if (rssiBar < Store::RssiBar::noOfSupprtedBars) {
                signal[static_cast<size_t>(rssiBar)]->setVisible(true);


@@ 229,7 269,7 @@ namespace gui

    bool TopBar::updateNetworkAccessTechnology()
    {
        if (elements.networkAccessTechnology) {
        if (configuration.isEnabled(Indicator::NetworkAccessTechnology)) {
            auto accessTechnology = Store::GSM::get()->getNetwork().accessTechnology;

            constexpr auto text2g  = "2G";


@@ 258,16 298,16 @@ namespace gui
        return true;
    }

    void TopBar::setTime(const UTF8 &time)
    void TopBar::setTime(const UTF8 &value)
    {
        timeLabel->setText(time);
        timeLabel->setText(value);
    }

    void TopBar::setTime(const uint32_t &time, bool mode24H)
    void TopBar::setTime(uint32_t value, bool mode24H)
    {
        setTime(utils::time::Time());
        timeMode   = (mode24H ? TimeMode::TIME_24H : TimeMode::TIME_12H);
        this->time = time;
        time       = value;
    }

    UTF8 TopBar::getTimeString()


@@ 276,13 316,17 @@ namespace gui
        return timeLabel->getText();
    }

    uint32_t TopBar::getTime() const noexcept
    {
        return time;
    }

    void TopBar::simSet()
    {
        if (!sim) {
        if (sim == nullptr) {
            return;
        }
        else if (elements.sim) {
        if (configuration.isEnabled(Indicator::SimCard)) {
            return sim->show(Store::GSM::get()->sim);
        }
        sim->visible = false;

M module-gui/gui/widgets/TopBar.hpp => module-gui/gui/widgets/TopBar.hpp +61 -41
@@ 1,21 1,52 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_
#define MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_
#pragma once

#include "Image.hpp"
#include "Label.hpp"
#include "Rect.hpp"
#include "TopBar/SIM.hpp"
#include <common_data/EventStore.hpp>

#include <vector>
#include <map>

namespace gui
namespace gui::top_bar
{
    enum class Indicator
    {
        Signal,
        Time,
        Lock,
        Battery,
        SimCard,
        NetworkAccessTechnology
    };
    using Indicators        = std::vector<Indicator>;
    using IndicatorStatuses = std::map<Indicator, bool>;

    static const uint32_t batteryBarsCount  = 6;
    static const uint32_t signalImgCount    = 6;
    /**
     * Carries the top bar configuration.
     */
    class Configuration
    {
      public:
        void enable(Indicator indicator);
        void enable(const Indicators &indicators);
        void disable(Indicator indicator);
        void set(Indicator indicator, bool enabled);
        [[nodiscard]] auto isEnabled(Indicator indicator) const -> bool;
        [[nodiscard]] auto getIndicatorsConfiguration() const noexcept -> const IndicatorStatuses &;

      private:
        IndicatorStatuses indicatorStatuses = {{Indicator::Signal, false},
                                               {Indicator::Time, false},
                                               {Indicator::Lock, false},
                                               {Indicator::Battery, false},
                                               {Indicator::SimCard, false},
                                               {Indicator::NetworkAccessTechnology, false}};
    };

    /// Header of most of design Windows
    ///


@@ 31,19 62,10 @@ namespace gui
    /// [signal]    [title ] [sim] [battery]
    class TopBar : public Rect
    {
        static const uint32_t signalOffset;
        static const uint32_t batteryOffset;
        static constexpr uint32_t batteryBarsCount = 6;
        static constexpr uint32_t signalImgCount   = 6;

      public:
        enum class Elements
        {
            SIGNAL = 0x01,
            LOCK,
            BATTERY,
            TIME,
            SIM,
            NETWORK_ACCESS_TECHNOLOGY
        };
        enum class TimeMode
        {
            TIME_12H,


@@ 60,32 82,32 @@ namespace gui
        std::map<const Store::Battery::State, Image *> batteryChargings = {
            {Store::Battery::State::Charging, nullptr}, {Store::Battery::State::PluggedNotCharging, nullptr}};
        gui::SIM *sim = nullptr;
        void prepareWidget();
        Configuration configuration;
        static TimeMode timeMode;

        void prepareWidget();

        /// show bars in number - 0 bars, 1 bar, 2 bars...
        void batteryShowBars(uint32_t val);

        /// elements shown on TopBar
        struct
        {
            bool signal : 1;
            bool lock : 1;
            bool battery : 1;
            bool time : 1;
            bool sim : 1;
            bool networkAccessTechnology : 1;
        } elements = {false, false, false, false, true, true};
        static uint32_t calculateBatteryBars(uint32_t percentage);

        /**
         * Sets the status of the top bar indicator.
         * @param indicator     Indicator
         */
        void setIndicatorStatus(Indicator indicator, bool enabled);

      public:
        TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h);

        /**
         * @brief Hides or shows images.
         * @note LOCK and TIME are located in the same place so only 1 can be active at the same time.
         * Configures the top bar.
         * @param configuration     Top bar configuration
         */
        void setActive(TopBar::Elements element, bool active);
        void setActive(std::list<std::pair<TopBar::Elements, bool>> elements);
        void configure(Configuration &&config);
        [[nodiscard]] auto getConfiguration() const noexcept -> const Configuration &;

        /**
         * @brief Sets charge level of the battery based on percent value. This will cause appropriate image to be
         * displayed.


@@ 103,16 125,14 @@ namespace gui
        bool updateNetworkAccessTechnology();

        void simSet();
        void setTime(const UTF8 &time);
        void setTime(const uint32_t &time, bool mode24H);

        void setTime(const UTF8 &value);
        void setTime(uint32_t value, bool mode24H);

        UTF8 getTimeString();
        uint32_t getTime()
        {
            return time;
        };
        uint32_t getTime() const noexcept;

        void accept(GuiVisitor &visitor) override;
    };

} /* namespace gui */

#endif /* MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_ */
} // namespace gui::top_bar

M module-gui/gui/widgets/visitor/GuiVisitor.hpp => module-gui/gui/widgets/visitor/GuiVisitor.hpp +5 -2
@@ 11,7 11,10 @@ namespace gui
    class Window;
    class Label;
    class BottomBar;
    class TopBar;
    namespace top_bar
    {
        class TopBar;
    }

    /// The general purpose abstract interface for enabling Double-Dispatch behavior throughout `gui::Item`'s
    /// inheritance hierarchy.


@@ 24,7 27,7 @@ namespace gui
        virtual void visit(gui::Window &item)    = 0;
        virtual void visit(gui::Label &item)     = 0;
        virtual void visit(gui::BottomBar &item) = 0;
        virtual void visit(gui::TopBar &item)    = 0;
        virtual void visit(gui::top_bar::TopBar &item) = 0;
        virtual ~GuiVisitor()                    = default;
    };
} // namespace gui

M module-gui/test/test-google/test-gui-gridlayout.cpp => module-gui/test/test-google/test-gui-gridlayout.cpp +150 -2
@@ 67,7 67,20 @@ class GridLayoutTesting : public ::testing::Test
            Box->addWidget(item);
        }
    }

    void addItem(gui::BoxLayout *Box,
                 uint32_t item_w,
                 uint32_t item_h,
                 uint32_t id,
                 bool active                 = true,
                 const gui::Margins &margins = gui::Margins())
    {
        auto item     = new TestItem(nullptr, 0, 0, item_w, item_h);
        item->ID      = id;
        item->visible = true;
        item->setMargins(margins);
        item->activeItem = active;
        Box->addWidget(item);
    }
    gui::GridLayout *gridLayout = nullptr;

    ///> GridLayout test constants


@@ 120,6 133,139 @@ TEST_F(GridLayoutTesting, Navigate_Test)
    ASSERT_EQ(1 + expColSize, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 + expColSize << " should have focus";
}

TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_1)
{
    ///> Test for grid layout with 48 elements (A - active item, N - non active item, NV - non visible item)
    ///> | 1   A | 2  NA | 3   A | 4  NA | 5   A | 6  NA | 7  A  | 8  NA | 9   A | 10 NA | 11 A  | 12 NA |
    ///> | 13 NA | 14  A | 15 NA | 16  A | 17 NA | 18  A | 19 NA | 20  A | 21 NA | 22  A | 23 NA | 24  A |
    ///> | 25  A | 26 NA | 27  A | 28 NA | 29  A | 30 NA | 31 A  | 32 NA | 33  A | 34 NA | 35 A  | 36 NA |
    ///> | 37 NA | 38  A | 39 NA | 40  A | 41 NA | 42  A | 43 NA | 44  A | 45 NA | 46  A | 47 NA | 48  A |
    ///> | 49 NV | 50 NV | 51 NV | 52 NV |
    for (uint32_t i = 1; i <= 12; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 13; i <= 24; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    for (uint32_t i = 25; i <= 36; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 37; i <= 48; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    ///> Add some items to exceed grid layout area
    for (uint32_t i = 49; i <= 52; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, true);
    }
    gridLayout->setFocus(true);
    ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected";
    ASSERT_EQ(52, gridLayout->children.size()) << "GridLayout should contain " << 52 << " elements";

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(5, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 5 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(5 + (2 * expColSize), dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 5 + (2 * expColSize) << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(1 + (2 * expColSize), dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 + (2 * expColSize) << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
}

TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_2_BorderCallback)
{
    ///> Test for grid layout with 48 elements
    ///> | 1   A | 2  NA | 3   A | 4  NA | 5   A | 6  NA | 7  A  | 8  NA | 9   A | 10 NA | 11 A  | 12 NA |
    ///> | 13 NA | 14  A | 15 NA | 16  A | 17 NA | 18  A | 19 NA | 20  A | 21 NA | 22  A | 23 NA | 24  A |
    ///> | 25  A | 26 NA | 27  A | 28 NA | 29  A | 30 NA | 31 A  | 32 NA | 33  A | 34 NA | 35 A  | 36 NA |
    ///> | 37 NA | 38  A | 39 NA |
    for (uint32_t i = 1; i <= 12; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 13; i <= 24; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    for (uint32_t i = 25; i <= 36; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 37; i <= 39; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }

    gridLayout->setFocus(true);
    ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected";
    ASSERT_EQ(39, gridLayout->children.size()) << "GridLayout should contain " << 39 << " elements";

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(9, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 9 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(33, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 33 << " should have focus";
    moveNTimes(gridLayout, 3, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(27, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 27 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(3, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 3 << " should have focus";
    moveNTimes(gridLayout, 5, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";

    ///> Test for grid layout with 1 element
    ///> | 1NA |
    gridLayout->erase();
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false);
    ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected";
    gridLayout->setFocus(false);
    gridLayout->setFocus(true);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    ///> Test for grid layout with 1 element
    ///> | 1NA | 1A |
    gridLayout->erase();
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false);
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 2, true);
    ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected";
    gridLayout->setFocus(false);
    gridLayout->setFocus(true);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
}

///> TODO: Enable this test when issue with setFocus will be resolved
TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
{


@@ 149,7 295,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
        << "element with ID " << 37 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(46, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 37 << " should have focus";
        << "element with ID " << 46 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(10, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 10 << " should have focus";


@@ 170,6 316,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
    ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected";

    gridLayout->setFocus(true);

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)


@@ 194,6 341,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
    ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected";

    gridLayout->setFocus(true);

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)

M module-gui/test/test-google/test-gui-visitor-call.cpp => module-gui/test/test-google/test-gui-visitor-call.cpp +1 -1
@@ 25,7 25,7 @@ class VisitorMock : public gui::GuiVisitor
    MOCK_METHOD1(visit, void(gui::Window &item));
    MOCK_METHOD1(visit, void(gui::Label &item));
    MOCK_METHOD1(visit, void(gui::BottomBar &item));
    MOCK_METHOD1(visit, void(gui::TopBar &item));
    MOCK_METHOD1(visit, void(gui::top_bar::TopBar &item));
};

class CustomRect : public gui::Rect

M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +30 -9
@@ 34,7 34,8 @@ namespace app::manager
{
    namespace
    {
        constexpr auto default_application_locktime_ms = 30000;
        static constexpr auto default_application_locktime_ms = 30000;
        static constexpr auto shutdown_delay_ms               = 500;
    }; // namespace

    ApplicationManagerBase::ApplicationManagerBase(std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers)


@@ 102,16 103,11 @@ namespace app::manager
        : Service{serviceName}, ApplicationManagerBase(std::move(launchers)), rootApplicationName{_rootApplicationName},
          blockingTimer{std::make_unique<sys::Timer>(
              "BlockTimer", this, std::numeric_limits<sys::ms>::max(), sys::Timer::Type::SingleShot)},
          shutdownDelay{std::make_unique<sys::Timer>("ShutdownDelay", this, shutdown_delay_ms)},
          settings(std::make_unique<settings::Settings>(this))
    {
        registerMessageHandlers();
        blockingTimer->connect([this](sys::Timer &) { onPhoneLocked(); });
        settings->registerValueChange(settings::SystemProperties::displayLanguage,
                                      [this](std::string value) { displayLanguageChanged(value); });
        settings->registerValueChange(settings::SystemProperties::inputLanguage,
                                      [this](std::string value) { inputLanguageChanged(value); });
        settings->registerValueChange(settings::SystemProperties::lockTime,
                                      [this](std::string value) { lockTimeChanged(value); });
    }

    sys::ReturnCodes ApplicationManager::InitHandler()


@@ 120,6 116,18 @@ namespace app::manager
        utils::localize.setFallbackLanguage(utils::localize.DefaultLanguage);
        utils::localize.setDisplayLanguage(displayLanguage);
        utils::localize.setInputLanguage(inputLanguage);
        settings->registerValueChange(
            settings::SystemProperties::displayLanguage,
            [this](std::string value) { displayLanguageChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::inputLanguage,
            [this](std::string value) { inputLanguageChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::lockTime,
            [this](std::string value) { lockTimeChanged(value); },
            settings::SettingsScope::Global);

        startSystemServices();
        startBackgroundApplications();


@@ 161,6 169,7 @@ namespace app::manager

    sys::ReturnCodes ApplicationManager::DeinitHandler()
    {
        settings->unregisterValueChange();
        closeApplications();
        closeServices();
        return sys::ReturnCodes::Success;


@@ 248,6 257,7 @@ namespace app::manager
        connect(typeid(CellularMMIResponseMessage), convertibleToActionHandler);
        connect(typeid(CellularMMIPushMessage), convertibleToActionHandler);
        connect(typeid(sys::CriticalBatteryLevelNotification), convertibleToActionHandler);
        connect(typeid(sys::SystemBrownoutMesssage), convertibleToActionHandler);
    }

    sys::ReturnCodes ApplicationManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)


@@ 391,6 401,8 @@ namespace app::manager
            auto params = static_cast<ApplicationLaunchData *>(actionMsg->getData().get());
            return handleLaunchAction(params);
        }
        case actions::CloseSystem:
            return handleCloseSystem();
        default: {
            auto &actionParams = actionMsg->getData();
            return handleCustomAction(action, std::move(actionParams));


@@ 415,6 427,14 @@ namespace app::manager
        return handleSwitchApplication(&switchRequest);
    }

    auto ApplicationManager::handleCloseSystem() -> bool
    {
        shutdownDelay->connect([&](sys::Timer &) { sys::SystemManager::CloseSystem(this); });
        shutdownDelay->start();

        return true;
    }

    auto ApplicationManager::handleCustomAction(actions::ActionId action, actions::ActionParamsPtr &&actionParams)
        -> bool
    {


@@ 540,7 560,8 @@ namespace app::manager
            return false;
        }
        displayLanguage = requestedLanguage;
        settings->setValue(settings::SystemProperties::displayLanguage, displayLanguage);
        settings->setValue(
            settings::SystemProperties::displayLanguage, displayLanguage, settings::SettingsScope::Global);
        utils::localize.setDisplayLanguage(displayLanguage);
        rebuildActiveApplications();
        return true;


@@ 555,7 576,7 @@ namespace app::manager
            return false;
        }
        inputLanguage = requestedLanguage;
        settings->setValue(settings::SystemProperties::inputLanguage, inputLanguage);
        settings->setValue(settings::SystemProperties::inputLanguage, inputLanguage, settings::SettingsScope::Global);
        utils::localize.setInputLanguage(inputLanguage);
        return true;
    }

M module-services/service-appmgr/service-appmgr/Actions.hpp => module-services/service-appmgr/service-appmgr/Actions.hpp +2 -0
@@ 24,6 24,7 @@ namespace app::manager
        {
            Home,
            Launch,
            CloseSystem,
            Call,
            Dial,
            ShowCallLog,


@@ 48,6 49,7 @@ namespace app::manager
            ShowMMIPush,
            DisplayCMEError,
            DisplayLowBatteryNotification,
            SystemBrownout,
            UserAction // The last enumerator in the Action enum.
                       // All user-defined actions shall have values greater than UserAction.
                       // All system-wide actions shall have values lesser than UserAction.

M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp => module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp +2 -0
@@ 114,6 114,7 @@ namespace app::manager
        auto handleAction(ActionRequest *actionMsg) -> bool;
        auto handleHomeAction() -> bool;
        auto handleLaunchAction(ApplicationLaunchData *launchParams) -> bool;
        auto handleCloseSystem() -> bool;
        auto handleCustomAction(actions::ActionId action, actions::ActionParamsPtr &&actionParams) -> bool;
        auto handleSwitchApplication(SwitchRequest *msg, bool closeCurrentlyFocusedApp = true) -> bool;
        auto handleCloseConfirmation(CloseConfirmation *msg) -> bool;


@@ 141,6 142,7 @@ namespace app::manager
                                                   // defined in settings database application
                                                   // manager is sending signal to power manager and changing window to
                                                   // the desktop window in the blocked state.
        std::unique_ptr<sys::Timer> shutdownDelay;
        // Temporary solution - to be replaced with ActionsMiddleware.
        std::tuple<ApplicationName, actions::ActionId, actions::ActionParamsPtr> pendingAction;


M module-services/service-cellular/CellularRequestHandler.cpp => module-services/service-cellular/CellularRequestHandler.cpp +2 -0
@@ 22,6 22,8 @@

#include <module-cellular/at/response.hpp>

using namespace cellular;

void CellularRequestHandler::handle(ImeiRequest &request, at::Result &result)
{
    if (!request.checkModemResponse(result)) {

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +2 -0
@@ 11,6 11,8 @@
#include <service-evtmgr/Constants.hpp>
#include <service-appmgr/Controller.hpp>

using namespace at::urc;

// this static function will be replaced by Settings API
static bool isSettingsAutomaticTimeSyncEnabled()
{

M module-services/service-cellular/CellularUrcHandler.hpp => module-services/service-cellular/CellularUrcHandler.hpp +11 -13
@@ 18,27 18,25 @@
#include <module-cellular/at/UrcResponse.hpp>
#include <module-cellular/at/UrcQiurc.hpp>

using namespace at::urc;

/**
 * ServiceCellular helper for handling Urc messages
 */
class CellularUrcHandler : public UrcHandler
class CellularUrcHandler : public at::urc::UrcHandler
{
  public:
    CellularUrcHandler(ServiceCellular &cellularService) : cellularService(cellularService)
    {}

    void Handle(Clip &urc) final;
    void Handle(Creg &urc) final;
    void Handle(Cmti &urc) final;
    void Handle(Cusd &urc) final;
    void Handle(Ctze &urc) final;
    void Handle(Qind &urc) final;
    void Handle(Cpin &urc) final;
    void Handle(Qiurc &urc) final;
    void Handle(PoweredDown &urc) final;
    void Handle(UrcResponse &urc) final;
    void Handle(at::urc::Clip &urc) final;
    void Handle(at::urc::Creg &urc) final;
    void Handle(at::urc::Cmti &urc) final;
    void Handle(at::urc::Cusd &urc) final;
    void Handle(at::urc::Ctze &urc) final;
    void Handle(at::urc::Qind &urc) final;
    void Handle(at::urc::Cpin &urc) final;
    void Handle(at::urc::Qiurc &urc) final;
    void Handle(at::urc::PoweredDown &urc) final;
    void Handle(at::urc::UrcResponse &urc) final;

    /**
     * Gets the response that should be returned after handling Urc

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +10 -8
@@ 204,8 204,6 @@ ServiceCellular::ServiceCellular() : sys::Service(serviceName, "", cellularStack
        sys::Bus::SendMulticast(msg.value(), sys::BusChannels::ServiceCellularNotifications, this);
    };
    registerMessageHandlers();
    settings->registerValueChange(settings::Cellular::volte_on,
                                  [this](const std::string &value) { volteChanged(value); });
    packetData = std::make_unique<packet_data::PacketData>(*this);
    packetData->loadAPNSettings();
}


@@ 235,6 233,8 @@ sys::ReturnCodes ServiceCellular::InitHandler()
    board = EventManagerServiceAPI::GetBoard(this);

    state.set(this, State::ST::WaitForStartPermission);
    settings->registerValueChange(settings::Cellular::volte_on,
                                  [this](const std::string &value) { volteChanged(value); });
    return sys::ReturnCodes::Success;
}



@@ 297,12 297,12 @@ void ServiceCellular::registerMessageHandlers()
        return handleCellularGetActiveContextsMessage(msg);
    });

    connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer {
        connect(typeid(CellularGetCurrentOperatorMessage), [&](sys::Message *request) -> sys::MessagePointer {
            auto msg = static_cast<CellularGetCurrentOperatorMessage *>(request);
            return handleCellularGetCurrentOperator(msg);
        });
    connect(typeid(CellularGetCurrentOperatorMessage), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<CellularGetCurrentOperatorMessage *>(request);
        return handleCellularGetCurrentOperator(msg);
    });

    connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<CellularGetAPNMessage *>(request);
        return handleCellularGetAPNMessage(msg);
    });


@@ 1284,7 1284,9 @@ bool ServiceCellular::handleSimState(at::SimState state, const std::string messa
    switch (state) {
    case at::SimState::Ready:
        Store::GSM::get()->sim = Store::GSM::get()->selected;
        settings->setValue(settings::SystemProperties::activeSim, utils::enumToString(Store::GSM::get()->selected));
        settings->setValue(settings::SystemProperties::activeSim,
                           utils::enumToString(Store::GSM::get()->selected),
                           settings::SettingsScope::Global);
        // SIM causes SIM INIT, only on ready
        response =
            std::move(std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::SIM_READY));

M module-services/service-cellular/service-cellular/CellularRequestHandler.hpp => module-services/service-cellular/service-cellular/CellularRequestHandler.hpp +8 -10
@@ 6,21 6,19 @@
#include "RequestHandler.hpp"
#include "service-cellular/ServiceCellular.hpp"

using namespace cellular;

class CellularRequestHandler : public RequestHandler
class CellularRequestHandler : public cellular::RequestHandler
{
  public:
    CellularRequestHandler(ServiceCellular &serviceCellular) : cellular(serviceCellular)
    {}

    void handle(ImeiRequest &request, at::Result &result) final;
    void handle(UssdRequest &request, at::Result &result) final;
    void handle(CallRequest &request, at::Result &result) final;
    void handle(PasswordRegistrationRequest &request, at::Result &result) final;
    void handle(SupplementaryServicesRequest &request, at::Result &result) final;
    void handle(PinChangeRequest &request, at::Result &result) final;
    void handle(ClirRequest &request, at::Result &result) final;
    void handle(cellular::ImeiRequest &request, at::Result &result) final;
    void handle(cellular::UssdRequest &request, at::Result &result) final;
    void handle(cellular::CallRequest &request, at::Result &result) final;
    void handle(cellular::PasswordRegistrationRequest &request, at::Result &result) final;
    void handle(cellular::SupplementaryServicesRequest &request, at::Result &result) final;
    void handle(cellular::PinChangeRequest &request, at::Result &result) final;
    void handle(cellular::ClirRequest &request, at::Result &result) final;

  private:
    ServiceCellular &cellular;

M module-services/service-cellular/service-cellular/PacketDataTypes.hpp => module-services/service-cellular/service-cellular/PacketDataTypes.hpp +64 -2
@@ 5,6 5,10 @@

#include <string>
#include <memory>
#include <unordered_map>
#include <map>

#include <Utils.hpp>

namespace packet_data
{


@@ 22,10 26,11 @@ namespace packet_data
         */
        enum class APNType
        {
            Default, ///< for data traffic
            Default, ///< only one APN is set as default
            IMS,     ///< IP Multimedia Subsystem for eg VoLTE
            MMS,     ///< for MMS service
            Fota     ///< for Firmware Update
            Fota,    ///< for Firmware Update
            Internet //< for data traffic
        };

        /**


@@ 81,6 86,63 @@ namespace packet_data
            std::string password;
            std::string ip; /// set after connection

            std::string getAuthMethod()
            {
                return utils::enumToString(authMethod);
            }

            void setAuthMethod(const std::string &str)
            {
                if (str == "NONE")
                    authMethod = AuthMethod::NONE;
                else if (str == "AUTO")
                    authMethod = AuthMethod::AUTO;
                else if (str == "CHAP")
                    authMethod = AuthMethod::CHAP;
                else if (str == "PAP")
                    authMethod = AuthMethod::PAP;
                else
                    authMethod = AuthMethod::NONE;
            }

            std::string getApnType()
            {
                return utils::enumToString(apnType);
            }

            void setApnType(const std::string &str)
            {
                if (str == "Default")
                    apnType = APNType::Default;
                else if (str == "Fota")
                    apnType = APNType::Fota;
                else if (str == "IMS")
                    apnType = APNType::IMS;
                else if (str == "Internet")
                    apnType = APNType::Internet;
                else if (str == "MMS")
                    apnType = APNType::MMS;
                else
                    apnType = APNType::Internet;
            }

            std::string getApnProtocol()
            {
                return utils::enumToString(contextType);
            }

            void setApnProtocol(const std::string &str)
            {
                if (str == "ipv4")
                    contextType = ContextType::ipv4;
                else if (str == "ipv6")
                    contextType = ContextType::ipv6;
                else if (str == "ipv4v6")
                    contextType = ContextType::ipv4v6;
                else
                    contextType = ContextType::ipv4;
            }

            bool isEmpty() const noexcept
            {
                return apn.empty();

M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +48 -12
@@ 60,7 60,10 @@ auto DBServiceAPI::ThreadGetCount(sys::Service *serv, EntryState state) -> uint3

    auto ret            = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto threadResponse = dynamic_cast<DBThreadResponseMessage *>(ret.second.get());
    assert(threadResponse != nullptr);
    if (threadResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (threadResponse->retCode == 1)) {
        return threadResponse->count;
    }


@@ 91,7 94,10 @@ auto DBServiceAPI::ContactGetByIDCommon(sys::Service *serv, std::shared_ptr<DBCo
{
    auto ret             = sys::Bus::SendUnicast(contactMsg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return std::move(contactResponse->records);
    }


@@ 133,7 139,10 @@ auto DBServiceAPI::MatchContactByPhoneNumber(sys::Service *serv, const utils::Ph

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactNumberResponseMessage *>(ret.second.get());
    assert(contactResponse);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    return std::move(contactResponse->contact);
}



@@ 180,7 189,10 @@ auto DBServiceAPI::ContactAdd(sys::Service *serv, const ContactRecord &rec) -> b

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 194,7 206,10 @@ auto DBServiceAPI::ContactRemove(sys::Service *serv, uint32_t id) -> bool

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 207,7 222,10 @@ auto DBServiceAPI::ContactUpdate(sys::Service *serv, const ContactRecord &rec) -

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 225,7 243,10 @@ auto DBServiceAPI::ContactSearch(sys::Service *serv, UTF8 primaryName, UTF8 alte

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return std::move(contactResponse->records);
    }


@@ 240,7 261,10 @@ auto DBServiceAPI::CalllogAdd(sys::Service *serv, const CalllogRecord &rec) -> C

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return CalllogRecord();
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        auto records = *calllogResponse->records;
        if (!records.empty()) {


@@ 258,7 282,10 @@ auto DBServiceAPI::CalllogRemove(sys::Service *serv, uint32_t id) -> bool

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return true;
    }


@@ 273,7 300,10 @@ auto DBServiceAPI::CalllogUpdate(sys::Service *serv, const CalllogRecord &rec) -

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return true;
    }


@@ 286,7 316,10 @@ auto DBServiceAPI::CalllogGetCount(sys::Service *serv, EntryState state) -> uint

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return calllogResponse->count;
    }


@@ 310,7 343,10 @@ auto DBServiceAPI::GetCountryCodeByMCC(sys::Service *serv, uint32_t mcc) -> uint

    auto ret      = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto response = dynamic_cast<DBCountryCodeResponseMessage *>(ret.second.get());
    assert(response != nullptr);
    if (response == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if (ret.first == sys::ReturnCodes::Success) {
        return (response->row.country_code);
    }

M module-services/service-db/agents/settings/Settings.cpp => module-services/service-db/agents/settings/Settings.cpp +46 -23
@@ 52,9 52,9 @@ namespace settings
    {
        LOG_DEBUG("handleVariableChanged");
        if (auto msg = dynamic_cast<settings::Messages::VariableChanged *>(req)) {
            auto key = msg->getPath().variable;
            auto key = msg->getPath();
            auto val = msg->getValue();
            LOG_DEBUG("handleVariableChanged: (k=v): (%s=%s)", key.c_str(), val.value_or("").c_str());
            LOG_DEBUG("handleVariableChanged: (k=v): (%s=%s)", key.to_string().c_str(), val.value_or("").c_str());
            ValueCb::iterator it_cb = cbValues.find(key);
            if (cbValues.end() != it_cb) {
                auto [cb, cbWithName] = it_cb->second;


@@ 62,13 62,13 @@ namespace settings
                    // in case of two callbacks there is a need to duplicate the value
                    auto value = std::move(val.value_or(""));
                    cb(std::string{value});
                    cbWithName(key, std::move(value));
                    cbWithName(key.variable, std::move(value));
                }
                else if (nullptr != cb) {
                    cb(std::move(val.value_or("")));
                }
                else {
                    cbWithName(key, std::move(val.value_or("")));
                    cbWithName(key.variable, std::move(val.value_or("")));
                }
            }
        }


@@ 115,56 115,79 @@ namespace settings
        return std::make_shared<sys::ResponseMessage>();
    }

    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb)
    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb, SettingsScope scope)
    {
        ValueCb::iterator it_cb = cbValues.find(variableName);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.first) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", variableName.c_str());
        }
        cbValues[variableName].first = cb;
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.first) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str());
        }
        cbValues[path].first = cb;

        auto msg      = std::make_shared<settings::Messages::RegisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallbackWithName cb)
    void Settings::registerValueChange(const std::string &variableName,
                                       ValueChangedCallbackWithName cb,
                                       SettingsScope scope)
    {
        auto it_cb = cbValues.find(variableName);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.second) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", variableName.c_str());
        }
        cbValues[variableName].second = cb;
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.second) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str());
        }
        cbValues[path].second = cb;

        auto msg      = std::make_shared<settings::Messages::RegisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::unregisterValueChange(const std::string &variableName)
    void Settings::unregisterValueChange(const std::string &variableName, SettingsScope scope)
    {
        ValueCb::iterator it_cb = cbValues.find(variableName);
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() == it_cb) {
            LOG_INFO("Callback function on value change (%s) does not exist", variableName.c_str());
            LOG_INFO("Callback function on value change (%s) does not exist", path.to_string().c_str());
        }
        else {
            LOG_DEBUG("[Settings::unregisterValueChange] %s", path.to_string().c_str());
            cbValues.erase(it_cb);
        }

        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        auto msg      = std::make_shared<settings::Messages::UnregisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::setValue(const std::string &variableName, const std::string &variableValue)
    void Settings::unregisterValueChange()
    {
        for (auto it_cb : cbValues) {
            LOG_DEBUG("[Settings::unregisterValueChange] %s", it_cb.first.to_string().c_str());
            auto msg = std::make_shared<settings::Messages::UnregisterOnVariableChange>(it_cb.first);
            sendMsg(std::move(msg));
        }
        cbValues.clear();
        LOG_INFO("Unregistered all settings variable change on application (%s)", app->GetName().c_str());
    }

    void Settings::setValue(const std::string &variableName, const std::string &variableValue, SettingsScope scope)
    {
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;
        auto msg      = std::make_shared<settings::Messages::SetVariable>(path, variableValue);
        sendMsg(std::move(msg));
    }

M module-services/service-db/agents/settings/SettingsAgent.cpp => module-services/service-db/agents/settings/SettingsAgent.cpp +20 -26
@@ 4,8 4,6 @@
#include "SettingsAgent.hpp"
#include "Settings_queries.hpp"

#include <service-db/SettingsMessages.hpp>

#include <Database/Database.hpp>
#include <Service/Service.hpp>
#include <module-sys/Service/Bus.hpp>


@@ 24,16 22,6 @@ SettingsAgent::SettingsAgent(sys::Service *parentService) : DatabaseAgent(parent

void SettingsAgent::initDb()
{
    auto notifications = database->query(settings::Statements::getAllNotifications);
    if (nullptr == notifications || 0 == notifications->getRowCount()) {
        return;
    }
    do {
        variableChangeRecipents[(*notifications)[0].getString()].insert((*notifications)[1].getString());
        /*what about mode/profile
        modeChangeRecipents;
        profileChangeRecipents;*/
    } while (notifications->nextRow());
}

void SettingsAgent::deinitDb()


@@ 95,8 83,7 @@ auto SettingsAgent::getAgentName() -> const std::string
// dbSingleVar
auto SettingsAgent::dbGetValue(settings::EntryPath path) -> std::optional<std::string>
{
    // auto retQuery = database->query(settings::Statements::getValue, path.to_string());
    auto retQuery = database->query(settings::Statements::getValue, path.variable.c_str());
    auto retQuery = database->query(settings::Statements::getValue, path.to_string().c_str());
    if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
        return std::string{};
    }


@@ 106,17 93,18 @@ auto SettingsAgent::dbGetValue(settings::EntryPath path) -> std::optional<std::s
auto SettingsAgent::dbSetValue(settings::EntryPath path, std::string value) -> bool
{
    /// insert or update
    return database->execute(settings::Statements::insertValue, path.variable.c_str(), value.c_str());
    return database->execute(settings::Statements::insertValue, path.to_string().c_str(), value.c_str());
}

auto SettingsAgent::dbRegisterValueChange(settings::EntryPath path) -> bool
{
    return database->execute(settings::Statements::setNotification, path.variable.c_str(), path.service.c_str());
    return database->execute(settings::Statements::setNotification, path.to_string().c_str(), path.service.c_str());
}

auto SettingsAgent::dbUnregisterValueChange(settings::EntryPath path) -> bool
{
    return database->execute(settings::Statements::clearNotificationdRow, path.variable.c_str());
    return database->execute(
        settings::Statements::clearNotificationdRow, path.to_string().c_str(), path.service.c_str());
}

// db Profile


@@ 223,12 211,13 @@ auto SettingsAgent::handleSetVariable(sys::Message *req) -> sys::MessagePointer
        auto oldValue = dbGetValue(path);
        if (oldValue.has_value() && oldValue.value() != value) {
            dbSetValue(path, value);
            // for (auto service : variableChangeRecipents[path.to_string()]) {
            for (auto service : variableChangeRecipents[path.variable]) {
                if (service != path.service) {
            LOG_DEBUG("[SettingsAgent::handleSetVariable] %s=%s", path.to_string().c_str(), value.c_str());
            for (auto regPath : variableChangeRecipents[path.to_string()]) {
                if (regPath.service != path.service) {
                    auto updateMsg =
                        std::make_shared<settings::Messages::VariableChanged>(path, value, oldValue.value_or(""));
                    sys::Bus::SendUnicast(std::move(updateMsg), service, parentService);
                        std::make_shared<settings::Messages::VariableChanged>(regPath, value, oldValue.value_or(""));
                    sys::Bus::SendUnicast(std::move(updateMsg), regPath.service, parentService);
                    LOG_DEBUG("[SettingsAgent::handleSetVariable] notified service: %s", regPath.service.c_str());
                }
            }
        }


@@ 242,14 231,18 @@ auto SettingsAgent::handleRegisterOnVariableChange(sys::Message *req) -> sys::Me
        auto path = msg->getPath();
        if (dbRegisterValueChange(path)) {
            auto it = variableChangeRecipents.find(path.to_string());
            if (variableChangeRecipents.end() == it || it->second.end() == it->second.find(path.service)) {
                variableChangeRecipents[path.to_string()] = {path.service};
            if (variableChangeRecipents.end() == it || it->second.end() == it->second.find(path)) {
                variableChangeRecipents[path.to_string()] = {path};
                auto currentValue                         = dbGetValue(path).value_or("");
                auto msgValue = std::make_shared<::settings::Messages::VariableChanged>(path, currentValue, "");
                sys::Bus::SendUnicast(std::move(msgValue), msg->sender, parentService);
                LOG_DEBUG("[SettingsAgent::handleRegisterOnVariableChange] %s=%s to %s",
                          path.to_string().c_str(),
                          currentValue.c_str(),
                          msg->sender.c_str());
            }
            else {
                it->second.insert(path.service);
                it->second.insert(path);
            }
        }
    }


@@ 263,7 256,8 @@ auto SettingsAgent::handleUnregisterOnVariableChange(sys::Message *req) -> sys::
        if (dbUnregisterValueChange(path)) {
            auto it = variableChangeRecipents.find(path.to_string());
            if (variableChangeRecipents.end() != it) {
                it->second.erase(path.service);
                it->second.erase(path);
                LOG_DEBUG("[SettingsAgent::handleUnregisterOnVariableChange] %s", path.to_string().c_str());
            }
        }
    }

M module-services/service-db/agents/settings/SettingsAgent.hpp => module-services/service-db/agents/settings/SettingsAgent.hpp +2 -1
@@ 32,7 32,8 @@ class SettingsAgent : public DatabaseAgent
    auto getAgentName() -> const std::string override;

  private:
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    // using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<settings::EntryPath>>;
    MapOfRecipentsToBeNotified variableChangeRecipents;
    using SetOfRecipents = std::set<std::string>;
    SetOfRecipents profileChangedRecipents;

M module-services/service-db/service-db/Settings.hpp => module-services/service-db/service-db/Settings.hpp +15 -10
@@ 5,6 5,8 @@

#include <module-sys/Service/Message.hpp>
#include <service-db/DBServiceName.hpp>
#include "SettingsScope.hpp"
#include "SettingsMessages.hpp"

#include <cstdint>
#include <functional>


@@ 16,11 18,6 @@

namespace settings
{
    namespace Messages
    {
        class SettingsMessage;
    }

    class Settings
    {
      public:


@@ 36,10 33,18 @@ namespace settings
        Settings(sys::Service *app, const std::string &dbAgentName = service::name::db);
        virtual ~Settings();

        void setValue(const std::string &variableName, const std::string &variableValue);
        void registerValueChange(const std::string &variableName, ValueChangedCallback cb);
        void registerValueChange(const std::string &variableName, ValueChangedCallbackWithName cb);
        void unregisterValueChange(const std::string &variableName);
        void setValue(const std::string &variableName,
                      const std::string &variableValue,
                      SettingsScope scope = SettingsScope::AppLocal);
        void registerValueChange(const std::string &variableName,
                                 ValueChangedCallback cb,
                                 SettingsScope scope = SettingsScope::AppLocal);
        void registerValueChange(const std::string &variableName,
                                 ValueChangedCallbackWithName cb,
                                 SettingsScope scope = SettingsScope::AppLocal);
        void unregisterValueChange(const std::string &variableName, SettingsScope scope = SettingsScope::AppLocal);
        /// unregisters all registered variables (both global and local)
        void unregisterValueChange();

        void getAllProfiles(OnAllProfilesRetrievedCallback cb);
        void setCurrentProfile(const std::string &profile);


@@ 61,7 66,7 @@ namespace settings
        std::string phoneMode;
        std::string profile;

        using ValueCb = std::map<std::string, std::pair<ValueChangedCallback, ValueChangedCallbackWithName>>;
        using ValueCb = std::map<EntryPath, std::pair<ValueChangedCallback, ValueChangedCallbackWithName>>;
        ValueCb cbValues;
        ModeChangedCallback cbMode;
        OnAllModesRetrievedCallback cbAllModes;

M module-services/service-db/service-db/SettingsMessages.hpp => module-services/service-db/service-db/SettingsMessages.hpp +30 -0
@@ 5,6 5,7 @@

#include <MessageType.hpp>
#include <Service/Message.hpp>
#include <service-db/SettingsScope.hpp>

#include <list>
#include <memory>


@@ 20,11 21,40 @@ namespace settings
        std::string service;
        std::string profile;
        std::string variable;
        SettingsScope scope;

        [[nodiscard]] auto to_string(std::string sep = "\\") const -> std::string
        {
            if (SettingsScope::Global == scope) {
                return variable;
            }
            return mode + sep + service + sep + profile + sep + variable;
        }

        bool operator<(const EntryPath &other) const
        {
            if (mode < other.mode)
                return true;
            if (mode > other.mode)
                return false;
            if (service < other.service)
                return true;
            if (service > other.service)
                return false;
            if (profile < other.profile)
                return true;
            if (profile > other.profile)
                return false;
            if (variable < other.variable)
                return true;
            if (variable > other.variable)
                return false;
            if (scope < other.scope)
                return true;
            if (scope > other.scope)
                return false;
            return false;
        }
    };

    namespace Messages

A module-services/service-db/service-db/SettingsScope.hpp => module-services/service-db/service-db/SettingsScope.hpp +12 -0
@@ 0,0 1,12 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
namespace settings
{
    enum class SettingsScope
    {
        Global,
        AppLocal
    };
}

M module-services/service-db/test/test-service-db-settings-messages.cpp => module-services/service-db/test/test-service-db-settings-messages.cpp +4 -4
@@ 118,13 118,13 @@ TEST_CASE("Settings Messages")
        settings::Service settings("settings");
        settings.InitHandler();

        sys::Bus::SendUnicast(std::make_shared<settings::Messages::RegisterOnVariableChange>(
                                  settings::EntryPath({"mode", "service", "profile", "variable"})),
        sys::Bus::SendUnicast(std::make_shared<settings::Messages::RegisterOnVariableChange>(settings::EntryPath(
                                  {"mode", "service", "profile", "variable", settings::SettingsScope::AppLocal})),
                              "db-worker",
                              &settings);

        sys::Bus::SendUnicast(std::make_shared<settings::Messages::UnregisterOnVariableChange>(
                                  settings::EntryPath({"mode", "service", "profile", "variable"})),
        sys::Bus::SendUnicast(std::make_shared<settings::Messages::UnregisterOnVariableChange>(settings::EntryPath(
                                  {"mode", "service", "profile", "variable", settings::SettingsScope::AppLocal})),
                              "db-worker",
                              &settings);
    }

M module-services/service-db/test/test-service-db-settings-testservices.hpp => module-services/service-db/test/test-service-db-settings-testservices.hpp +6 -4
@@ 28,26 28,28 @@ namespace settings
            if (auto msg = dynamic_cast<settings::UTMsg::ReqRegValChg *>(req)) {
                debug("ReqRegValChg", msg->name, msg->value);
                whoRequestedNotifyOnChange = msg->sender;
                mySettings->registerValueChange(msg->name, ([this](std::string value) {
                mySettings->registerValueChange(msg->name,
                                                ([this](std::string value) {
                                                    ValueChanged(value);
                                                    auto cnf = std::make_shared<settings::UTMsg::CnfValChg>("", value);
                                                    sys::Bus::SendUnicast(
                                                        std::move(cnf), whoRequestedNotifyOnChange, this);
                                                }));
                                                }),
                                                settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfRegValChg>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this);
            }
            else if (auto msg = dynamic_cast<settings::UTMsg::ReqUnRegValChg *>(req)) {
                // unregister
                debug("ReqUnRegValChg", msg->name, msg->value);
                mySettings->unregisterValueChange(msg->name);
                mySettings->unregisterValueChange(msg->name, settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfUnRegValChg>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), msg->sender, this);
            }
            else if (auto msg = dynamic_cast<settings::UTMsg::ReqSetVal *>(req)) {
                // set value
                debug("ReqSetVal", msg->name, msg->value);
                mySettings->setValue(msg->name, msg->value);
                mySettings->setValue(msg->name, msg->value, settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfReqSetVal>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), msg->sender, this);
            }

M module-services/service-desktop/DesktopMessages.cpp => module-services/service-desktop/DesktopMessages.cpp +1 -0
@@ 6,6 6,7 @@

namespace sdesktop::developerMode
{
    using namespace parserFSM;
    void Event::send()
    {
        MessageHandler::putToSendQueue(context.createSimpleResponse());

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +4 -3
@@ 29,8 29,6 @@ ServiceDesktop::ServiceDesktop() : sys::Service(service::name::service_desktop, 
    updateOS = std::make_unique<UpdateMuditaOS>(this);
    settings = std::make_unique<settings::Settings>(this);

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });
}

ServiceDesktop::~ServiceDesktop()


@@ 42,7 40,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
{
    desktopWorker = std::make_unique<WorkerDesktop>(this);
    const bool ret = desktopWorker->init(
        {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string), sdesktop::cdc_queue_len},
        {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},
         {sdesktop::SEND_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_object_size}});

    if (ret == false) {


@@ 116,6 114,9 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
        return std::make_shared<sys::ResponseMessage>();
    });

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });

    return (sys::ReturnCodes::Success);
}


M module-services/service-desktop/WorkerDesktop.cpp => module-services/service-desktop/WorkerDesktop.cpp +5 -6
@@ 30,7 30,7 @@ bool WorkerDesktop::init(std::list<sys::WorkerQueueInfo> queues)
    Worker::init(queues);

    receiveQueue                         = Worker::getQueueHandleByName(sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
    parserFSM::MessageHandler::sendQueue = Worker::getQueueHandleByName(sdesktop::SEND_QUEUE_BUFFER_NAME);
    parserFSM::MessageHandler::setSendQueueHandle(Worker::getQueueHandleByName(sdesktop::SEND_QUEUE_BUFFER_NAME));

    return (bsp::usbInit(receiveQueue, this) < 0) ? false : true;
}


@@ 58,16 58,17 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)

    LOG_INFO("handleMessage received data from queue: %s", qname.c_str());

    static std::string *sendMsg = nullptr;
    static std::string receivedMsg;
    if (qname == sdesktop::RECEIVE_QUEUE_BUFFER_NAME) {
        std::string *receivedMsg = nullptr;
        if (!queue->Dequeue(&receivedMsg, 0)) {
            LOG_ERROR("handleMessage failed to receive from \"%s\"", sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
            return false;
        }
        parser.processMessage(receivedMsg);
        parser.processMessage(std::move(*receivedMsg));
        delete receivedMsg;
    }
    else if (qname == sdesktop::SEND_QUEUE_BUFFER_NAME) {
        std::string *sendMsg = nullptr;
        if (!queue->Dequeue(&sendMsg, 0)) {
            LOG_ERROR("handleMessage xQueueReceive failed for %s.", sdesktop::SEND_QUEUE_BUFFER_NAME);
            return false;


@@ 75,9 76,7 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)

        LOG_DEBUG("handeMessage sending %d bytes using usbCDCSend", static_cast<unsigned int>(sendMsg->length()));
        bsp::usbCDCSend(sendMsg);

        delete sendMsg;
        sendMsg = nullptr;
    }
    else {
        LOG_INFO("handeMessage got message on an unhandled queue");

M module-services/service-desktop/endpoints/EndpointFactory.hpp => module-services/service-desktop/endpoints/EndpointFactory.hpp +13 -14
@@ 19,36 19,35 @@
#include "restore/RestoreEndpoint.hpp"
#include "update/UpdateEndpoint.hpp"

using namespace parserFSM;

class EndpointFactory
{
  public:
    static auto create(Context &context, sys::Service *ownerServicePtr) -> std::unique_ptr<Endpoint>
    static auto create(parserFSM::Context &context, sys::Service *ownerServicePtr)
        -> std::unique_ptr<parserFSM::Endpoint>
    {
        LOG_DEBUG("Creating endpoint: %d", static_cast<int>(context.getEndpoint()));
        switch (context.getEndpoint()) {
        case EndpointType::update:
        case parserFSM::EndpointType::update:
            return std::make_unique<UpdateEndpoint>(ownerServicePtr);
        case EndpointType::filesystemUpload:
        case parserFSM::EndpointType::filesystemUpload:
            return std::make_unique<FilesystemEndpoint>(ownerServicePtr);
        case EndpointType::backup:
        case parserFSM::EndpointType::backup:
            return std::make_unique<BackupEndpoint>(ownerServicePtr);
        case EndpointType::deviceInfo:
        case parserFSM::EndpointType::deviceInfo:
            return std::make_unique<DeviceInfoEndpoint>(ownerServicePtr);
        case EndpointType::restore:
        case parserFSM::EndpointType::restore:
            return std::make_unique<RestoreEndpoint>(ownerServicePtr);
        case EndpointType::contacts:
        case parserFSM::EndpointType::contacts:
            return std::make_unique<ContactsEndpoint>(ownerServicePtr);
        case EndpointType::messages:
        case parserFSM::EndpointType::messages:
            return std::make_unique<MessagesEndpoint>(ownerServicePtr);
        case EndpointType::factory:
        case parserFSM::EndpointType::factory:
            return std::make_unique<FactoryResetEndpoint>(ownerServicePtr);
        case EndpointType::calllog:
        case parserFSM::EndpointType::calllog:
            return std::make_unique<CalllogEndpoint>(ownerServicePtr);
        case EndpointType::developerMode:
        case parserFSM::EndpointType::developerMode:
            return std::make_unique<DeveloperModeEndpoint>(ownerServicePtr);
        case EndpointType::calendarEvents:
        case parserFSM::EndpointType::calendarEvents:
            return std::make_unique<CalendarEventsEndpoint>(ownerServicePtr);
        default:
            return nullptr;

M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp +2 -0
@@ 18,6 18,8 @@

static bool backupReady = false;

using namespace parserFSM;

auto BackupEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp +4 -6
@@ 20,16 20,14 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class BackupEndpoint : public Endpoint
class BackupEndpoint : public parserFSM::Endpoint
{
  public:
    BackupEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {
        debugName = "BackupEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto request(Context &context) -> sys::ReturnCodes;
    auto upload(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto request(parserFSM::Context &context) -> sys::ReturnCodes;
    auto upload(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp +4 -6
@@ 7,18 7,16 @@
#include "Service/Service.hpp"
#include "CalendarEventsHelper.hpp"

using namespace parserFSM;

class CalendarEventsEndpoint : public Endpoint
class CalendarEventsEndpoint : public parserFSM::Endpoint
{
  private:
    std::string debugName = "CalendarEventsEndpoint";
    std::unique_ptr<CalendarEventsHelper> helper;
    std::unique_ptr<parserFSM::CalendarEventsHelper> helper;

  public:
    CalendarEventsEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        helper = std::make_unique<CalendarEventsHelper>(ownerServicePtr);
        helper = std::make_unique<parserFSM::CalendarEventsHelper>(ownerServicePtr);
    }
    void handle(Context &context) override;
    void handle(parserFSM::Context &context) override;
};

M module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp => module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp +4 -6
@@ 20,18 20,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class CalllogEndpoint : public Endpoint
class CalllogEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<CalllogHelper> helper;
    std::unique_ptr<parserFSM::CalllogHelper> helper;

  public:
    CalllogEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "CalllogEndpoint";
        helper    = std::make_unique<CalllogHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::CalllogHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp => module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp +4 -6
@@ 22,18 22,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class ContactsEndpoint : public Endpoint
class ContactsEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<ContactHelper> helper;
    std::unique_ptr<parserFSM::ContactHelper> helper;

  public:
    ContactsEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "ContactsEndpoint";
        helper    = std::make_unique<ContactHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::ContactHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp +4 -6
@@ 21,18 21,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class DeveloperModeEndpoint : public Endpoint
class DeveloperModeEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<DeveloperModeHelper> helper;
    std::unique_ptr<parserFSM::DeveloperModeHelper> helper;

  public:
    DeveloperModeEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "DeveloperModeEndpoint";
        helper    = std::make_unique<DeveloperModeHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::DeveloperModeHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp => module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp +2 -0
@@ 15,6 15,8 @@
#include <sys/statvfs.h>
#include <purefs/filesystem_paths.hpp>

using namespace parserFSM;

auto DeviceInfoEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp => module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp +3 -5
@@ 19,9 19,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class DeviceInfoEndpoint : public Endpoint
class DeviceInfoEndpoint : public parserFSM::Endpoint
{

  public:


@@ 29,6 27,6 @@ class DeviceInfoEndpoint : public Endpoint
    {
        debugName = "DeviceInfoEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto getDeviceInfo(Context &context) -> bool;
    auto handle(parserFSM::Context &context) -> void override;
    auto getDeviceInfo(parserFSM::Context &context) -> bool;
};

M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp => module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp +3 -3
@@ 13,7 13,7 @@

#include <memory>

auto FactoryResetEndpoint::handle(Context &context) -> void
auto FactoryResetEndpoint::handle(parserFSM::Context &context) -> void
{
    if (context.getMethod() == parserFSM::http::Method::post) {



@@ 27,14 27,14 @@ auto FactoryResetEndpoint::handle(Context &context) -> void
            context.setResponseBody(json11::Json::object({{parserFSM::json::factoryRequest, false}}));
        }

        MessageHandler::putToSendQueue(context.createSimpleResponse());
        parserFSM::MessageHandler::putToSendQueue(context.createSimpleResponse());

        return;
    }
    else {
        context.setResponseBody(json11::Json::object({{parserFSM::json::factoryRequest, false}}));

        MessageHandler::putToSendQueue(context.createSimpleResponse());
        parserFSM::MessageHandler::putToSendQueue(context.createSimpleResponse());

        return;
    }

M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp => module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp +3 -5
@@ 19,9 19,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class FactoryResetEndpoint : public Endpoint
class FactoryResetEndpoint : public parserFSM::Endpoint
{

  public:


@@ 29,6 27,6 @@ class FactoryResetEndpoint : public Endpoint
    {
        debugName = "FactoryResetEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto makeFactoryReset(Context &context) -> bool;
    auto handle(parserFSM::Context &context) -> void override;
    auto makeFactoryReset(parserFSM::Context &context) -> bool;
};

M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp => module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp +3 -1
@@ 6,6 6,8 @@
#include "service-desktop/ServiceDesktop.hpp"
#include <purefs/filesystem_paths.hpp>

using namespace parserFSM;

auto FilesystemEndpoint::handle(Context &context) -> void
{
    LOG_DEBUG("handle");


@@ 68,4 70,4 @@ auto FilesystemEndpoint::run(Context &context) -> sys::ReturnCodes

    MessageHandler::putToSendQueue(context.createSimpleResponse());
    return returnCode;
}
\ No newline at end of file
}

M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp => module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp +4 -6
@@ 6,14 6,12 @@
#include <module-services/service-desktop/endpoints/Endpoint.hpp>
#include "Service/Service.hpp"

using namespace parserFSM;

class FilesystemEndpoint : public Endpoint
class FilesystemEndpoint : public parserFSM::Endpoint
{
  public:
    FilesystemEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {}
    auto handle(Context &context) -> void override;
    auto run(Context &context) -> sys::ReturnCodes;
    auto getUpdates(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto run(parserFSM::Context &context) -> sys::ReturnCodes;
    auto getUpdates(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp => module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp +4 -6
@@ 21,18 21,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class MessagesEndpoint : public Endpoint
class MessagesEndpoint : public parserFSM::Endpoint
{
  private:
    std::shared_ptr<MessageHelper> helper;
    std::shared_ptr<parserFSM::MessageHelper> helper;

  public:
    MessagesEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "MessagesEndpoint";
        helper    = std::make_shared<MessageHelper>(ownerServicePtr);
        helper    = std::make_shared<parserFSM::MessageHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp => module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp +2 -0
@@ 14,6 14,8 @@

#include <memory>

using namespace parserFSM;

auto RestoreEndpoint::handle(Context &context) -> void
{
    if (context.getMethod() == parserFSM::http::Method::post) {

M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp => module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp +2 -4
@@ 16,14 16,12 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class RestoreEndpoint : public Endpoint
class RestoreEndpoint : public parserFSM::Endpoint
{
  public:
    RestoreEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {
        debugName = "RestoreEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp => module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp +2 -0
@@ 16,6 16,8 @@
#include <filesystem>
#include <memory>

using namespace parserFSM;

auto UpdateEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp => module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp +4 -6
@@ 20,9 20,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class UpdateEndpoint : public Endpoint
class UpdateEndpoint : public parserFSM::Endpoint
{

  public:


@@ 30,7 28,7 @@ class UpdateEndpoint : public Endpoint
    {
        debugName = "UpdateEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto run(Context &context) -> sys::ReturnCodes;
    auto getUpdates(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto run(parserFSM::Context &context) -> sys::ReturnCodes;
    auto getUpdates(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/parser/MessageHandler.cpp => module-services/service-desktop/parser/MessageHandler.cpp +3 -3
@@ 23,7 23,7 @@ using namespace parserFSM;

xQueueHandle MessageHandler::sendQueue;

MessageHandler::MessageHandler(std::string &message, sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
MessageHandler::MessageHandler(const std::string &message, sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
{
    try {
        messageJson = json11::Json::parse(message, JsonErrorMsg);


@@ 53,10 53,10 @@ void MessageHandler::processMessage()
    }
}

void MessageHandler::putToSendQueue(const std::string msg)
void MessageHandler::putToSendQueue(const std::string &msg)
{
    if (uxQueueSpacesAvailable(sendQueue) != 0) {
        auto *responseString = new std::string(msg);
        auto responseString = new std::string(msg);
        xQueueSend(sendQueue, &responseString, portMAX_DELAY);
    }
}

M module-services/service-desktop/parser/MessageHandler.hpp => module-services/service-desktop/parser/MessageHandler.hpp +14 -11
@@ 24,29 24,32 @@ namespace parserFSM
{
    class MessageHandler
    {
        static xQueueHandle sendQueue;

        json11::Json messageJson;
        std::string JsonErrorMsg;
        sys::Service *OwnerServicePtr = nullptr;

      public:
        MessageHandler(std::string &message, sys::Service *OwnerService);
        static xQueueHandle sendQueue;
        MessageHandler(const std::string &message, sys::Service *OwnerService);

        bool isJSONNull()
        [[nodiscard]] auto isJSONNull() const -> bool
        {
            return messageJson.is_null();
        };
        bool isValid()
        [[nodiscard]] auto isValid() const noexcept -> bool
        {
            return JsonErrorMsg.empty();
        }
        std::string &getErrorString()
        [[nodiscard]] auto getErrorString() const -> const std::string &
        {
            return JsonErrorMsg;
        };
        void processMessage();
        static void putToSendQueue(const std::string msg);

      private:
        json11::Json messageJson;
        std::string JsonErrorMsg;
        sys::Service *OwnerServicePtr = nullptr;
        static void putToSendQueue(const std::string &msg);
        static void setSendQueueHandle(xQueueHandle handle)
        {
            sendQueue = handle;
        }
    };
} // namespace parserFSM

M module-services/service-desktop/parser/ParserFSM.cpp => module-services/service-desktop/parser/ParserFSM.cpp +23 -23
@@ 28,10 28,10 @@ using namespace parserFSM;
StateMachine::StateMachine(sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
{}

void StateMachine::processMessage(std::string &msg)
void StateMachine::processMessage(std::string &&msg)
{
    receivedMsgPtr = &msg;
    LOG_DEBUG("Msg: %s", receivedMsgPtr->c_str());
    receivedMsg = std::move(msg);
    LOG_DEBUG("Msg: %s", receivedMsg.c_str());

    switch (state) {
    case State::ReceivedPayload:


@@ 58,20 58,20 @@ void StateMachine::parseHeader()
    header.clear();
    payloadLength = 0;

    auto messageStart = receivedMsgPtr->find(message::endpointChar);
    auto messageStart = receivedMsg.find(message::endpointChar);
    if (messageStart == std::string::npos) {
        LOG_ERROR("This is not a valid endpoint message! Type=%c", receivedMsgPtr->at(0));
        LOG_ERROR("This is not a valid endpoint message! Type=%c", receivedMsg.at(0));
        return;
    }

    if (receivedMsgPtr->size() < message::size_header) // header divided in few parts
    if (receivedMsg.size() < message::size_header) // header divided in few parts
    {
        state = State::ReceivedPartialHeader;
        header.append(*receivedMsgPtr); // append to whole header string
        header.append(receivedMsg); // append to whole header string
        return;
    }

    header        = message::getHeader(*receivedMsgPtr);
    header        = message::getHeader(receivedMsg);
    payloadLength = message::calcPayloadLength(header);
    if (payloadLength == 0) // failed to obtain payload length from msg
    {


@@ 82,7 82,7 @@ void StateMachine::parseHeader()

    LOG_DEBUG("Payload length: %lu", payloadLength);

    message::removeHeader(*receivedMsgPtr);
    message::removeHeader(receivedMsg);
    parseNewMessage();
}



@@ 91,39 91,39 @@ void StateMachine::parsePartialHeader()
    auto previousHeaderLength = header.size();
    auto missingHeaderLength  = message::size_header - previousHeaderLength;

    if (receivedMsgPtr->size() >= missingHeaderLength) // rest of the message is here
    if (receivedMsg.size() >= missingHeaderLength) // rest of the message is here
    {
        header.append(receivedMsgPtr->substr(0, missingHeaderLength));
        header.append(receivedMsg.substr(0, missingHeaderLength));
        LOG_DEBUG("Header: %s\n", header.c_str());
        payloadLength = message::calcPayloadLength(header);

        LOG_DEBUG("Payload length: %lu\n", payloadLength);
        message::eraseFront(*receivedMsgPtr, missingHeaderLength);
        message::eraseFront(receivedMsg, missingHeaderLength);

        parseNewMessage();
    }
    else // the message is even longer :(
    {
        header.append(*receivedMsgPtr);
        header.append(receivedMsg);
    }
}

void StateMachine::parseNewMessage()
{
    if (receivedMsgPtr->size() >= payloadLength) {
    if (receivedMsg.size() >= payloadLength) {

        payload = message::extractPayload(*receivedMsgPtr, payloadLength);
        payload = message::extractPayload(receivedMsg, payloadLength);

        parsePayload();

        if (receivedMsgPtr->size() > payloadLength) { // contains part of new header
            message::eraseFront(*receivedMsgPtr, payloadLength);
        if (receivedMsg.size() > payloadLength) { // contains part of new header
            message::eraseFront(receivedMsg, payloadLength);
            parseHeader();
        }
    }
    else // message divided in 2 or more packets
    {
        payload = receivedMsgPtr->substr(0, std::string::npos); // take rest of the message
        payload = receivedMsg.substr(0, std::string::npos); // take rest of the message
        state   = State::ReceivedPartialPayload;
    }
}


@@ 133,20 133,20 @@ void StateMachine::parsePartialMessage()
    auto previousPayloadLength = payload.size();
    auto missingPayloadLength  = payloadLength - previousPayloadLength;

    if (receivedMsgPtr->size() >= missingPayloadLength) // rest of the message is here
    if (receivedMsg.size() >= missingPayloadLength) // rest of the message is here
    {
        payload.append(message::extractPayload(*receivedMsgPtr, missingPayloadLength));
        payload.append(message::extractPayload(receivedMsg, missingPayloadLength));

        parsePayload();

        if (receivedMsgPtr->size() > missingPayloadLength) {
            message::eraseFront(*receivedMsgPtr, missingPayloadLength);
        if (receivedMsg.size() > missingPayloadLength) {
            message::eraseFront(receivedMsg, missingPayloadLength);
            parseHeader();
        }
    }
    else // the message is even longer
    {
        payload.append(*receivedMsgPtr);
        payload.append(receivedMsg);
    }
}


M module-services/service-desktop/parser/ParserFSM.hpp => module-services/service-desktop/parser/ParserFSM.hpp +6 -6
@@ 23,21 23,21 @@ namespace parserFSM
    class StateMachine
    {
      public:
        StateMachine(sys::Service *OwnerService);
        void processMessage(std::string &msg);
        State getCurrentState()
        explicit StateMachine(sys::Service *OwnerService);
        void processMessage(std::string &&msg);
        [[nodiscard]] auto getCurrentState() const noexcept -> State
        {
            return state;
        };

        void setState(const parserFSM::State newState)
        void setState(const parserFSM::State newState) noexcept
        {
            state = newState;
        }

      private:
        std::string *receivedMsgPtr = nullptr;
        parserFSM::State state      = State::NoMsg;
        std::string receivedMsg;
        parserFSM::State state = State::NoMsg;
        std::string payload;
        std::string header;
        unsigned long payloadLength   = 0;

M module-services/service-desktop/service-desktop/DesktopMessages.hpp => module-services/service-desktop/service-desktop/DesktopMessages.hpp +1 -1
@@ 71,7 71,7 @@ namespace sdesktop
        class Event
        {
          protected:
            Context context;
            parserFSM::Context context;

          public:
            void send();

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +25 -21
@@ 48,76 48,80 @@ using namespace parserFSM;
TEST_CASE("Parser Test")
{
    StateMachine parser(nullptr);
    std::string testMessage("#00000");

    SECTION("Parse message with divided header and payload")
    {
        parser.processMessage(testMessage);
        std::string testMessage("#00000");
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialHeader);

        testMessage = R"(0050{"endpo)";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(int":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse whole message")
    {
        testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse message with start char detached from mesage")
    {
        testMessage = R"(#)";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialHeader);

        testMessage = R"(000000050{"en)";
        parser.processMessage(testMessage);
        testMessage = R"(000000050{"en)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(dpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse message with beginning of another one")
    {
        testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}}#000000050{"end)";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}}#000000050{"end)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(point":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }
    SECTION("Parse junk message")
    {
        testMessage = R"({"address": "6 Czeczota St.\n02600 Warsaw"})";
        parser.processMessage(testMessage);
        std::string testMessage = R"({"address": "6 Czeczota St.\n02600 Warsaw"})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with incorrect header length")
    {
        testMessage = R"(#000000072{"endpoint":7, "method":2, "uuid":3, "body":{"threadID":1,"unread":false}})";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000072{"endpoint":7, "method":2, "uuid":3, "body":{"threadID":1,"unread":false}})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with damaged json ")
    {
        testMessage = R"(#000000074{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000074{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with damaged json and incorrect header length")
    {
        testMessage = R"(#000000072{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000072{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
}

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +11 -14
@@ 91,28 91,25 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
        if (!queue->Dequeue(&notification, 0)) {
            return false;
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INTB)) {
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INTB)) {
            LOG_DEBUG("Battery INTB");
            const auto status = bsp::battery_getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::minVAlert)) {
            const auto status = bsp::battery_charger::getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::minVAlert)) {
                auto messageBrownout = std::make_shared<sevm::BatteryBrownoutMessage>();
                sys::Bus::SendUnicast(messageBrownout, service::name::system_manager, this->service);
            }
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::SOCOnePercentChange)) {
                std::uint8_t battLevel = 0;
                bsp::battery_getBatteryLevel(battLevel);
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::SOCOnePercentChange)) {
                bsp::battery_charger::StateOfCharge battLevel = bsp::battery_charger::getBatteryLevel();
                auto message = std::make_shared<sevm::BatteryLevelMessage>(battLevel, false);
                sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
                battery_level_check::checkBatteryLevelCritical();
            }
            bsp::battery_ClearAllIRQs();
            bsp::battery_charger::clearAllIRQs();
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INOKB)) {
            bool status;
            bsp::battery_getChargeStatus(status);
            bsp::battery_ClearAllIRQs();
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INOKB)) {
            bsp::battery_charger::clearAllIRQs();
            auto message     = std::make_shared<sevm::BatteryPlugMessage>();
            message->plugged = status;
            message->plugged = bsp::battery_charger::getChargeStatus();
            sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
        }
    }


@@ 193,7 190,7 @@ bool WorkerEvent::init(std::list<sys::WorkerQueueInfo> queuesList)
    bsp::vibrator::init();
    bsp::keyboard_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueKeyboardIRQ)]->GetQueueHandle());
    bsp::headset::Init(queues[static_cast<int32_t>(WorkerEventQueues::queueHeadsetIRQ)]->GetQueueHandle());
    bsp::battery_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::battery_charger::init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::rtc_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueRTC)]->GetQueueHandle());
    bsp::cellular::init(queues[static_cast<int32_t>(WorkerEventQueues::queueCellular)]->GetQueueHandle());
    bsp::magnetometer::init(queues[static_cast<int32_t>(WorkerEventQueues::queueMagnetometerIRQ)]->GetQueueHandle());


@@ 216,7 213,7 @@ bool WorkerEvent::deinit(void)
    Worker::deinit();
    bsp::keyboard_Deinit();
    bsp::headset::Deinit();
    bsp::battery_Deinit();
    bsp::battery_charger::deinit();
    bsp::torch::deinit();
    bsp::keypad_backlight::deinit();
    bsp::eink_frontlight::deinit();

M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp => module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp +2 -3
@@ 5,8 5,7 @@

#include <service-db/service-db/Settings.hpp>
#include "ControlFunctions.hpp"

#include <sstream>
#include <Utils.hpp>

namespace sys
{


@@ 85,7 84,7 @@ namespace screen_light_control

        template <class T> void setScreenLightSettings(const std::string &varName, T value)
        {
            settings->setValue(varName, std::to_string(value));
            settings->setValue(varName, utils::to_string(value));
        }
        void initFromSettings();


M module-services/service-fota/FotaUrcHandler.cpp => module-services/service-fota/FotaUrcHandler.cpp +2 -0
@@ 3,6 3,8 @@

#include "FotaUrcHandler.hpp"

using namespace at::urc;

void FotaUrcHandler::Handle(Qind &urc)
{
    if (urc.isFotaValid()) {

M module-services/service-fota/FotaUrcHandler.hpp => module-services/service-fota/FotaUrcHandler.hpp +11 -13
@@ 8,27 8,25 @@
#include <module-cellular/at/UrcHandler.hpp>
#include <module-cellular/at/UrcQind.hpp>

using namespace at::urc;

/**
 * ServiceFota helper for handling Urc messages
 */
class FotaUrcHandler : public UrcHandler
class FotaUrcHandler : public at::urc::UrcHandler
{
  public:
    FotaUrcHandler(FotaService::Service &fotaService) : fotaService(fotaService)
    {}

    void Handle(Qind &urc) final;
    virtual void Handle(Clip &urc){};
    virtual void Handle(Creg &urc){};
    virtual void Handle(Cmti &urc){};
    virtual void Handle(Cusd &urc){};
    virtual void Handle(Ctze &urc){};
    virtual void Handle(Cpin &urc){};
    virtual void Handle(Qiurc &urc){};
    virtual void Handle(PoweredDown &urc){};
    virtual void Handle(UrcResponse &urc){};
    void Handle(at::urc::Qind &urc) final;
    virtual void Handle(at::urc::Clip &urc){};
    virtual void Handle(at::urc::Creg &urc){};
    virtual void Handle(at::urc::Cmti &urc){};
    virtual void Handle(at::urc::Cusd &urc){};
    virtual void Handle(at::urc::Ctze &urc){};
    virtual void Handle(at::urc::Cpin &urc){};
    virtual void Handle(at::urc::Qiurc &urc){};
    virtual void Handle(at::urc::PoweredDown &urc){};
    virtual void Handle(at::urc::UrcResponse &urc){};

  private:
    FotaService::Service &fotaService;

M module-services/service-time/service-time/CalendarTimeEvents.hpp => module-services/service-time/service-time/CalendarTimeEvents.hpp +1 -1
@@ 27,7 27,7 @@ namespace stm
    {
      private:
        EventsRecord eventRecord;
        TimePoint startTP = TIME_POINT_INVALID;
        calendar::TimePoint startTP = TIME_POINT_INVALID;

      protected:
        const std::string timerName() override

M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +4 -3
@@ 29,6 29,7 @@ namespace sys

namespace stm
{
    using namespace std::chrono_literals;
    constexpr static auto eventTimerMinSkipInterval = 100ms;

    CalendarTimeEvents::CalendarTimeEvents(sys::Service *service) : TimeEvents(service)


@@ 36,8 37,8 @@ namespace stm

    bool CalendarTimeEvents::sendNextEventQuery()
    {
        TimePoint filterFrom = TimePointNow();
        TimePoint filterTill = filterFrom;
        calendar::TimePoint filterFrom = TimePointNow();
        calendar::TimePoint filterTill = filterFrom;
        if (startTP != TIME_POINT_INVALID) {
            filterFrom = std::min(startTP, filterFrom);
            filterTill = filterFrom;


@@ 64,7 65,7 @@ namespace stm
        }

        eventRecord   = records.at(0);
        startTP       = eventRecord.date_from - minutes{eventRecord.reminder};
        startTP       = eventRecord.date_from - std::chrono::minutes{eventRecord.reminder};
        auto duration = eventRecord.date_from - std::chrono::minutes{eventRecord.reminder} - TimePointNow();
        if (duration.count() <= 0) {
            duration = std::chrono::milliseconds(eventTimerMinSkipInterval);

M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +7 -3
@@ 116,7 116,7 @@ namespace sys
        // pingPongTimerID = CreateTimer(Ticks::MsToTicks(pingInterval), true);
        // ReloadTimer(pingPongTimerID);

        cpuStatisticsTimer = std::make_unique<sys::Timer>("cpuStatistics", this, timerInitInterval.count());
        cpuStatisticsTimer = std::make_unique<sys::Timer>("cpuStatistics", this, constants::timerInitInterval.count());
        cpuStatisticsTimer->connect([&](sys::Timer &) { CpuStatisticsTimerHandler(); });
        cpuStatisticsTimer->start();
    }


@@ 261,6 261,10 @@ namespace sys

        connect(sevm::BatteryBrownoutMessage(), [&](Message *) {
            LOG_INFO("Battery Brownout voltage level reached!");

            auto msg = std::make_shared<SystemBrownoutMesssage>();
            Bus::SendUnicast(msg, app::manager::ApplicationManager::ServiceName, this);

            return MessageNone{};
        });



@@ 284,7 288,7 @@ namespace sys
            CellularServiceAPI::ChangeModulePowerState(this, cellular::State::PowerState::On);

            auto msg = std::make_shared<CriticalBatteryLevelNotification>(false);
            Bus::SendUnicast(msg, app::manager::ApplicationManager::ServiceName, this);
            Bus::SendUnicast(std::move(msg), app::manager::ApplicationManager::ServiceName, this);

            return MessageNone{};
        });


@@ 354,7 358,7 @@ namespace sys
    {
        if (!cpuStatisticsTimerInit) {
            cpuStatisticsTimerInit = true;
            cpuStatisticsTimer->setInterval(timerPeriodInterval.count());
            cpuStatisticsTimer->setInterval(constants::timerPeriodInterval.count());
        }

        cpuStatistics->Update();

M module-sys/SystemManager/SystemManager.hpp => module-sys/SystemManager/SystemManager.hpp +6 -3
@@ 26,9 26,12 @@

namespace sys
{
    using namespace std::chrono_literals;
    inline constexpr std::chrono::milliseconds timerInitInterval{30s};
    inline constexpr std::chrono::milliseconds timerPeriodInterval{100ms};
    namespace constants
    {
        using namespace std::chrono_literals;
        inline constexpr std::chrono::milliseconds timerInitInterval{30s};
        inline constexpr std::chrono::milliseconds timerPeriodInterval{100ms};
    } // namespace constants

    enum class Code
    {

M module-sys/SystemManager/messages/SystemManagerMessage.hpp => module-sys/SystemManager/messages/SystemManagerMessage.hpp +10 -0
@@ 37,4 37,14 @@ namespace sys
        bool isActive;
    };

    class SystemBrownoutMesssage : public sys::Message, public app::manager::actions::ConvertibleToAction
    {
      public:
        [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>
        {
            return std::make_unique<app::manager::ActionRequest>(
                service::name::system_manager, app::manager::actions::SystemBrownout, nullptr);
        }
    };

} // namespace sys

M module-utils/CMakeLists.txt => module-utils/CMakeLists.txt +3 -0
@@ 38,6 38,9 @@ set (SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/Utils.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/log/Logger.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/log/log.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/log/LoggerBuffer.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/circular_buffer/StringCircularBuffer.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/generators/RandomStringGenerator.cpp
)

add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_SOURCES})

M module-utils/Utils.hpp => module-utils/Utils.hpp +7 -0
@@ 122,7 122,14 @@ namespace utils
                baseAsStr = "-0";
            }
        }

        auto fractionalPart = static_cast<unsigned long int>(roundl(frac));
        auto fractionalPartLength = std::to_string(fractionalPart).length();
        if (fractionalPartLength > precision) {
            base += 1;
            baseAsStr      = std::to_string(base);
            fractionalPart = 0;
        }
        if (fractionalPart == 0) {
            if (baseAsStr == "-0") {
                return "0";

A module-utils/circular_buffer/StringCircularBuffer.cpp => module-utils/circular_buffer/StringCircularBuffer.cpp +55 -0
@@ 0,0 1,55 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "StringCircularBuffer.hpp"

std::pair<bool, std::string> StringCircularBuffer::get()
{
    if (isEmpty()) {
        return {false, ""};
    }

    const std::string val = buffer[tail];
    full                  = false;
    tail                  = (tail + 1) % capacity;
    --size;

    return {true, val};
}

void StringCircularBuffer::put(const std::string &item)
{
    updateMembersBeforePut();
    buffer[head] = item;
    updateMembersAfterPut();
}

void StringCircularBuffer::put(std::string &&item)
{
    updateMembersBeforePut();
    buffer[head] = std::move(item);
    updateMembersAfterPut();
}

void StringCircularBuffer::reset()
{
    head = tail;
    full = false;
    size = 0;
}

void StringCircularBuffer::updateMembersAfterPut()
{
    head = (head + 1) % capacity;
    full = head == tail;
}

void StringCircularBuffer::updateMembersBeforePut()
{
    if (full) {
        tail = (tail + 1) % capacity;
    }
    else {
        ++size;
    }
}

A module-utils/circular_buffer/StringCircularBuffer.hpp => module-utils/circular_buffer/StringCircularBuffer.hpp +46 -0
@@ 0,0 1,46 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <memory>
#include <string>

class StringCircularBuffer
{
  public:
    explicit StringCircularBuffer(size_t size) : buffer(std::make_unique<std::string[]>(size)), capacity(size)
    {}
    virtual ~StringCircularBuffer() = default;
    [[nodiscard]] size_t getCapacity() const noexcept
    {
        return capacity;
    }
    [[nodiscard]] bool isEmpty() const noexcept
    {
        return size == 0;
    }
    [[nodiscard]] virtual std::pair<bool, std::string> get();
    [[nodiscard]] size_t getSize() const noexcept
    {
        return size;
    }
    [[nodiscard]] bool isFull() const noexcept
    {
        return full;
    }
    virtual void put(const std::string &item);
    virtual void put(std::string &&item);
    void reset();

  private:
    void updateMembersAfterPut();
    void updateMembersBeforePut();

    std::unique_ptr<std::string[]> buffer;
    bool full{false};
    size_t head{0};
    size_t capacity;
    size_t size{0};
    size_t tail{0};
};

A module-utils/generators/RandomStringGenerator.cpp => module-utils/generators/RandomStringGenerator.cpp +20 -0
@@ 0,0 1,20 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <algorithm>
#include "RandomStringGenerator.hpp"

std::string RandomStringGenerator::getRandomString()
{
    const size_t length = lengthDist(rng);
    std::string str(length, 0);
    std::generate_n(str.begin(), length, [this]() { return charSet[charDist(rng)]; });
    return str;
}

std::vector<std::string> RandomStringGenerator::createRandomStringVector(size_t size)
{
    std::vector<std::string> vec(size);
    std::generate_n(vec.begin(), size, [this]() { return getRandomString(); });
    return vec;
}

A module-utils/generators/RandomStringGenerator.hpp => module-utils/generators/RandomStringGenerator.hpp +33 -0
@@ 0,0 1,33 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <random>
#include <string>
#include <vector>

class RandomStringGenerator
{
  public:
    RandomStringGenerator(size_t minLength = minRandomStringLength, size_t maxLength = maxRandomStringLength)
        : minLength(minLength), maxLength(maxLength), lengthDist(minLength, maxLength)
    {}

    std::string getRandomString();
    std::vector<std::string> createRandomStringVector(size_t size);

  private:
    std::uniform_int_distribution<> charDist{0, sizeof(charSet) - 1};
    std::default_random_engine rng{std::random_device{}()};
    const size_t minLength;
    const size_t maxLength;
    std::uniform_int_distribution<> lengthDist;

    static constexpr auto minRandomStringLength = 1;
    static constexpr auto maxRandomStringLength = 25;
    static constexpr char charSet[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
                                       'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
                                       'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
                                       'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
};

M module-utils/ical/ParserICS.cpp => module-utils/ical/ParserICS.cpp +8 -5
@@ 446,7 446,7 @@ auto Event::timeStringFrom(const std::string &icalTime) const -> std::string
           getSecondsFromIcalTime(icalTime);
}

auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint
auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> calendar::TimePoint
{
    std::string icalDate(getDateFromIcalFormat(icalDateTime));
    std::string icalTime(getTimeFromIcalFormat(icalDateTime));


@@ 459,7 459,7 @@ auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> Time
    return TimePointFromString(dateTime.c_str());
}

auto Event::TimePointToIcalDate(const TimePoint &tp) const -> std::string
auto Event::TimePointToIcalDate(const calendar::TimePoint &tp) const -> std::string
{
    constexpr uint32_t bufferLimit = 16;
    auto time                      = TimePointToTimeT(tp);


@@ 541,7 541,10 @@ auto Event::validateUID(const std::string &UID) -> bool
    return validateDT(DTimestamp);
}

Event::Event(const std::string &summary, const TimePoint from, TimePoint till, const std::string &uid)
Event::Event(const std::string &summary,
             const calendar::TimePoint from,
             calendar::TimePoint till,
             const std::string &uid)
{
    if (summary.empty()) {
        isValid = false;


@@ 595,12 598,12 @@ auto Event::getSummary() const -> std::string
    return summary;
}

auto Event::getDTStartTimePoint() const -> TimePoint
auto Event::getDTStartTimePoint() const -> calendar::TimePoint
{
    return dtstart;
}

auto Event::getDTEndTimePoint() const -> TimePoint
auto Event::getDTEndTimePoint() const -> calendar::TimePoint
{
    return dtend;
}

M module-utils/ical/ParserICS.hpp => module-utils/ical/ParserICS.hpp +7 -7
@@ 91,8 91,8 @@ class Event
{
    std::string uid;
    std::string summary;
    TimePoint dtstart;
    TimePoint dtend;
    calendar::TimePoint dtstart;
    calendar::TimePoint dtend;

    auto isDate(const std::string &dt) -> bool;
    auto isTime(const std::string &dt) -> bool;


@@ 112,13 112,13 @@ class Event
    [[nodiscard]] auto dateStringFrom(const std::string &icalDate) const -> std::string;
    [[nodiscard]] auto timeStringFrom(const std::string &icalTime) const -> std::string;

    [[nodiscard]] auto TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint;
    [[nodiscard]] auto TimePointToIcalDate(const TimePoint &tp) const -> std::string;
    [[nodiscard]] auto TimePointFromIcalDate(const std::string &icalDateTime) const -> calendar::TimePoint;
    [[nodiscard]] auto TimePointToIcalDate(const calendar::TimePoint &tp) const -> std::string;

  public:
    bool isValid = true;
    Event()      = default;
    Event(const std::string &summary, TimePoint from, TimePoint till, const std::string &uid);
    Event(const std::string &summary, calendar::TimePoint from, calendar::TimePoint till, const std::string &uid);

    void setUID(const std::string &property);
    void setSummary(const std::string &property);


@@ 127,8 127,8 @@ class Event

    [[nodiscard]] auto getUID() const -> std::string;
    [[nodiscard]] auto getSummary() const -> std::string;
    [[nodiscard]] auto getDTStartTimePoint() const -> TimePoint;
    [[nodiscard]] auto getDTEndTimePoint() const -> TimePoint;
    [[nodiscard]] auto getDTStartTimePoint() const -> calendar::TimePoint;
    [[nodiscard]] auto getDTEndTimePoint() const -> calendar::TimePoint;

    [[nodiscard]] auto getDTStartString() const -> std::string;
    [[nodiscard]] auto getDTEndString() const -> std::string;

A module-utils/log/LoggerBuffer.cpp => module-utils/log/LoggerBuffer.cpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "LoggerBuffer.hpp"

std::pair<bool, std::string> LoggerBuffer::get()
{
    auto [result, logMsg] = StringCircularBuffer::get();
    if (!result) {
        return {result, logMsg};
    }
    if (numOfLostBytes > 0) {
        logMsg += "\r\n" + std::to_string(numOfLostBytes) + " " + lostBytesMessage;
        numOfLostBytes = 0;
    }
    return {true, logMsg};
}

void LoggerBuffer::put(const std::string &logMsg)
{
    updateNumOfLostBytes();
    StringCircularBuffer::put(logMsg);
}

void LoggerBuffer::put(std::string &&logMsg)
{
    updateNumOfLostBytes();
    StringCircularBuffer::put(std::move(logMsg));
}

void LoggerBuffer::updateNumOfLostBytes()
{
    if (StringCircularBuffer::isFull()) {
        auto [_, lostMsg] = StringCircularBuffer::get();
        numOfLostBytes += lostMsg.length();
    }
}

A module-utils/log/LoggerBuffer.hpp => module-utils/log/LoggerBuffer.hpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "circular_buffer/StringCircularBuffer.hpp"

class LoggerBuffer : public StringCircularBuffer
{
  public:
    using StringCircularBuffer::StringCircularBuffer;

    [[nodiscard]] std::pair<bool, std::string> get() override;
    void put(const std::string &logMsg) override;
    void put(std::string &&logMsg) override;

    static constexpr auto lostBytesMessage = "bytes was lost.";

  private:
    void updateNumOfLostBytes();

    size_t numOfLostBytes{0};
};

M module-utils/test/CMakeLists.txt => module-utils/test/CMakeLists.txt +10 -0
@@ 75,6 75,16 @@ add_catch2_executable(
        module-utils
)

# Logger buffer tests
add_catch2_executable(
    NAME
        utils-loggerbuffer
    SRCS
        test_LoggerBuffer.cpp
    LIBS
        module-utils
)

# ParserICS tests
#add_catch2_executable(
#    NAME

A module-utils/test/test_LoggerBuffer.cpp => module-utils/test/test_LoggerBuffer.cpp +192 -0
@@ 0,0 1,192 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include <catch2/catch.hpp>

#include "generators/RandomStringGenerator.hpp"
#include "log/LoggerBuffer.hpp"
#include <string>
#include <vector>

using namespace std;

void TestBuffer(const LoggerBuffer &buffer, size_t capacity, size_t numOfMsgs)
{
    const bool isEmpty = buffer.isEmpty();
    REQUIRE((numOfMsgs == 0 ? isEmpty : !isEmpty));
    const bool isFull = buffer.isFull();
    REQUIRE((capacity > 0 && capacity == numOfMsgs ? isFull : !isFull));
    REQUIRE(buffer.getCapacity() == capacity);
    REQUIRE(buffer.getSize() == numOfMsgs);
}

size_t GetNumOfBytes(vector<string>::const_iterator startIt, vector<string>::const_iterator endIt)
{
    size_t numOfBytes = 0;
    for (; startIt != endIt; ++startIt) {
        numOfBytes += startIt->length();
    }
    return numOfBytes;
}

TEST_CASE("LoggerBuffer tests")
{
    const size_t capacity = 100;
    LoggerBuffer buffer(capacity);

    RandomStringGenerator randomStringGenerator;

    auto putMsgFunc = [&](const auto &msg) { buffer.put(msg); };
    auto getMsgFunc = [&](const auto &originalMsg) {
        const auto [result, msg] = buffer.get();
        REQUIRE(result);
        REQUIRE(msg == originalMsg);
    };
    auto putAllMsgsFunc = [&](const vector<string> &msgs) { for_each(msgs.begin(), msgs.end(), putMsgFunc); };
    auto getAllMsgsFunc = [&](const vector<string> &msgs) { for_each(msgs.begin(), msgs.end(), getMsgFunc); };
    auto checkLostBytes = [&](size_t numOfBytes, const string &originalMsg) {
        const auto [result, msg] = buffer.get();
        REQUIRE(result);
        REQUIRE(msg.find(originalMsg) != string::npos);
        REQUIRE(msg.find(to_string(numOfBytes)) != string::npos);
        REQUIRE(msg.find(LoggerBuffer::lostBytesMessage) != string::npos);
    };

    SECTION("calling get on empty buffer should return false")
    {
        const auto [result, _] = buffer.get();
        REQUIRE(!result);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("after putting one msg in buffer, get should return this msg")
    {
        const string originalMsg = randomStringGenerator.getRandomString();
        buffer.put(originalMsg);
        TestBuffer(buffer, capacity, 1);
        const auto [result, msg] = buffer.get();
        REQUIRE(result);
        REQUIRE(msg == originalMsg);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("after filling whole buffer with msgs, caliling get repeatedly should return all these msgs back")
    {
        const auto msgs = randomStringGenerator.createRandomStringVector(capacity);
        putAllMsgsFunc(msgs);
        TestBuffer(buffer, capacity, msgs.size());
        getAllMsgsFunc(msgs);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("buffer should be empty after resetting it")
    {
        const auto msgs = randomStringGenerator.createRandomStringVector(capacity);
        putAllMsgsFunc(msgs);
        TestBuffer(buffer, capacity, msgs.size());
        buffer.reset();
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("when more msgs are put into buffer than its capacity, only last msgs should be returned with get and "
            "first msg should contain lost bytes message")
    {
        const size_t numOfMsgsAboveCapacity = 13;
        const auto msgs = randomStringGenerator.createRandomStringVector(capacity + numOfMsgsAboveCapacity);
        putAllMsgsFunc(msgs);
        auto firstLostMsgIt       = msgs.begin();
        auto firstMsgInBufferIt   = firstLostMsgIt + numOfMsgsAboveCapacity;
        const auto numOfLostBytes = GetNumOfBytes(firstLostMsgIt, firstMsgInBufferIt);
        checkLostBytes(numOfLostBytes, *firstMsgInBufferIt);
        for_each(firstMsgInBufferIt + 1, msgs.end(), getMsgFunc);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("each get should reduce number of msgs in buffer")
    {
        size_t numOfMsgsInBuffer = capacity;
        const auto msgs          = randomStringGenerator.createRandomStringVector(capacity);

        auto getStartIt = msgs.begin();

        putAllMsgsFunc(msgs);
        TestBuffer(buffer, capacity, capacity);

        size_t numOfMsgsToGet = 15;
        for_each(getStartIt, getStartIt + numOfMsgsToGet, getMsgFunc);
        numOfMsgsInBuffer -= numOfMsgsToGet;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);
        getStartIt += numOfMsgsToGet;

        numOfMsgsToGet = 34;
        for_each(getStartIt, getStartIt + numOfMsgsToGet, getMsgFunc);
        numOfMsgsInBuffer -= numOfMsgsToGet;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);
        getStartIt += numOfMsgsToGet;

        for_each(getStartIt, msgs.end(), getMsgFunc);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("put get put get")
    {
        const auto msgs = randomStringGenerator.createRandomStringVector(capacity);

        auto putStartIt = msgs.begin();
        auto getStartIt = msgs.begin();

        size_t numOfMsgsToPut = 37;
        for_each(putStartIt, putStartIt + numOfMsgsToPut, putMsgFunc);
        putStartIt += numOfMsgsToPut;
        size_t numOfMsgsInBuffer = numOfMsgsToPut;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        size_t numOfMsgsToGet = 25;
        for_each(getStartIt, getStartIt + numOfMsgsToGet, getMsgFunc);
        getStartIt += numOfMsgsToGet;
        numOfMsgsInBuffer -= numOfMsgsToGet;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        numOfMsgsToPut = msgs.end() - putStartIt;
        for_each(putStartIt, msgs.end(), putMsgFunc);
        numOfMsgsInBuffer += numOfMsgsToPut;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        for_each(getStartIt, msgs.end(), getMsgFunc);
        TestBuffer(buffer, capacity, 0);
    }

    SECTION("put get put get - with buffer overflow")
    {
        const size_t numOfMsgsAboveCapacity = 43;
        const auto msgs = randomStringGenerator.createRandomStringVector(capacity + numOfMsgsAboveCapacity);

        auto putStartIt = msgs.begin();
        auto getStartIt = msgs.begin();

        size_t numOfMsgsToPut = 77;
        for_each(putStartIt, putStartIt + numOfMsgsToPut, putMsgFunc);
        putStartIt += numOfMsgsToPut;
        size_t numOfMsgsInBuffer = numOfMsgsToPut;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        size_t numOfMsgsToGet = 15;
        for_each(getStartIt, getStartIt + numOfMsgsToGet, getMsgFunc);
        getStartIt += numOfMsgsToGet;
        numOfMsgsInBuffer -= numOfMsgsToGet;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        numOfMsgsToPut = msgs.end() - putStartIt; // put rest of msgs - more than buffer can hold
        for_each(putStartIt, msgs.end(), putMsgFunc);
        numOfMsgsInBuffer = capacity;
        TestBuffer(buffer, capacity, numOfMsgsInBuffer);

        auto firstLostMsgIt       = getStartIt;
        auto firstMsgInBufferIt   = firstLostMsgIt + numOfMsgsAboveCapacity - numOfMsgsToGet;
        const auto numOfLostBytes = GetNumOfBytes(firstLostMsgIt, firstMsgInBufferIt);
        checkLostBytes(numOfLostBytes, *firstMsgInBufferIt);
        for_each(firstMsgInBufferIt + 1, msgs.end(), getMsgFunc);
        TestBuffer(buffer, capacity, 0);
    }
}

M module-utils/time/TimeRangeParser.cpp => module-utils/time/TimeRangeParser.cpp +2 -2
@@ 19,8 19,8 @@ namespace utils::time
        return utils::localize.get(utils::time::Locale::getPM());
    }

    std::string TimeRangeParser::getCalendarTimeString(TimePoint startDate,
                                                       TimePoint endDate,
    std::string TimeRangeParser::getCalendarTimeString(calendar::TimePoint startDate,
                                                       calendar::TimePoint endDate,
                                                       Version version,
                                                       bool isMode24H)
    {

M module-utils/time/TimeRangeParser.hpp => module-utils/time/TimeRangeParser.hpp +2 -2
@@ 20,8 20,8 @@ namespace utils::time
        std::string AMPMtoString(bool isAm);

      public:
        std::string getCalendarTimeString(TimePoint startDate,
                                          TimePoint endDate,
        std::string getCalendarTimeString(calendar::TimePoint startDate,
                                          calendar::TimePoint endDate,
                                          Version version = Version::normal,
                                          bool isMode24H  = false);
    };

M test/harness/harness.py => test/harness/harness.py +5 -1
@@ 72,7 72,11 @@ class Harness:

    def send_text(self, text: str):
        for letter in text:
            send_char(letter, self.connection)
            try:
                send_char(letter, self.connection)
            except KeyError as e:
                available = ' '.join((f"'{_}'" for _ in utils.keymap.keys()))
                raise LookupError(f"Character {e} not present in the keymap\nAvailable characters: {available}")

    def send_number(self, number: str):
        utils.send_number(number, self.connection)

M test/harness/utils.py => test/harness/utils.py +2 -1
@@ 156,7 156,8 @@ class Timeout(Exception):

    @classmethod
    @contextmanager
    def limit(cls, seconds):
    def limit(cls, seconds: int):
        assert seconds >= 1, "Timeout must be at least 1 second !"
        def signal_handler(signum, frame):
            raise Timeout("Timed out!")


M test/pytest/conftest.py => test/pytest/conftest.py +1 -1
@@ 54,7 54,7 @@ def harness(request):
    Try to init one Pure phone with serial port path or automatically
    '''
    port_name = request.config.option.port
    TIMEOUT = int(request.config.option.timeout)
    TIMEOUT = min(1, request.config.option.timeout)
    timeout_started = time.time()

    RETRY_EVERY_SECONDS = 1.0

M tools/check_commit_messages.py => tools/check_commit_messages.py +1 -1
@@ 33,7 33,7 @@ def validate_commit(commit):
  empty_line = lines[1]
  body = ''.join(lines[2:]).strip()

  subject_format = r'^\[\w+-\d+\] .+[^.]$'
  subject_format = r'^\[EGD-\d+\] [A-Z].+[^.]$'
  if not re.match(subject_format, subject):
    errors.append(f'[{commit.hexsha}] invalid subject "{subject}", should match format "{subject_format}"')


A tools/clang-tidy.cmake => tools/clang-tidy.cmake +19 -0
@@ 0,0 1,19 @@
find_program(RUN_CLANG_TIDY_COMMAND NAMES run-clang-tidy)
if (NOT RUN_CLANG_TIDY_COMMAND)
	message(WARNING "run-clang-tidy can not be found.")
	return()
endif()

if (NOT CMAKE_EXPORT_COMPILE_COMMANDS)
	message(WARNING "Unable to run clang-tidy without the compile commands database.")
	return()
endif()

set(STATIC_ANALYSIS_OUTPUT_DIR "StaticAnalysis")

string(TIMESTAMP CURRENT_TIME)
set(CLANG_TIDY_OUTPUL_FILE "clang-tidy_${CURRENT_TIME}")

add_custom_target(clang-tidy
	COMMAND ${CMAKE_COMMAND} -E make_directory ${STATIC_ANALYSIS_OUTPUT_DIR}
	COMMAND ${RUN_CLANG_TIDY_COMMAND} -header-filter='.*' -p ${CMAKE_BINARY_DIR} > "${STATIC_ANALYSIS_OUTPUT_DIR}/${CLANG_TIDY_OUTPUL_FILE}")

M tools/download_asset.py => tools/download_asset.py +2 -2
@@ 52,7 52,7 @@ class Getter(object):
        try:
            gitConfigReader = self.gitRepo.config_reader()
            self.apitoken = gitConfigReader.get_value("user", "apitoken")
        except git.exc.NoOptionError as error:
        except: 
            pass

    def getGHLogin(self, args=None):


@@ 63,7 63,7 @@ class Getter(object):
        try:
            gitConfigReader = self.gitRepo.config_reader()
            self.ghLogin = gitConfigReader.get_value("user", "githublogin")
        except git.exc.NoOptionError as error:
        except:
            pass

    def findWorkDir(self):