~aleteoryx/muditaos

97899f428294fb8d35f8b191b334d0fa14b4736d — Przemyslaw Brudny 4 years ago 9b9c44b + e9177f2
Merge remote-tracking branch 'origin/stable'
26 files changed, 399 insertions(+), 72 deletions(-)

M module-apps/apps-common/popups/presenter/AlarmPresenter.cpp
M module-bluetooth/Bluetooth/BluetoothWorker.cpp
M module-bluetooth/Bluetooth/BluetoothWorker.hpp
M module-bluetooth/Bluetooth/CommandHandler.cpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp
M module-os/board/rt1051/_exit.cpp
M module-platform/linux/tests/unittest_filesystem_core.cpp
M module-platform/linux/tests/unittest_filesystem_ext4.cpp
M module-services/service-bluetooth/ServiceBluetooth.cpp
M module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp
M module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp
M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp
M module-services/service-evtmgr/screen-light-control/ScreenLightControlParameters.hpp
M module-services/service-time/AlarmOperations.cpp
M module-services/service-time/AlarmOperations.hpp
M module-services/service-time/tests/tests-AlarmOperations.cpp
M module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp
M products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.cpp
M products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.hpp
M products/PurePhone/services/desktop/endpoints/contacts/ContactHelper.cpp
M products/PurePhone/services/evtmgr/EventManager.cpp
M products/PurePhone/services/evtmgr/backlight-handler/BacklightHandler.cpp
M products/PurePhone/services/evtmgr/include/evtmgr/BacklightHandler.hpp
M products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.cpp
M products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.hpp
M module-apps/apps-common/popups/presenter/AlarmPresenter.cpp => module-apps/apps-common/popups/presenter/AlarmPresenter.cpp +3 -2
@@ 40,8 40,9 @@ namespace app::popup

    template <typename requestType, typename responseType> void AlarmPopupContract::AlarmModel::snoozeAlarm()
    {
        auto request =
            std::make_unique<requestType>(record->ID, TimePointNow() + std::chrono::minutes(record->snoozeDuration));
        auto request = std::make_unique<requestType>(record->ID,
                                                     std::chrono::floor<std::chrono::minutes>(TimePointNow()) +
                                                         std::chrono::minutes(record->snoozeDuration));
        auto task = async(std::move(request), service::name::service_time);
        auto cb   = [&](auto response) {
            auto result = dynamic_cast<responseType *>(response);

M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +14 -0
@@ 157,6 157,7 @@ auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
    case bluetooth::Command::Unpair:
        controller->processCommand(command);
        removeFromBoundDevices(command.getDevice().address);
        handleUnpairDisconnect(command.getDevice());
        break;
    case bluetooth::Command::None:
        break;


@@ 284,3 285,16 @@ void BluetoothWorker::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDe
    cpp_freertos::LockGuard lock(loopMutex);
    profileManager->setAudioDevice(std::move(device));
}
auto BluetoothWorker::isAddressConnected(const uint8_t *addr) -> bool
{
    auto deviceAddr =
        std::visit(bluetooth::StringVisitor(), this->settings->getValue(bluetooth::Settings::ConnectedDevice));
    return static_cast<bool>(deviceAddr == bd_addr_to_str(addr));
}
void BluetoothWorker::handleUnpairDisconnect(const Devicei &device)
{
    if (isAddressConnected(device.address)) {
        auto disconnectCmd = bluetooth::Command(bluetooth::Command::DisconnectAudio, device);
        controller->processCommand(disconnectCmd);
    }
}

M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +2 -0
@@ 80,6 80,8 @@ class BluetoothWorker : private sys::Worker
    void onLinkKeyAdded(const std::string &deviceAddress);
    void initDevicesList();
    void removeFromBoundDevices(uint8_t *addr);
    auto isAddressConnected(const bd_addr_t addr) -> bool;
    void handleUnpairDisconnect(const Devicei &device);

  public:
    enum Error

M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +0 -3
@@ 152,9 152,6 @@ namespace bluetooth
    Error::Code CommandHandler::unpair(const Devicei &device)
    {
        LOG_INFO("Unpairing...");
        if (profileManager->isAddressActuallyUsed(device.address)) {
            profileManager->disconnect();
        }
        const auto error_code = driver->unpair(device) ? Error::Success : Error::LibraryError;
        LOG_INFO("Unpairing result: %s", magic_enum::enum_name(error_code).data());
        return error_code;

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +0 -5
@@ 47,7 47,6 @@ namespace bluetooth
                ptr->connect();
            }
        }

        return Error::Success;
    }



@@ 116,10 115,6 @@ namespace bluetooth
        profilesList[profileType]->setAudioDevice(device);
        return switchProfile(profileType);
    }
    auto ProfileManager::isAddressActuallyUsed(const bd_addr_t address) -> bool
    {
        return !static_cast<bool>(bd_addr_cmp(address, remoteAddr));
    }
    auto ProfileManager::callAnswered() -> Error::Code
    {
        return currentProfilePtr->callAnswered();

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +0 -3
@@ 45,15 45,12 @@ namespace bluetooth
        auto initializeCall() -> Error::Code;
        auto callAnswered() -> Error::Code;
        auto setIncomingCallNumber(const std::string &num) -> Error::Code;
        auto isAddressActuallyUsed(const bd_addr_t address) -> bool;

        auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code;

      private:
        sys::Service *ownerService;
        ProfileList profilesList;
        bluetooth::Profile *currentProfilePtr = nullptr;
        bd_addr_t remoteAddr{};
        bool initialized = false;
    };
} // namespace bluetooth

M module-os/board/rt1051/_exit.cpp => module-os/board/rt1051/_exit.cpp +12 -10
@@ 44,17 44,19 @@

static void __attribute__((noreturn)) stop_system(void)
{
    if (dumpLogs() != 1) {
        LOG_ERROR("Cannot dump logs");
    }
    
    const auto err = purefs::subsystem::unmount_all();
    if(err) {
        LOG_WARN("Unable unmount all filesystems with error: %i.", err);
    } else {
        LOG_INFO("Filesystems unmounted successfully...");
    if(!isIRQ()) {
        if (dumpLogs() != 1) {
            LOG_ERROR("Cannot dump logs");
        }
        const auto err = purefs::subsystem::unmount_all();
        if(err) {
            LOG_WARN("Unable unmount all filesystems with error: %i.", err);
        } else {
            LOG_INFO("Filesystems unmounted successfully...");
        }
    }
    LOG_INFO("Restarting the system...");
    haltIfDebugging();
    vTaskEndScheduler();
    NVIC_SystemReset();
    // waiting for system reset


@@ 68,7 70,7 @@ static void __attribute__((noreturn)) stop_system(void)
void __attribute__((noreturn, used)) _exit_backtrace(int code, bool bt_dump)
{
    LOG_INFO("_exit %d", code);
    if( bt_dump ) {
    if( bt_dump && !isIRQ() ) {
        _StackTrace_Dump_And_Abort();
    }
    stop_system();

M module-platform/linux/tests/unittest_filesystem_core.cpp => module-platform/linux/tests/unittest_filesystem_core.cpp +71 -0
@@ 366,3 366,74 @@ TEST_CASE("Corefs: Autodetect filesystems")
    REQUIRE(fscore->mount("emmc0part0", "/sys", "auto") == 0);
    REQUIRE(fscore->umount("/sys") == 0);
}

TEST_CASE("Corefs: stat extended")
{
    using namespace purefs;
    auto dm   = std::make_shared<blkdev::disk_manager>();
    auto disk = std::make_shared<blkdev::disk_image>(::testing::vfs::disk_image);
    REQUIRE(disk);
    REQUIRE(dm->register_device(disk, "emmc0") == 0);
    purefs::fs::filesystem fs_core(dm);
    const auto vfs_vfat = std::make_shared<fs::drivers::filesystem_vfat>();
    REQUIRE(vfs_vfat->mount_count() == 0);
    auto ret = fs_core.register_filesystem("vfat", vfs_vfat);
    REQUIRE(ret == 0);
    REQUIRE(fs_core.mount("emmc0part0", "/sys", "vfat") == 0);

    // Check if it is a directory
    struct stat st;
    REQUIRE(fs_core.stat("/sys", st) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(fs_core.stat("/sys/", st) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    // Check for dir and subdir
    const auto dir = "/sys/advdirx";
    const auto fil = "/sys/advdirx/advfile";
    // Create directory and truncated file
    REQUIRE(fs_core.mkdir(dir, 0755) == 0);
    auto fd = fs_core.open(fil, O_CREAT | O_RDWR, 0);
    REQUIRE(fd >= 3);
    REQUIRE(fs_core.ftruncate(fd, 124567) == 0);
    REQUIRE(fs_core.close(fd) == 0);
    fd = -1;

    // Now check for stat for directories and sub dirs
    // Root dir
    REQUIRE(fs_core.stat("/sys", st) == 0);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode) == 0);

    // Sub dir
    REQUIRE(fs_core.stat(dir, st) == 0);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode) == 0);

    // Check for file
    REQUIRE(0 == fs_core.stat(fil, st));
    REQUIRE(124567 == st.st_size);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode) == 0);
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode));

    // Final cleanup
    REQUIRE(0 == fs_core.unlink(fil));
    REQUIRE(0 == fs_core.rmdir(dir));

    // Final umount
    REQUIRE(fs_core.umount("/sys") == 0);
}

M module-platform/linux/tests/unittest_filesystem_ext4.cpp => module-platform/linux/tests/unittest_filesystem_ext4.cpp +64 -1
@@ 239,7 239,7 @@ TEST_CASE("ext4: Directory tests")
    REQUIRE(fs_core->umount("/sys") == 0);
}

TEST_CASE("littlefs: Remount RO->RW->RW")
TEST_CASE("ext4: Remount RO->RW->RW")
{
    using namespace purefs;
    static constexpr auto filename = "/sys/remount_test.txt";


@@ 276,3 276,66 @@ TEST_CASE("littlefs: Remount RO->RW->RW")

    REQUIRE(fs_core->umount("/sys") == 0);
}

TEST_CASE("ext4: stat extended")
{
    using namespace purefs;
    auto [fs_core, dm] = prepare_filesystem("emmc0");
    REQUIRE(fs_core);
    REQUIRE(fs_core->mount("emmc0part0", "/sys", "ext4") == 0);
    // Check if it is a directory
    struct stat st;
    REQUIRE(fs_core->stat("/sys", st) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(fs_core->stat("/sys/", st) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    // Check for dir and subdir
    const auto dir = "/sys/advdirx";
    const auto fil = "/sys/advdirx/advfile";
    // Create directory and truncated file
    REQUIRE(fs_core->mkdir(dir, 0755) == 0);
    auto fd = fs_core->open(fil, O_CREAT | O_RDWR, 0);
    REQUIRE(fd >= 3);
    REQUIRE(fs_core->ftruncate(fd, 124567) == 0);
    REQUIRE(fs_core->close(fd) == 0);
    fd = -1;

    // Now check for stat for directories and sub dirs
    // Root dir
    REQUIRE(fs_core->stat("/sys", st) == 0);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode) == 0);

    // Sub dir
    REQUIRE(fs_core->stat(dir, st) == 0);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode));
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode) == 0);

    // Check for file
    REQUIRE(0 == fs_core->stat(fil, st));
    REQUIRE(124567 == st.st_size);
    REQUIRE(S_ISFIFO(st.st_mode) == 0);
    REQUIRE(S_ISCHR(st.st_mode) == 0);
    REQUIRE(S_ISDIR(st.st_mode) == 0);
    REQUIRE(S_ISBLK(st.st_mode) == 0);
    REQUIRE(S_ISLNK(st.st_mode) == 0);
    REQUIRE(S_ISSOCK(st.st_mode) == 0);
    REQUIRE(S_ISREG(st.st_mode));

    // Final cleanup
    REQUIRE(0 == fs_core->unlink(fil));
    REQUIRE(0 == fs_core->rmdir(dir));

    // Final umount
    REQUIRE(fs_core->umount("/sys") == 0);
}

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +0 -2
@@ 294,8 294,6 @@ auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::sh
{
    if (msg->isSucceed()) {
        auto device        = msg->getDevice();
        auto deviceInModel = bluetoothDevicesModel->getDeviceByAddress(device.address)->get();

        bluetoothDevicesModel->mergeInternalDeviceState(device);

        settingsHolder->setValue(bluetooth::Settings::ConnectedDevice, bd_addr_to_str(device.address));

M module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp => module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp +5 -0
@@ 108,6 108,11 @@ namespace screen_light_control::functions
        rampTarget = value;
    }

    void resetRampToTarget()
    {
        rampState = rampTarget;
    }

    bool isRampTargetReached()
    {
        return rampTargetReached;

M module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp => module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp +2 -0
@@ 29,6 29,8 @@ namespace screen_light_control::functions

    void setRampStep(float step);

    void resetRampToTarget();

    void setHysteresis(float hyst);

    void setFunctionFromPoints(const BrightnessFunction &points);

M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp => module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp +1 -0
@@ 31,5 31,6 @@ namespace screen_light_control
        [[nodiscard]] virtual auto isAutoModeOn() const noexcept -> bool     = 0;
        [[nodiscard]] virtual auto getBrightnessValue() const noexcept
            -> bsp::eink_frontlight::BrightnessPercentage = 0;
        [[nodiscard]] virtual auto isFadeOutOngoing() -> bool = 0;
    };
} // namespace screen_light_control

M module-services/service-evtmgr/screen-light-control/ScreenLightControlParameters.hpp => module-services/service-evtmgr/screen-light-control/ScreenLightControlParameters.hpp +9 -8
@@ 18,12 18,13 @@ namespace screen_light_control
    /// Set of actions to control the screen light
    enum class Action
    {
        turnOff,                   ///< Turn off screen frontlight
        turnOn,                    ///< Turn on screen frontlight
        enableAutomaticMode,       ///< Enable automatic mode of screen frontlight
        disableAutomaticMode,      ///< Disable automatic mode of screen frontlight
        setManualModeBrightness,   ///< Set screen brightness in manual mode control
        setAutomaticModeParameters ///< Set parameters for automatic mode of screen frontlight
        turnOff,                    ///< Turn off screen frontlight
        turnOn,                     ///< Turn on screen frontlight
        enableAutomaticMode,        ///< Enable automatic mode of screen frontlight
        disableAutomaticMode,       ///< Disable automatic mode of screen frontlight
        setManualModeBrightness,    ///< Set screen brightness in manual mode control
        setAutomaticModeParameters, ///< Set parameters for automatic mode of screen frontlight
        fadeOut                     ///< Set light fade out in automatic mode
    };

    struct ManualModeParameters


@@ 37,8 38,8 @@ namespace screen_light_control
    {
        /// Vector of points for screen brightness [%] in relation to ambient light [Lux] function. Points have to be in
        /// ascending order of ambient light values.
        functions::BrightnessFunction functionPoints =
            functions::BrightnessFunction({{0.0f, 70.0f}, {250.0f, 70.0f}, {450.0f, 40.0f}, {500.0f, 0.0f}});
        functions::BrightnessFunction functionPoints = functions::BrightnessFunction(
            {{0.0f, 35.0f}, {10.0f, 75.0f}, {85.0f, 100.0f}, {500.0f, 100.0f}, {520.0f, 0.0f}});
        /// Ramp time of screen brightness in milliseconds per 0-100% change
        unsigned int rampTimeMS = 1500;
        /// Hysteresis value of screen brightness control

M module-services/service-time/AlarmOperations.cpp => module-services/service-time/AlarmOperations.cpp +15 -3
@@ 136,6 136,9 @@ namespace alarms
        }
        switchAlarmExecution(*(*found), false);
        ongoingSingleEvents.erase(found);

        processOngoingEvents();

        handleActiveAlarmsCountChange();
        callback(true);
    }


@@ 193,6 196,8 @@ namespace alarms
        switchAlarmExecution(*(*found), false);
        ongoingSingleEvents.erase(found);

        processOngoingEvents();

        handleSnoozedAlarmsCountChange();
        handleActiveAlarmsCountChange();



@@ 280,13 285,20 @@ namespace alarms
            processSnoozedEventsQueue(now);
        }

        if (!isHandlingInProgress && !ongoingSingleEvents.empty()) {
        if (!isHandlingInProgress) {
            processOngoingEvents();
            return true;
        }
        return false;
    }

    void AlarmOperationsCommon::processOngoingEvents()
    {
        if (!ongoingSingleEvents.empty()) {
            switchAlarmExecution(*(ongoingSingleEvents.front()), true);
            handleActiveAlarmsCountChange();
            handleSnoozedAlarmsCountChange();
            return true;
        }
        return false;
    }

    void AlarmOperationsCommon::addAlarmExecutionHandler(const alarms::AlarmType type,

M module-services/service-time/AlarmOperations.hpp => module-services/service-time/AlarmOperations.hpp +1 -0
@@ 141,6 141,7 @@ namespace alarms
        void checkAndUpdateCache(AlarmEventRecord record);
        void switchAlarmExecution(const SingleEventRecord &singleAlarmEvent, bool newStateOn);
        bool processEvents(TimePoint now);
        void processOngoingEvents();
        void processNextEventsQueue(const TimePoint now);
        void processSnoozedEventsQueue(const TimePoint now);
        virtual void onAlarmTurnedOff(const std::shared_ptr<AlarmEventRecord> &event, alarms::AlarmType alarmType);

M module-services/service-time/tests/tests-AlarmOperations.cpp => module-services/service-time/tests/tests-AlarmOperations.cpp +40 -0
@@ 608,3 608,43 @@ TEST_F(AlarmOperationsFixture, recurrentAlarmEnablingDisabling)
    alarmOperations->updateAlarm(alarmRecord, universalBoolCallback);
    EXPECT_FALSE(alarmActive);
}

TEST_F(AlarmOperationsFixture, handleMultipleConcurrentAlarms)
{
    auto alarmRepoMock         = std::make_unique<MockAlarmEventsRepository>();
    const auto alarmTime       = TimePointFromStringWithShift("2022-11-11 11:00:00");
    const auto alarmTimeSnooze = TimePointFromStringWithShift("2022-11-11 11:10:00");
    alarmRepoMock->nextRecords.push_back(
        AlarmEventRecord(1, AlarmTime{11h, 0min}, defMusic, defEnabled, defSnooze, defRRule));
    alarmRepoMock->nextRecords.push_back(
        AlarmEventRecord(2, AlarmTime{11h, 0min}, defMusic, defEnabled, defSnooze, defRRule));
    alarmRepoMock->nextRecords.push_back(
        AlarmEventRecord(3, AlarmTime{11h, 0min}, defMusic, defEnabled, defSnooze, defRRule));

    auto alarmOperations = getMockedAlarmOperations(alarmRepoMock);
    auto handler         = std::make_shared<MockAlarmHandler>();
    EXPECT_CALL(*handler, handle(testing::_)).Times(6);
    alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler);

    int snoozedCount   = 0;
    auto countcallback = [&](unsigned count) { snoozedCount = count; };
    alarmOperations->addSnoozedAlarmsCountChangeCallback(countcallback);
    bool alarmActive    = false;
    auto activeCallback = [&](bool isAnyActive) { alarmActive = isAnyActive; };
    alarmOperations->addActiveAlarmCountChangeCallback(activeCallback);

    alarmOperations->updateEventsCache(TimePointFromStringWithShift("2022-11-11 08:59:00"));

    alarmOperations->minuteUpdated(alarmTime);
    alarmOperations->snoozeRingingAlarm(1, alarmTimeSnooze, universalBoolCallback);
    alarmOperations->snoozeRingingAlarm(2, alarmTimeSnooze, universalBoolCallback);
    alarmOperations->snoozeRingingAlarm(3, alarmTimeSnooze, universalBoolCallback);
    EXPECT_EQ(snoozedCount, 3);
    EXPECT_TRUE(alarmActive);

    alarmOperations->minuteUpdated(alarmTimeSnooze);
    EXPECT_EQ(snoozedCount, 0);
    alarmOperations->turnOffRingingAlarm(1, universalBoolCallback);
    alarmOperations->turnOffRingingAlarm(2, universalBoolCallback);
    alarmOperations->turnOffRingingAlarm(3, universalBoolCallback);
}

M module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp => module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp +49 -7
@@ 127,18 127,48 @@ namespace purefs::fs::drivers
            st.st_rdev  = 0;
            st.st_size  = fs.fsize;

            // TODO: Block FF_MIN_SS != FF_MAX_SS
#if FF_MAX_SS != FF_MIN_SS
            st.st_blksize = fatfs->ssize;
#else
            st.st_blksize = FF_MIN_SS;
#endif
            // TODO: Time is currently not supported
            st.st_blocks = fs.fsize / st.st_blksize;
            st.st_atime  = 0;
            st.st_mtime  = 0;
            st.st_ctime  = 0;
        }

        int internal_stat_rootdir(const char *translated_path, bool ro, struct stat *entry)
        {
            FATFS *fs;
            DWORD bfree;
            FRESULT res = f_getfree(translated_path, &bfree, &fs);
            if (res != FR_OK) {
                return -EIO;
            }
            entry->st_dev  = 0;
            entry->st_ino  = 0;
            entry->st_mode = (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IRUSR | S_IRGRP | S_IROTH);
            if (!ro) {
                entry->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
            }
            entry->st_nlink = 1;
            entry->st_uid   = 0;
            entry->st_gid   = 0;
            entry->st_rdev  = 0;
            entry->st_size  = 0;
#if FF_MAX_SS != FF_MIN_SS
            entry->st_blksize = fatfs->ssize;
#else
            entry->st_blksize = FF_MIN_SS;
#endif
            entry->st_blocks = fs->fsize / entry->st_blksize;
            entry->st_atime  = 0;
            entry->st_mtime  = 0;
            entry->st_ctime  = 0;
            return 0;
        }

    } // namespace

    auto filesystem_vfat::mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh,


@@ 360,11 390,19 @@ namespace purefs::fs::drivers
        }
        FILINFO finfo;
        const auto fspath = vmnt->native_path(file);
        const int fres    = f_stat(fspath.c_str(), &finfo);
        if (fres == FR_OK) {
            translate_filinfo_to_stat(finfo, nullptr, vmnt->is_ro(), st);
        static constexpr auto slash_pos       = 2U;
        static constexpr auto root_size       = 3U;
        static constexpr auto empty_root_size = 2U;
        if ((fspath[slash_pos] == '/' && fspath.size() == root_size) || fspath.size() == empty_root_size) {
            return internal_stat_rootdir(fspath.c_str(), vmnt->is_ro(), &st);
        }
        else {
            const int fres = f_stat(fspath.c_str(), &finfo);
            if (fres == FR_OK) {
                translate_filinfo_to_stat(finfo, nullptr, vmnt->is_ro(), st);
            }
            return translate_error(fres);
        }
        return translate_error(fres);
    }

    auto filesystem_vfat::unlink(fsmount mnt, std::string_view name) noexcept -> int


@@ 486,7 524,11 @@ namespace purefs::fs::drivers
            LOG_ERROR("Non fat filesystem pointer");
            return -EBADF;
        }
        const int fres = f_truncate(vfile->ff_filp());
        int fres = f_lseek(vfile->ff_filp(), len);
        if (fres != FR_OK) {
            return translate_error(fres);
        }
        fres = f_truncate(vfile->ff_filp());
        return translate_error(fres);
    }


M products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.cpp => products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.cpp +6 -0
@@ 196,4 196,10 @@ namespace bell::screen_light_control
    {
        return std::max<bsp::eink_frontlight::BrightnessPercentage>(target, MINIMAL_TARGET);
    }

    bool ScreenLightController::isFadeOutOngoing()
    {
        return false;
    }

} // namespace bell::screen_light_control

M products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.hpp => products/BellHybrid/services/evtmgr/screen-light-control/ScreenLightControl.hpp +1 -0
@@ 42,6 42,7 @@ namespace bell::screen_light_control
        [[nodiscard]] auto isLightOn() const noexcept -> bool override;
        [[nodiscard]] bool isAutoModeOn() const noexcept override;
        [[nodiscard]] auto getBrightnessValue() const noexcept -> bsp::eink_frontlight::BrightnessPercentage override;
        [[nodiscard]] auto isFadeOutOngoing() -> bool override;

      private:
        void controlTimerCallback();

M products/PurePhone/services/desktop/endpoints/contacts/ContactHelper.cpp => products/PurePhone/services/desktop/endpoints/contacts/ContactHelper.cpp +1 -8
@@ 156,14 156,7 @@ namespace sdesktop::endpoints
    auto ContactHelper::createDBEntry(Context &context) -> sys::ReturnCodes
    {
        auto newRecord = from_json(context.getBody());
        if (newRecord.numbers.empty()) {
            LOG_ERROR("Empty number, not added!");
            context.setResponseStatus(http::Code::NotAcceptable);
            putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Failure;
        }

        auto query = std::make_unique<db::query::ContactAdd>(newRecord);
        auto query     = std::make_unique<db::query::ContactAdd>(newRecord);

        auto listener = std::make_unique<db::EndpointListener>(
            [](db::QueryResult *result, Context context) {

M products/PurePhone/services/evtmgr/EventManager.cpp => products/PurePhone/services/evtmgr/EventManager.cpp +3 -1
@@ 92,6 92,8 @@ void EventManager::initProductEvents()

    connect(sevm::ToggleTorchColorMessage(), [&]([[maybe_unused]] sys::Message *msg) {
        toggleTorchColor();
        // Handle only torch short press. Done here as workaround since only app can recognize press length.
        backlightHandler.handleKeyPressed();
        return sys::MessageNone{};
    });



@@ 166,7 168,7 @@ void EventManager::handleKeyEvent(sys::Message *msg)
    auto kbdMessage = dynamic_cast<sevm::KbdMessage *>(msg);

    if (kbdMessage->key.state == RawKey::State::Pressed) {
        backlightHandler.handleKeyPressed();
        backlightHandler.handleKeyPressed(kbdMessage->key.keyCode);
    }
    else if (kbdMessage->key.state == RawKey::State::Moved) {
        handleKeyMoveEvent(kbdMessage->key);

M products/PurePhone/services/evtmgr/backlight-handler/BacklightHandler.cpp => products/PurePhone/services/evtmgr/backlight-handler/BacklightHandler.cpp +50 -16
@@ 14,21 14,32 @@ namespace backlight
    namespace timers
    {
        constexpr auto keypadLightTimerName    = "KeypadLightTimer";
        constexpr auto keypadLightTimerTimeout = std::chrono::seconds(5);
        constexpr auto lightTimerTimeout        = std::chrono::seconds(20);
        constexpr auto lightFadeoutTimerTimeout = std::chrono::seconds(10);
    } // namespace timers

    namespace
    {
        constexpr std::array exclusions = {bsp::KeyCodes::Torch};

        [[nodiscard]] bool isKeyOnExclusionList(bsp::KeyCodes key)
        {
            for (const auto &exclusion : exclusions) {
                if (key == exclusion) {
                    return true;
                }
            }
            return false;
        }
    } // namespace

    Handler::Handler(std::shared_ptr<settings::Settings> settings, sys::Service *parent)
        : HandlerCommon(std::move(settings),
                        std::make_shared<pure::screen_light_control::ScreenLightController>(parent),
                        parent,
                        [this](sys::Timer &t) {
                            if (getScreenAutoModeState() == screen_light_control::ScreenLightMode::Automatic &&
                                this->screenLightController->isLightOn()) {
                                this->screenLightController->processRequest(screen_light_control::Action::turnOff);
                            }
                        }),
                        [this](sys::Timer &t) { handleScreenLightTimeout(); }),
          keypadLightTimer{sys::TimerFactory::createSingleShotTimer(
              parent, timers::keypadLightTimerName, timers::keypadLightTimerTimeout, [this](sys::Timer &) {
              parent, timers::keypadLightTimerName, timers::lightTimerTimeout, [this](sys::Timer &) {
                  bsp::keypad_backlight::shutdown();
              })}
    {}


@@ 57,17 68,19 @@ namespace backlight
        });
    }

    void Handler::handleKeyPressed([[maybe_unused]] int key)
    void Handler::handleKeyPressed(bsp::KeyCodes key)
    {
        handleKeypadLightRefresh();
        handleScreenLightRefresh();
        if (!isKeyOnExclusionList(key)) {
            handleKeypadLightRefresh();
            handleScreenLightRefresh();
        }
    }

    void Handler::processScreenRequest(screen_light_control::Action action,
                                       const screen_light_control::Parameters &params)
    {
        if (action == screen_light_control::Action::enableAutomaticMode) {
            startScreenLightTimer();
            getScreenLightTimer()->restart(timers::lightTimerTimeout);
        }
        handleScreenLightSettings(action, params);
        getScreenLightControl()->processRequest(action, params);


@@ 157,16 170,37 @@ namespace backlight

    void Handler::handleScreenLightRefresh([[maybe_unused]] const int key)
    {
        if (getScreenLightState() && getScreenAutoModeState() == screen_light_control::ScreenLightMode::Automatic) {
            if (!getScreenLightControl()->isLightOn()) {
        if (getScreenLightState()) {
            if (!getScreenLightControl()->isLightOn() || getScreenLightControl()->isFadeOutOngoing()) {
                getScreenLightControl()->processRequest(screen_light_control::Action::turnOn);
            }
            startScreenLightTimer();
            getScreenLightTimer()->restart(timers::lightTimerTimeout);
        }
    }

    void Handler::handleScreenLightTimeout()
    {
        if (getScreenAutoModeState() == screen_light_control::ScreenLightMode::Automatic) {
            if (screenLightController->isLightOn()) {
                if (screenLightController->isFadeOutOngoing()) {
                    screenLightController->processRequest(screen_light_control::Action::turnOff);
                }
                else {
                    screenLightController->processRequest(screen_light_control::Action::fadeOut);
                    getScreenLightTimer()->restart(timers::lightFadeoutTimerTimeout);
                }
            }
        }
        else if (getScreenAutoModeState() == screen_light_control::ScreenLightMode::Manual) {
            if (screenLightController->isLightOn()) {
                screenLightController->processRequest(screen_light_control::Action::turnOff);
            }
        }
    }

    void Handler::onScreenLightTurnedOn()
    {
        startScreenLightTimer();
        getScreenLightTimer()->restart(timers::lightTimerTimeout);
    }

} // namespace backlight

M products/PurePhone/services/evtmgr/include/evtmgr/BacklightHandler.hpp => products/PurePhone/services/evtmgr/include/evtmgr/BacklightHandler.hpp +3 -1
@@ 8,6 8,7 @@
#include <Timers/TimerHandle.hpp>
#include <Service/ServiceProxy.hpp>
#include <backlight-handler/BacklightHandlerCommon.hpp>
#include <hal/key_input/KeyEventDefinitions.hpp>

namespace settings
{


@@ 23,7 24,7 @@ namespace backlight
        Handler(std::shared_ptr<settings::Settings> settings, sys::Service *parent);

        void init() override;
        void handleKeyPressed(int key = 0);
        void handleKeyPressed(bsp::KeyCodes key = bsp::KeyCodes::Undefined);
        /// Process request of the keypad light control
        /// @keypad_backlight::action an action to perform
        /// @return True if request was processed successfully, false otherwise


@@ 48,5 49,6 @@ namespace backlight
        void handleKeypadLightRefresh();
        void handleScreenLightRefresh(int key = 0);
        void onScreenLightTurnedOn() override;
        void handleScreenLightTimeout();
    };
} // namespace backlight

M products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.cpp => products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.cpp +40 -1
@@ 8,6 8,10 @@

namespace pure::screen_light_control
{
    namespace
    {
        constexpr bsp::eink_frontlight::BrightnessPercentage fadeOutBrigthnessMax = 35.0f;
    }

    ScreenLightController::ScreenLightController(sys::Service *parent)
    {


@@ 58,6 62,9 @@ namespace pure::screen_light_control
                setParameters(params.getAutoModeParams());
            }
            break;
        case Action::fadeOut:
            handleFadeOut();
            break;
        }
    }



@@ 68,7 75,9 @@ namespace pure::screen_light_control

    void ScreenLightController::readoutTimerCallback()
    {
        ::screen_light_control::functions::calculateBrightness(bsp::light_sensor::readout());
        if (!fadeOut) {
            ::screen_light_control::functions::calculateBrightness(bsp::light_sensor::readout());
        }
    }

    auto ScreenLightController::isLightOn() const noexcept -> bool


@@ 137,9 146,21 @@ namespace pure::screen_light_control

    void ScreenLightController::turnOn()
    {
        fadeOut = false;

        bsp::eink_frontlight::turnOn();
        bsp::light_sensor::wakeup();

        if (automaticMode == ScreenLightMode::Automatic) {
            if (lightOn) {
                ::screen_light_control::functions::calculateBrightness(bsp::light_sensor::readout());
            }
            else {
                // It takes some time to get initial readout -> using last saved measurement
                ::screen_light_control::functions::calculateBrightness(stashedReadout);
            }
            ::screen_light_control::functions::resetRampToTarget();
            bsp::eink_frontlight::setBrightness(::screen_light_control::functions::getRampState());
            enableTimers();
        }
        lightOn = true;


@@ 153,9 174,27 @@ namespace pure::screen_light_control
    void ScreenLightController::turnOff()
    {
        bsp::eink_frontlight::turnOff();
        stashedReadout = bsp::light_sensor::readout();
        bsp::light_sensor::standby();
        disableTimers();
        lightOn = false;
        fadeOut = false;
    }

    void ScreenLightController::handleFadeOut()
    {
        if (automaticMode == ScreenLightMode::Automatic) {
            fadeOut = true;
            // Set fadeout brightess as maximum or current ramp state if lower
            auto rampState         = ::screen_light_control::functions::getRampState();
            auto fadeOutBrigthness = std::clamp(rampState, 0.0f, fadeOutBrigthnessMax);
            ::screen_light_control::functions::setRampTarget(fadeOutBrigthness);
        }
    }

    bool ScreenLightController::isFadeOutOngoing()
    {
        return fadeOut;
    }

} // namespace screen_light_control

M products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.hpp => products/PurePhone/services/evtmgr/screen-light-control/ScreenLightControl.hpp +7 -1
@@ 40,6 40,8 @@ namespace pure::screen_light_control
        [[nodiscard]] bool isAutoModeOn() const noexcept override;
        [[nodiscard]] auto getBrightnessValue() const noexcept -> bsp::eink_frontlight::BrightnessPercentage override;

        [[nodiscard]] auto isFadeOutOngoing() -> bool override;

      private:
        void controlTimerCallback();
        void readoutTimerCallback();


@@ 57,6 59,8 @@ namespace pure::screen_light_control
        void enableAutomaticMode();
        void disableAutomaticMode();

        void handleFadeOut();

        static constexpr inline auto CONTROL_TIMER_MS = 25;
        static constexpr inline auto READOUT_TIMER_MS = 500;



@@ 65,6 69,8 @@ namespace pure::screen_light_control

        bool lightOn                                               = false;
        ScreenLightMode automaticMode                              = ScreenLightMode::Manual;
        bsp::eink_frontlight::BrightnessPercentage brightnessValue = 0.0;
        bsp::eink_frontlight::BrightnessPercentage brightnessValue = 0.0f;
        bool fadeOut                                               = false;
        bsp::light_sensor::IlluminanceLux stashedReadout           = 0.0f;
    };
} // namespace pure::screen_light_control