~aleteoryx/muditaos

57c7672f8f4324526dd63c614b6089fa1a9fc021 — Piotr Tanski 5 years ago c1fa253
[EGD-4366] Global data cleanup. (#999)

31 files changed, 619 insertions(+), 501 deletions(-)

M module-apps/application-call/CMakeLists.txt
A module-apps/application-call/widgets/Icons.cpp
M module-apps/application-call/widgets/Icons.hpp
M module-apps/application-special-input/data/SpecialCharactersTableStyle.hpp
M module-apps/application-special-input/models/SpecialInputModel.cpp
M module-apps/application-special-input/models/SpecialInputModel.hpp
M module-audio/Audio/AudioCommon.hpp
M module-audio/Audio/AudioMux.cpp
M module-bsp/board/rt1051/bsp/magnetometer/ALS31300.hpp
M module-bsp/board/rt1051/bsp/magnetometer/magnetometer.cpp
A module-bsp/board/rt1051/common/chip.cpp
M module-bsp/board/rt1051/common/chip.hpp
M module-bsp/targets/Target_RT1051.cmake
M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp
M module-services/service-desktop/endpoints/backup/BackupRestore.cpp
M module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp
M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp
M module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp
M module-services/service-desktop/tests/unittest.cpp
M module-services/service-fileindexer/StartupIndexer.cpp
M module-utils/time/time_conversion.cpp
M module-utils/time/time_conversion.hpp
M module-vfs/CMakeLists.txt
M module-vfs/board/cross/free_rtos_custom/portable/vfs.cpp
M module-vfs/board/linux/free_rtos_custom/portable/vfs.cpp
M module-vfs/vfs-utils.cpp
M module-vfs/vfs.cpp
M module-vfs/vfs.hpp
A module-vfs/vfs_globals.hpp
A module-vfs/vfs_paths.cpp
A module-vfs/vfs_paths.hpp
M module-apps/application-call/CMakeLists.txt => module-apps/application-call/CMakeLists.txt +1 -0
@@ 21,6 21,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/windows/EnterNumberWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/EmergencyCallWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/CallWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/Icons.cpp"
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationCall.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/EnterNumberWindow.hpp"

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

#include "Icons.hpp"

#include "application-call/data/CallAppStyle.hpp"

namespace gui
{
    namespace
    {
        constexpr auto crossImg      = "cross";
        constexpr auto addContactStr = "app_call_contact";
        constexpr auto messageImg    = "mail";
        constexpr auto sendSmstStr   = "app_call_message";
        constexpr auto muteImg       = "microphone_on";
        constexpr auto mutedImg      = "microphone_off";
        constexpr auto muteStr       = "app_call_mute";
        constexpr auto mutedStr      = "app_call_muted";
        constexpr auto speakerImg    = "speaker_off";
        constexpr auto speakerOnImg  = "speaker_on";
        constexpr auto speakerStr    = "app_call_speaker";
        constexpr auto speakerOnStr  = "app_call_speaker_on";

        const Icon<AddContactIconState>::IconMap contactIconMap = {
            {AddContactIconState::ADD_CONTACT, {crossImg, addContactStr}}};
        const Icon<SendSmsIconState>::IconMap smsIconMap = {{SendSmsIconState::SEND_SMS, {messageImg, sendSmstStr}}};
        const Icon<MicrophoneIconState>::IconMap microphoneIconMap = {
            {MicrophoneIconState::MUTE, {muteImg, muteStr}}, {MicrophoneIconState::MUTED, {mutedImg, mutedStr}}};
        const Icon<SpeakerIconState>::IconMap speakerIconMap = {
            {SpeakerIconState::SPEAKER, {speakerImg, speakerStr}},
            {SpeakerIconState::SPEAKERON, {speakerOnImg, speakerOnStr}}};
    } // namespace

    AddContactIcon::AddContactIcon(Item *parent, std::uint32_t x, std::uint32_t y)
        : Icon(parent, x, y, callAppStyle::icon::x_margin, AddContactIconState::ADD_CONTACT, contactIconMap)
    {}

    SendSmsIcon::SendSmsIcon(Item *parent, std::uint32_t x, std::uint32_t y)
        : Icon(parent, x, y, callAppStyle::icon::x_margin, SendSmsIconState::SEND_SMS, smsIconMap)
    {}

    MicrophoneIcon::MicrophoneIcon(Item *parent, std::uint32_t x, std::uint32_t y)
        : Icon(parent, x, y, callAppStyle::icon::x_margin, MicrophoneIconState::MUTE, microphoneIconMap)
    {}

    SpeakerIcon::SpeakerIcon(Item *parent, std::uint32_t x, std::uint32_t y)
        : Icon(parent, x, y, callAppStyle::icon::x_margin, SpeakerIconState::SPEAKER, speakerIconMap)
    {}

} // namespace gui

M module-apps/application-call/widgets/Icons.hpp => module-apps/application-call/widgets/Icons.hpp +9 -51
@@ 4,8 4,8 @@
#pragma once

#include "Icon.hpp"
#include "i18/i18.hpp"
#include "application-call/data/CallAppStyle.hpp"

#include <cstdint>

namespace gui
{


@@ 13,19 13,12 @@ namespace gui
    {
        ADD_CONTACT
    };

    class AddContactIcon : public Icon<AddContactIconState>
    {
      protected:
        static constexpr auto crossImg            = "cross";
        static constexpr auto addContactStr       = "app_call_contact";
        static const inline Icon::IconMap iconMap = {{AddContactIconState::ADD_CONTACT, {crossImg, addContactStr}}};

      public:
        AddContactIcon() = delete;
        AddContactIcon(Item *parent, const uint32_t &x, const uint32_t &y)
            : Icon(parent, x, y, callAppStyle::icon::x_margin, AddContactIconState::ADD_CONTACT, iconMap)
        {}
        ~AddContactIcon() override = default;
        AddContactIcon(Item *parent, std::uint32_t x, std::uint32_t y);
    };

    enum class SendSmsIconState


@@ 34,17 27,9 @@ namespace gui
    };
    class SendSmsIcon : public Icon<SendSmsIconState>
    {
      protected:
        static constexpr auto messageImg          = "mail";
        static constexpr auto sendSmstStr         = "app_call_message";
        static const inline Icon::IconMap iconMap = {{SendSmsIconState::SEND_SMS, {messageImg, sendSmstStr}}};

      public:
        SendSmsIcon() = delete;
        SendSmsIcon(Item *parent, const uint32_t &x, const uint32_t &y)
            : Icon(parent, x, y, callAppStyle::icon::x_margin, SendSmsIconState::SEND_SMS, iconMap)
        {}
        ~SendSmsIcon() override = default;
        SendSmsIcon(Item *parent, std::uint32_t x, std::uint32_t y);
    };

    enum class MicrophoneIconState


@@ 52,51 37,24 @@ namespace gui
        MUTE,
        MUTED
    };

    class MicrophoneIcon : public Icon<MicrophoneIconState>
    {
      protected:
        static constexpr auto muteImg             = "microphone_on";
        static constexpr auto mutedImg            = "microphone_off";
        static constexpr auto muteStr             = "app_call_mute";
        static constexpr auto mutedStr            = "app_call_muted";
        static const inline Icon::IconMap iconMap = {{MicrophoneIconState::MUTE, {muteImg, muteStr}},
                                                     {MicrophoneIconState::MUTED, {mutedImg, mutedStr}}};

      public:
        MicrophoneIcon() = delete;
        MicrophoneIcon(Item *parent, const uint32_t &x, const uint32_t &y)
            : Icon(parent, x, y, callAppStyle::icon::x_margin, MicrophoneIconState::MUTE, iconMap)
        {}
        ~MicrophoneIcon() override = default;
        MicrophoneIcon(Item *parent, std::uint32_t x, std::uint32_t y);
    };

    enum class SpeakerIconState
    {
        SPEAKER,
        SPEAKERON,
        // BLUETOOTH
        SPEAKERON
    };

    class SpeakerIcon : public Icon<SpeakerIconState>
    {
      protected:
        static constexpr auto speakerImg   = "speaker_off";
        static constexpr auto speakerOnImg = "speaker_on";
        // static constexpr auto bluetoothImg = "app_call_bluetooth";
        static constexpr auto speakerStr   = "app_call_speaker";
        static constexpr auto speakerOnStr = "app_call_speaker_on";
        // static constexpr auto bluetoothStr = "app_call_bluetooth";
        static const inline Icon::IconMap iconMap = {
            {SpeakerIconState::SPEAKER, {speakerImg, speakerStr}},
            {SpeakerIconState::SPEAKERON, {speakerOnImg, speakerOnStr}},
            //{SpeakerIconState::BLUETOOTH, {bluetoothImg, bluetoothStr}}
        };

      public:
        SpeakerIcon() = delete;
        SpeakerIcon(Item *parent, const uint32_t &x, const uint32_t &y)
            : Icon(parent, x, y, callAppStyle::icon::x_margin, SpeakerIconState::SPEAKER, iconMap)
        {}
        ~SpeakerIcon() override = default;
        SpeakerIcon(Item *parent, std::uint32_t x, std::uint32_t y);
    };
} // namespace gui

M module-apps/application-special-input/data/SpecialCharactersTableStyle.hpp => module-apps/application-special-input/data/SpecialCharactersTableStyle.hpp +5 -5
@@ 6,7 6,7 @@
#include <Style.hpp>
#include <utf8/UTF8.hpp>
#include <functional>
#include <vector>
#include <array>

namespace specialInputStyle
{


@@ 16,16 16,16 @@ namespace specialInputStyle
        SpecialCharacters
    };

    const inline char32_t symbol_for_newline         = U'␤';
    const inline std::vector<char32_t> special_chars = {
    constexpr inline auto symbol_for_newline  = U'␤';
    constexpr inline std::array special_chars = {
        U'.', U',', U'\'', U'?', U'!', U'"', U'-', U'(', U')', U'@', U'/', U':', U'_', U';', symbol_for_newline,
        U'+', U'&', U'%',  U'*', U'<', U'>', U'=', U'£', U'€', U'$', U'[', U']', U'{', U'}', U'\'',
        U'^', U'~', U'`',  U'į', U'§', U'…', U'#', U'|', U'÷', U'·', U'°', U'¿', U'¡', U'ą', U'à',
        U'á', U'ä', U'â',  U'ć', U'ç', U'ę', U'é', U'è', U'ê', U'ë', U'î', U'ï', U'í', U'ł', U'ń',
        U'ñ', U'ó', U'ô',  U'ö', U'ś', U'û', U'ú', U'ù', U'ü', U'ÿ', U'ż', U'ź', U'ß'};

    const inline std::vector<char32_t> emojis = {U'😁', U'😂', U'😃', U'😄', U'😅', U'😆', U'😉', U'😊', U'😋', U'😌', U'😍',
                                                 U'😏', U'😒', U'😓', U'😔', U'😖', U'😘', U'😚', U'😜', U'😝', U'😼'};
    constexpr inline std::array emojis = {U'😁', U'😂', U'😃', U'😄', U'😅', U'😆', U'😉', U'😊', U'😋', U'😌', U'😍',
                                          U'😏', U'😒', U'😓', U'😔', U'😖', U'😘', U'😚', U'😜', U'😝', U'😼'};

    namespace specialInputListView
    {

M module-apps/application-special-input/models/SpecialInputModel.cpp => module-apps/application-special-input/models/SpecialInputModel.cpp +7 -7
@@ 37,7 37,7 @@ auto SpecialInputModel::getMaxGridElements() const -> ssize_t
            specialInputStyle::specialCharacterTableWidget::char_grid_h);
}

void SpecialInputModel::buildGrids(std::vector<char32_t> elements)
void SpecialInputModel::buildGrid(const std::vector<char32_t> &elements)
{
    auto add_start = elements.begin();
    while (add_start != elements.end()) {


@@ 58,20 58,20 @@ void SpecialInputModel::buildGrids(std::vector<char32_t> elements)

void SpecialInputModel::createData(specialInputStyle::CharactersType type)
{
    auto create = [&](auto &vector) {
        buildGrids(vector);
        for (auto &dataitem : internalData) {
            dataitem->deleteByList = false;
    auto create = [&](const auto &vector) {
        buildGrid(vector);
        for (auto &item : internalData) {
            item->deleteByList = false;
        }
        list->rebuildList();
    };

    switch (type) {
    case specialInputStyle::CharactersType::SpecialCharacters:
        create(specialInputStyle::special_chars);
        create(std::vector<char32_t>{specialInputStyle::special_chars.begin(), specialInputStyle::special_chars.end()});
        break;
    case specialInputStyle::CharactersType::Emoji:
        create(specialInputStyle::emojis);
        create(std::vector<char32_t>{specialInputStyle::emojis.begin(), specialInputStyle::emojis.end()});
        break;
    }
}

M module-apps/application-special-input/models/SpecialInputModel.hpp => module-apps/application-special-input/models/SpecialInputModel.hpp +1 -1
@@ 14,7 14,7 @@ class SpecialInputModel : public app::InternalModel<gui::ListItem *>, public gui
  private:
    app::Application *application = nullptr;
    [[nodiscard]] auto getMaxGridElements() const -> ssize_t;
    void buildGrids(const std::vector<char32_t> elements);
    void buildGrid(const std::vector<char32_t> &elements);

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

M module-audio/Audio/AudioCommon.hpp => module-audio/Audio/AudioCommon.hpp +0 -16
@@ 51,15 51,6 @@ namespace audio
        Last = TextMessageRingtone,
    };

    const static std::map<PlaybackType, uint8_t> PlaybackTypePriority = {
        {PlaybackType::CallRingtone, 2},
        {PlaybackType::TextMessageRingtone, 3},
        {PlaybackType::Notifications, 3},
        {PlaybackType::Multimedia, 4},
        {PlaybackType::KeypadSound, 5},
        {PlaybackType::None, static_cast<uint8_t>(PlaybackType::Last)},
    };

    [[nodiscard]] const std::string str(const PlaybackType &playbackType) noexcept;

    [[nodiscard]] const std::string str(const Setting &setting) noexcept;


@@ 290,10 281,3 @@ namespace audio
    const std::string str(RetCode retcode);
    [[nodiscard]] auto GetVolumeText(const audio::Volume &volume) -> const std::string;
} // namespace audio

namespace audio::notifications
{
    const std::vector<audio::PlaybackType> typesToMute = {audio::PlaybackType::Notifications,
                                                          audio::PlaybackType::CallRingtone,
                                                          audio::PlaybackType::TextMessageRingtone};
} // namespace audio::notifications

M module-audio/Audio/AudioMux.cpp => module-audio/Audio/AudioMux.cpp +12 -0
@@ 6,6 6,18 @@

namespace audio
{
    namespace
    {
        const std::map<PlaybackType, uint8_t> PlaybackTypePriority = {
            {PlaybackType::CallRingtone, 2},
            {PlaybackType::TextMessageRingtone, 3},
            {PlaybackType::Notifications, 3},
            {PlaybackType::Multimedia, 4},
            {PlaybackType::KeypadSound, 5},
            {PlaybackType::None, static_cast<uint8_t>(PlaybackType::Last)},
        };
    } // namespace

    AudioMux::AudioMux(audio::AsyncCallback asyncClbk, audio::DbCallback dbClbk, size_t audioInputsCount)
        : audioInputs(audioInputsInternal)
    {

M module-bsp/board/rt1051/bsp/magnetometer/ALS31300.hpp => module-bsp/board/rt1051/bsp/magnetometer/ALS31300.hpp +2 -2
@@ 3,9 3,9 @@

#pragma once

#include <array>
#include <cstdint>
#include <cstring>
#include <set>
#include <chrono>

// ALS31300 magnetometer driver


@@ 167,7 167,7 @@ namespace drivers::als31300
    // --------

    /// give eeprom registers time to complete WRITE
    const std::set<uint8_t> EEPROM_REGS = {CUSTOMER_ACCESS_REG, CONF_REG, INT_REG};
    constexpr inline std::array<std::uint8_t, 3> EEPROM_REGS = {CONF_REG, INT_REG, CUSTOMER_ACCESS_REG};

    using std::chrono_literals::operator""ms;
    constexpr auto EEPROM_REG_WRITE_DELAY_MS = 60ms; // docs say 50ms, +10ms for good measure

M module-bsp/board/rt1051/bsp/magnetometer/magnetometer.cpp => module-bsp/board/rt1051/bsp/magnetometer/magnetometer.cpp +10 -1
@@ 34,6 34,15 @@ namespace bsp
{
    namespace magnetometer
    {
        namespace
        {
            bool isTimeToCompleteWriteDefinedForRegistry(std::uint8_t address)
            {
                const auto it = std::find(als31300::EEPROM_REGS.begin(), als31300::EEPROM_REGS.end(), address);
                return it != als31300::EEPROM_REGS.end();
            }
        } // namespace

        std::shared_ptr<DriverGPIO> gpio;

        bsp::KeyCodes current_parsed = bsp::KeyCodes::Undefined;


@@ 75,7 84,7 @@ namespace bsp
            i2c_buf.whole_reg = whole_reg;
#endif
            auto wrote = i2c->Write(addr, i2c_buf.buf, sizeof(als31300::whole_reg_t)) == sizeof(als31300::whole_reg_t);
            if (als31300::EEPROM_REGS.count(reg_addr) == 1) {
            if (isTimeToCompleteWriteDefinedForRegistry(reg_addr)) {
                vTaskDelay(pdMS_TO_TICKS(als31300::EEPROM_REG_WRITE_DELAY_MS.count()));
            }
            return wrote;

A module-bsp/board/rt1051/common/chip.cpp => module-bsp/board/rt1051/common/chip.cpp +54 -0
@@ 0,0 1,54 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "chip.hpp"

#include <log/log.hpp>

#include <map>
#include <string>

namespace
{
    const std::map<std::uint32_t, std::string> bootReasonDef = {
        {SRC_SRSR_IPP_RESET_B_SHIFT, "ipp_reset_b pin (Power-up sequence)"},
        {SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT, "CPU lockup or software setting of SYSRESETREQ"},
        {SRC_SRSR_CSU_RESET_B_SHIFT, "csu_reset_b input"},
        {SRC_SRSR_IPP_USER_RESET_B_SHIFT, "ipp_user_reset_b qualified reset"},
        {SRC_SRSR_WDOG_RST_B_SHIFT, "IC Watchdog Time-out reset"},
        {SRC_SRSR_JTAG_RST_B_SHIFT, "HIGH - Z JTAG reset"},
        {SRC_SRSR_JTAG_SW_RST_SHIFT, "JTAG software reset"},
        {SRC_SRSR_WDOG3_RST_B_SHIFT, "IC Watchdog3 Time-out reset"},
        {SRC_SRSR_TEMPSENSE_RST_B_SHIFT, "Tamper Sensor software reset"}};
} // namespace

void clearAndPrintBootReason()
{
    // get boot reason
    std::uint32_t SRSR_val = SRC_GetResetStatusFlags(SRC);

    LOG_INFO("Boot reason: %" PRIu32, SRSR_val);
    if (SRSR_val & (1UL << SRC_SRSR_IPP_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_IPP_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT)) {
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT).c_str());
        LOG_INFO("\tGPR_5 %" PRIu32, SRC_GetGeneralPurposeRegister(SRC, 5));
    }
    if (SRSR_val & (1UL << SRC_SRSR_CSU_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_CSU_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_IPP_USER_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_IPP_USER_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_WDOG_RST_B_SHIFT))
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_WDOG_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_JTAG_RST_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_JTAG_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_JTAG_SW_RST_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_JTAG_SW_RST_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_WDOG3_RST_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_WDOG3_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_TEMPSENSE_RST_B_SHIFT))
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_TEMPSENSE_RST_B_SHIFT).c_str());

    // clear all set bits
    SRC_ClearResetStatusFlags(SRC, SRSR_val);
}

M module-bsp/board/rt1051/common/chip.hpp => module-bsp/board/rt1051/common/chip.hpp +2 -44
@@ 3,6 3,7 @@

#pragma once

#include <cstdint>
extern "C"
{
#include "cmsis/cmsis_gcc.h"


@@ 10,48 11,5 @@ extern "C"
#include "fsl_drivers/fsl_src.h"
#include "macros.h"
}
#include <log/log.hpp>
#include <map>
#include <string>

static const std::map<uint32_t, std::string> bootReasonDef = {
    {SRC_SRSR_IPP_RESET_B_SHIFT, "ipp_reset_b pin (Power-up sequence)"},
    {SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT, "CPU lockup or software setting of SYSRESETREQ"},
    {SRC_SRSR_CSU_RESET_B_SHIFT, "csu_reset_b input"},
    {SRC_SRSR_IPP_USER_RESET_B_SHIFT, "ipp_user_reset_b qualified reset"},
    {SRC_SRSR_WDOG_RST_B_SHIFT, "IC Watchdog Time-out reset"},
    {SRC_SRSR_JTAG_RST_B_SHIFT, "HIGH - Z JTAG reset"},
    {SRC_SRSR_JTAG_SW_RST_SHIFT, "JTAG software reset"},
    {SRC_SRSR_WDOG3_RST_B_SHIFT, "IC Watchdog3 Time-out reset"},
    {SRC_SRSR_TEMPSENSE_RST_B_SHIFT, "Tamper Sensor software reset"}};

static inline void clearAndPrintBootReason()
{
    // get boot reason
    uint32_t SRSR_val = SRC_GetResetStatusFlags(SRC);

    LOG_INFO("Boot reason: %" PRIu32, SRSR_val);
    if (SRSR_val & (1UL << SRC_SRSR_IPP_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_IPP_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT)) {
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_LOCKUP_SYSRESETREQ_SHIFT).c_str());
        LOG_INFO("\tGPR_5 %" PRIu32, SRC_GetGeneralPurposeRegister(SRC, 5));
    }
    if (SRSR_val & (1UL << SRC_SRSR_CSU_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_CSU_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_IPP_USER_RESET_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_IPP_USER_RESET_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_WDOG_RST_B_SHIFT))
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_WDOG_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_JTAG_RST_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_JTAG_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_JTAG_SW_RST_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_JTAG_SW_RST_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_WDOG3_RST_B_SHIFT))
        LOG_INFO("\t*%s", bootReasonDef.at(SRC_SRSR_WDOG3_RST_B_SHIFT).c_str());
    if (SRSR_val & (1UL << SRC_SRSR_TEMPSENSE_RST_B_SHIFT))
        LOG_WARN("\t*%s", bootReasonDef.at(SRC_SRSR_TEMPSENSE_RST_B_SHIFT).c_str());

    // clear all set bits
    SRC_ClearResetStatusFlags(SRC, SRSR_val);
}
void clearAndPrintBootReason();

M module-bsp/targets/Target_RT1051.cmake => module-bsp/targets/Target_RT1051.cmake +1 -0
@@ 31,6 31,7 @@ set(BOARD_SOURCES ${BOARD_SOURCES}
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_wdog.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/irq/irq_gpio.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/board.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/chip.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/clock_config.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/pin_mux.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/startup_mimxrt1052.cpp"

M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp +2 -1
@@ 14,6 14,7 @@
#include "MessageHandler.hpp" // for MessageHandler
#include "json/json11.hpp"    // for Json, Json::object
#include "vfs.hpp"            // for vfs, os_backup
#include "vfs_paths.hpp"

static bool backupReady = false;



@@ 59,7 60,7 @@ auto BackupEndpoint::request(Context &context) -> sys::ReturnCodes
auto BackupEndpoint::upload(Context &context) -> sys::ReturnCodes
{
    if (context.getBody()[json::backupUpload] == true) {
        if (vfs.fileExists(purefs::dir::os_backup.c_str())) {
        if (const auto backupOSPath = purefs::dir::getBackupOSPath(); vfs.fileExists(backupOSPath.c_str())) {
            context.setResponseBody(json11::Json::object({{json::backupUpload, true}}));
        }
        else {

M module-services/service-desktop/endpoints/backup/BackupRestore.cpp => module-services/service-desktop/endpoints/backup/BackupRestore.cpp +21 -18
@@ 11,6 11,7 @@
#include <vector>     // for vector

#include "vfs.hpp" // for vfs, vfs::DirectoryEntry, os_backup, tar_buf, PATH_BACKUP, vfs::FILE, user_disk
#include "vfs_paths.hpp"
#include "microtar/src/microtar.hpp" // for mtar_close, mtar_header_t, MTAR_ESUCCESS, mtar_strerror, mtar_open, mtar_finalize, mtar_next, mtar_read_data, mtar_read_header, mtar_write_data, mtar_write_file_header, mtar_t, MTAR_TREG
#include "api/DBServiceAPI.hpp"      // for DBServiceAPI
#include "service-db/includes/DBServiceName.hpp" // for db


@@ 81,12 82,12 @@ void BackupRestore::RestoreUserFiles(sys::Service *ownerService)
bool BackupRestore::RemoveBackupDir()
{
    /* prepare directories */
    if (vfs.isDir(purefs::dir::os_backup.c_str())) {
        LOG_INFO("RemoveBackupDir: removing backup directory %s...", purefs::dir::os_backup.c_str());
    if (const auto backupOSPath = purefs::dir::getBackupOSPath(); vfs.isDir(backupOSPath.c_str())) {
        LOG_INFO("RemoveBackupDir: removing backup directory %s...", backupOSPath.c_str());

        if (vfs.deltree(purefs::dir::os_backup.c_str()) != 0) {
        if (vfs.deltree(backupOSPath.c_str()) != 0) {
            LOG_ERROR("RemoveBackupDir: removing backup directory %s failed, error: %s.",
                      purefs::dir::os_backup.c_str(),
                      backupOSPath.c_str(),
                      vfs.lastErrnoToStr().c_str());
            return false;
        }


@@ 97,12 98,13 @@ bool BackupRestore::RemoveBackupDir()

bool BackupRestore::CreateBackupDir()
{
    LOG_INFO("CreateBackupDir: creating backup directory %s...", purefs::dir::os_backup.c_str());
    const auto backupOSPath = purefs::dir::getBackupOSPath();
    LOG_INFO("CreateBackupDir: creating backup directory %s...", backupOSPath.c_str());

    if (vfs.isDir(purefs::dir::os_backup.c_str()) == false) {
        if (vfs.mkdir(purefs::dir::os_backup.c_str()) != 0) {
    if (vfs.isDir(backupOSPath.c_str()) == false) {
        if (vfs.mkdir(backupOSPath.c_str()) != 0) {
            LOG_ERROR("CreateBackupDir: creating backup directory %s failed, error: %s.",
                      purefs::dir::os_backup.c_str(),
                      backupOSPath.c_str(),
                      vfs.lastErrnoToStr().c_str());
            return false;
        }


@@ 116,21 118,21 @@ bool BackupRestore::PackUserFiles()
    std::string backupPathDB = PATH_BACKUP;
    backupPathDB += "/";

    std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(purefs::dir::os_backup.c_str(), "", true);
    const auto backupOSPath                  = purefs::dir::getBackupOSPath();
    std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(backupOSPath.c_str(), "", true);

    if (dirlist.size() <= empty_dirlist_size) {
        /* vfs.listdir also lists two extra directories ".." and "..." by default, they shall be ignored */
        LOG_ERROR("PackUserFiles: backup dir %s is empty, nothing to backup, quitting...",
                  purefs::dir::os_backup.c_str());
        LOG_ERROR("PackUserFiles: backup dir %s is empty, nothing to backup, quitting...", backupOSPath.c_str());
        BackupRestore::RemoveBackupDir();
        return false;
    }

    LOG_INFO("PackUserFiles: backup dir %s listed with %lu files.",
             purefs::dir::os_backup.c_str(),
             backupOSPath.c_str(),
             dirlist.size() - empty_dirlist_size);

    std::string tarFilePath = purefs::dir::os_backup;
    std::string tarFilePath = backupOSPath;
    tarFilePath += "/";
    tarFilePath += backup_file_name;



@@ 246,7 248,7 @@ bool BackupRestore::PackUserFiles()

bool BackupRestore::UnpackBackupFile()
{
    std::string tarFilePath = purefs::dir::os_backup;
    std::string tarFilePath = purefs::dir::getBackupOSPath();
    tarFilePath += "/";
    tarFilePath += backup_file_name;



@@ 273,7 275,7 @@ bool BackupRestore::UnpackBackupFile()
        if ((tarHeader.type == MTAR_TREG) && (ret == MTAR_ESUCCESS)) {
            LOG_INFO("UnpackBackupFile: extracting file %s...", tarHeader.name);

            std::string restoreFilePath = purefs::dir::os_backup;
            std::string restoreFilePath = purefs::dir::getBackupOSPath();
            restoreFilePath += "/";
            restoreFilePath += tarHeader.name;
            vfs::FILE *file = vfs.fopen(restoreFilePath.c_str(), "w");


@@ 334,7 336,8 @@ bool BackupRestore::UnpackBackupFile()
bool BackupRestore::ReplaceUserFiles()
{
    /* replace existing files that have respective backup files existing */
    std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(purefs::dir::os_backup.c_str());
    const auto backupOSPath                  = purefs::dir::getBackupOSPath();
    std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(backupOSPath.c_str());

    if (dirlist.size() <= empty_dirlist_size) {
        LOG_INFO("ReplaceUserFiles: dir emtpy, nothing to restore, quitting...");


@@ 343,10 346,10 @@ bool BackupRestore::ReplaceUserFiles()

    LOG_INFO("ReplaceUserFiles: dir listed with %lu files", dirlist.size() - empty_dirlist_size);

    std::string userFilePath = purefs::dir::user_disk;
    std::string userFilePath = purefs::dir::getUserDiskPath();
    userFilePath += "/";

    std::string backupFilePath = purefs::dir::os_backup;
    std::string backupFilePath = purefs::dir::getBackupOSPath();
    backupFilePath += "/";

    for (auto &direntry : dirlist) {

M module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp => module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp +7 -4
@@ 9,6 9,7 @@
#include <vector>     // for vector

#include "vfs.hpp" // for vfs, vfs::DirectoryEntry, copy_buf, os_factory, vfs::FILE, eMMC_disk, vfs::FileAttributes, vfs::FileAttributes::Directory, PATH_FACTORY
#include "vfs_paths.hpp"
#include "service-db/includes/DBServiceName.hpp" // for db
#include "SystemManager/SystemManager.hpp"       // for SystemManager
#include "log/log.hpp"                           // for LOG_ERROR, LOG_INFO


@@ 39,11 40,12 @@ namespace FactoryReset

        recurseDepth = 0;

        std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(purefs::dir::os_factory.c_str(), "");
        const auto factoryOSPath                 = purefs::dir::getFactoryOSPath();
        std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(factoryOSPath.c_str(), "");

        if (dirlist.size() <= empty_dirlist_size) {
            LOG_ERROR("FactoryReset: restoring factory state aborted");
            LOG_ERROR("FactoryReset: directory %s seems empty.", purefs::dir::os_factory.c_str());
            LOG_ERROR("FactoryReset: directory %s seems empty.", factoryOSPath.c_str());
            return false;
        }



@@ 58,7 60,7 @@ namespace FactoryReset
            return false;
        }

        if (CopyDirContent(purefs::dir::os_factory, purefs::dir::eMMC_disk) != true) {
        if (CopyDirContent(factoryOSPath, purefs::dir::eMMC_disk) != true) {
            LOG_ERROR("FactoryReset: restoring factory state aborted");
            return false;
        }


@@ 111,6 113,7 @@ namespace FactoryReset
            return false;
        }

        const auto factoryOSPath                 = purefs::dir::getFactoryOSPath();
        std::vector<vfs::DirectoryEntry> dirlist = vfs.listdir(sourcedir.c_str(), "");

        for (auto &direntry : dirlist) {


@@ 135,7 138,7 @@ namespace FactoryReset
            }

            if (direntry.attributes == vfs::FileAttributes::Directory) {
                if (targetpath.compare(purefs::dir::os_factory.c_str()) == 0) {
                if (targetpath.compare(factoryOSPath.c_str()) == 0) {
                    continue;
                }


M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp => module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp +4 -2
@@ 14,6 14,7 @@
#include "UpdateMuditaOS.hpp"  // for update
#include "json/json11.hpp"     // for Json, Json::object
#include "vfs.hpp"             // for vfs, os_updates
#include "vfs_paths.hpp"

auto UpdateEndpoint::handle(Context &context) -> void
{


@@ 32,7 33,7 @@ auto UpdateEndpoint::handle(Context &context) -> void
auto UpdateEndpoint::run(Context &context) -> sys::ReturnCodes
{
    std::string fileName = context.getBody()["fileName"].string_value();
    auto path            = purefs::dir::os_updates / fileName;
    auto path            = purefs::dir::getUpdatesOSPath() / fileName;
    auto fileExists      = vfs.fileExists(path.c_str());
    if (fileExists) {
        context.setResponseBody(json11::Json::object({{parserFSM::json::updateReady, true}}));


@@ 52,7 53,8 @@ auto UpdateEndpoint::run(Context &context) -> sys::ReturnCodes

auto UpdateEndpoint::getUpdates(Context &context) -> sys::ReturnCodes
{
    json11::Json fileList = vfs.listdir(purefs::dir::os_updates.c_str(), updateos::extension::update, true);
    const auto updatesOSPath = purefs::dir::getUpdatesOSPath();
    json11::Json fileList    = vfs.listdir(updatesOSPath.c_str(), updateos::extension::update, true);

    context.setResponseBody(json11::Json::object{{parserFSM::json::updateFileList, fileList}});


M module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp => module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp +44 -38
@@ 21,6 21,7 @@
#include "log/log.hpp"                     // for LOG_INFO, LOG_DEBUG, LOG_ERROR
#include "microtar/src/microtar.hpp" // for mtar_header_t, mtar_close, mtar_open, mtar_read_data, MTAR_ESUCCESS, mtar_find, mtar_next, mtar_read_header, mtar_t, MTAR_ENOTFOUND, MTAR_ENULLRECORD, MTAR_EOPENFAIL, MTAR_TDIR
#include "vfs.hpp" // for vfs, tar_buf, os_previous, os_updates, os_current, tmp, vfs::FILE, crc_char_size, vfs::DirectoryEntry, os_version, user_disk, version_string, boot_json, crc32, crc_buf, crc_radix, eMMC_disk
#include "vfs_paths.hpp"

FileInfo::FileInfo(mtar_header_t &h, unsigned long crc32) : fileSize(h.size), fileCRC32(crc32)
{


@@ 46,7 47,7 @@ UpdateMuditaOS::UpdateMuditaOS(ServiceDesktop *ownerService) : owner(ownerServic

updateos::UpdateError UpdateMuditaOS::setUpdateFile(fs::path updateFileToUse)
{
    updateFile = purefs::dir::os_updates / updateFileToUse;
    updateFile = purefs::dir::getUpdatesOSPath() / updateFileToUse;
    if (vfs.fileExists(updateFile.c_str())) {
        versioInformation = UpdateMuditaOS::getVersionInfoFromFile(updateFile);
        if (mtar_open(&updateTar, updateFile.c_str(), "r") == MTAR_ESUCCESS) {


@@ 250,47 251,50 @@ updateos::UpdateError UpdateMuditaOS::prepareRoot()
    int ret;
    // basic needed dirs

    informDebug("prepareRoot mkdir: %s", purefs::dir::os_previous.c_str());
    vfs.mkdir(purefs::dir::os_previous.c_str());
    informDebug("prepareRoot mkdir: %s", purefs::dir::os_current.c_str());
    vfs.mkdir(purefs::dir::os_current.c_str());
    informDebug("prepareRoot mkdir: %s", purefs::dir::user_disk.c_str());
    vfs.mkdir(purefs::dir::user_disk.c_str());
    const auto previousOSPath = purefs::dir::getPreviousOSPath();
    const auto currentOSPath  = purefs::dir::getCurrentOSPath();
    const auto userDiskPath   = purefs::dir::getUserDiskPath();

    informDebug("prepareRoot mkdir: %s", previousOSPath.c_str());
    vfs.mkdir(previousOSPath.c_str());
    informDebug("prepareRoot mkdir: %s", currentOSPath.c_str());
    vfs.mkdir(currentOSPath.c_str());
    informDebug("prepareRoot mkdir: %s", userDiskPath.c_str());
    vfs.mkdir(userDiskPath.c_str());

    // remove the previous OS version from partition
    informDebug("prepareRoot deltree: %s", purefs::dir::os_previous.c_str());
    ret = vfs.deltree(purefs::dir::os_previous.c_str());
    informDebug("prepareRoot deltree: %s", previousOSPath.c_str());
    ret = vfs.deltree(previousOSPath.c_str());

    if (ret != 0) {
        informError("prepareRoot ff_deltree on %s caused an error %s",
                    purefs::dir::os_previous.c_str(),
                    vfs.lastErrnoToStr().c_str());
        informError(
            "prepareRoot ff_deltree on %s caused an error %s", previousOSPath.c_str(), vfs.lastErrnoToStr().c_str());
    }

    if (vfs.isDir(purefs::dir::os_previous.c_str())) {
        informError("prepareRoot %s still exists, we can't continue", purefs::dir::os_previous.c_str());
    if (vfs.isDir(previousOSPath.c_str())) {
        informError("prepareRoot %s still exists, we can't continue", previousOSPath.c_str());
        return updateos::UpdateError::CantDeletePreviousOS;
    }
    // rename the current OS to previous on partition
    informDebug("prepareRoot rename: %s->%s", purefs::dir::os_current.c_str(), purefs::dir::os_previous.c_str());
    ret = vfs.rename(purefs::dir::os_current.c_str(), purefs::dir::os_previous.c_str());
    informDebug("prepareRoot rename: %s->%s", currentOSPath.c_str(), previousOSPath.c_str());
    ret = vfs.rename(currentOSPath.c_str(), previousOSPath.c_str());

    if (ret != 0) {
        informError("prepareRoot can't rename %s -> %s error %s",
                    purefs::dir::os_current.c_str(),
                    purefs::dir::os_previous.c_str(),
                    currentOSPath.c_str(),
                    previousOSPath.c_str(),
                    vfs.lastErrnoToStr().c_str());
        return updateos::UpdateError::CantRenameCurrentToPrevious;
    }

    // rename the temp directory to current (extracted update)
    informDebug("prepareRoot rename: %s->%s", updateTempDirectory.c_str(), purefs::dir::os_current.c_str());
    ret = vfs.rename(updateTempDirectory.c_str(), purefs::dir::os_current.c_str());
    informDebug("prepareRoot rename: %s->%s", updateTempDirectory.c_str(), currentOSPath.c_str());
    ret = vfs.rename(updateTempDirectory.c_str(), currentOSPath.c_str());

    if (ret != 0) {
        informError("prepareRoot can't rename %s -> %s error %s",
                    updateTempDirectory.c_str(),
                    purefs::dir::os_current.c_str(),
                    currentOSPath.c_str(),
                    vfs.lastErrnoToStr().c_str());
        return updateos::UpdateError::CantRenameTempToCurrent;
    }


@@ 304,7 308,7 @@ updateos::UpdateError UpdateMuditaOS::prepareRoot()
updateos::UpdateError UpdateMuditaOS::updateBootJSON()
{
    unsigned long bootJSONAbsoulteCRC = 0;
    fs::path bootJSONAbsoulte         = purefs::dir::eMMC_disk / purefs::file::boot_json;
    fs::path bootJSONAbsoulte         = purefs::createPath(purefs::dir::eMMC_disk, purefs::file::boot_json);
    informDebug("updateBootJSON %s", bootJSONAbsoulte.c_str());

    vfs::FILE *fp = vfs.fopen(bootJSONAbsoulte.c_str(), "r");


@@ 416,35 420,37 @@ updateos::UpdateError UpdateMuditaOS::prepareTempDirForUpdate()
{
    status = updateos::UpdateState::CreatingDirectories;

    updateTempDirectory = purefs::dir::tmp / vfs::generateRandomId(updateos::prefix_len);
    updateTempDirectory = purefs::dir::getTemporaryPath() / vfs::generateRandomId(updateos::prefix_len);

    informDebug("Temp dir for update %s", updateTempDirectory.c_str());

    if (vfs.isDir(purefs::dir::os_updates.c_str()) == false) {
        if (vfs.mkdir(purefs::dir::os_updates.c_str()) != 0) {
            informError("%s can't create it %s", purefs::dir::os_updates.c_str(), vfs.lastErrnoToStr().c_str());
    const auto updatesOSPath = purefs::dir::getUpdatesOSPath();
    if (vfs.isDir(updatesOSPath.c_str()) == false) {
        if (vfs.mkdir(updatesOSPath.c_str()) != 0) {
            informError("%s can't create it %s", updatesOSPath.c_str(), vfs.lastErrnoToStr().c_str());
            return updateos::UpdateError::CantCreateUpdatesDir;
        }
        else {
            informDebug("prepareTempDirForUpdate %s created", purefs::dir::os_updates.c_str());
            informDebug("prepareTempDirForUpdate %s created", updatesOSPath.c_str());
        }
    }
    else {
        informDebug("prepareTempDirForUpdate %s exists", purefs::dir::os_updates.c_str());
        informDebug("prepareTempDirForUpdate %s exists", updatesOSPath.c_str());
    }

    if (vfs.isDir(purefs::dir::tmp.c_str()) == false) {
        informDebug("prepareTempDirForUpdate %s is not a directory", purefs::dir::tmp.c_str());
        if (vfs.mkdir(purefs::dir::tmp.c_str()) != 0) {
            informError("%s can't create it %s", purefs::dir::tmp.c_str(), vfs.lastErrnoToStr().c_str());
    const auto tmpPath = purefs::dir::getTemporaryPath();
    if (vfs.isDir(tmpPath.c_str()) == false) {
        informDebug("prepareTempDirForUpdate %s is not a directory", tmpPath.c_str());
        if (vfs.mkdir(tmpPath.c_str()) != 0) {
            informError("%s can't create it %s", tmpPath.c_str(), vfs.lastErrnoToStr().c_str());
            return updateos::UpdateError::CantCreateTempDir;
        }
        else {
            informDebug("prepareTempDirForUpdate %s created", purefs::dir::tmp.c_str());
            informDebug("prepareTempDirForUpdate %s created", tmpPath.c_str());
        }
    }
    else {
        informDebug("prepareTempDirForUpdate %s exists", purefs::dir::tmp.c_str());
        informDebug("prepareTempDirForUpdate %s exists", tmpPath.c_str());
    }

    if (vfs.isDir(updateTempDirectory.c_str())) {


@@ 576,18 582,18 @@ bool UpdateMuditaOS::isUpgradeToCurrent(const std::string &versionToCompare)

const fs::path UpdateMuditaOS::checkForUpdate()
{
    std::vector<vfs::DirectoryEntry> fileList =
        vfs.listdir(purefs::dir::os_updates.c_str(), updateos::extension::update, true);
    const auto updatesOSPath                  = purefs::dir::getUpdatesOSPath();
    std::vector<vfs::DirectoryEntry> fileList = vfs.listdir(updatesOSPath.c_str(), updateos::extension::update, true);
    for (auto &file : fileList) {

        json11::Json versionInfo = UpdateMuditaOS::getVersionInfoFromFile(purefs::dir::os_updates / file.fileName);
        json11::Json versionInfo = UpdateMuditaOS::getVersionInfoFromFile(updatesOSPath / file.fileName);
        if (versionInfo.is_null())
            continue;

        if (versionInfo[purefs::json::os_version][purefs::json::version_string].is_string()) {
            if (UpdateMuditaOS::isUpgradeToCurrent(
                    versionInfo[purefs::json::os_version][purefs::json::version_string].string_value())) {
                return purefs::dir::os_updates / file.fileName;
                return updatesOSPath / file.fileName;
            }
        }
    }

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +1 -1
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>          // for vfs, eMMC_disk
#include <vfs_paths.hpp>    // for eMMC_disk
#include <catch2/catch.hpp> // for AssertionHandler, operator""_catch_sr, SourceLineInfo, StringRef, REQUIRE, Section, SECTION, SectionInfo, TEST_CASE
#include <memory>           // for allocator, unique_ptr, make_unique, operator==, allocator_traits<>::value_type
#include <filesystem>       // for path

M module-services/service-fileindexer/StartupIndexer.cpp => module-services/service-fileindexer/StartupIndexer.cpp +3 -2
@@ 6,6 6,7 @@
#include <filesystem>
#include <ff_stdio_listdir_recursive.h>
#include <vfs.hpp>
#include <vfs_paths.hpp>
#include <Service/Bus.hpp>
#include "Constants.hpp"



@@ 21,7 22,7 @@ namespace service::detail
            {".txt", mimeType::text}, {".wav", mimeType::audio}, {".mp3", mimeType::audio}, {".flac", mimeType::audio}};

        // List of initial dirs for scan
        const std::vector<std::string> start_dirs{purefs::dir::user_disk, purefs::dir::os_current};
        const std::vector<std::string> start_dirs{purefs::dir::getUserDiskPath(), purefs::dir::getCurrentOSPath()};
    } // namespace

    auto StartupIndexer::getFileType(std::string_view path) -> mimeType


@@ 71,4 72,4 @@ namespace service::detail
            mIdxTimer->start();
        }
    }
} // namespace service::detail
\ No newline at end of file
} // namespace service::detail

M module-utils/time/time_conversion.cpp => module-utils/time/time_conversion.cpp +261 -237
@@ 19,287 19,311 @@
#include "time_locale.hpp"
#include <Utils.hpp>

namespace utils
namespace utils::time
{
    namespace time
    namespace
    {
        constexpr auto verboseConversion = false; // debug switch

        Locale tlocale;
        static int msTimeGmtOff = 4 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;
        constexpr auto abbrev_len = 3U;

        UTF8 Localer::get_replacement(Replacements val, const struct tm &timeinfo)
        {
            UTF8 retval = "";
            switch (val) {
            case DayLong:
                retval = Locale::get_day(Locale::Day(timeinfo.tm_wday));
                break;
            case DayAbbrev:
                retval = Locale::get_day(Locale::Day(timeinfo.tm_wday)).substr(0, abbrev_len);
                break;
            case MonthLong:
                retval = Locale::get_month(Locale::Month(timeinfo.tm_mon));
                break;
            case MonthAbbrev:
                retval = Locale::get_month(Locale::Month(timeinfo.tm_mon)).substr(0, abbrev_len);
                break;
            case Timezone:
                break;
            }
            return retval;
        }
        /// order matters, it's used in replace_locale with enum Replacements
        const std::vector<std::string> specifiers_replacement = {"%a",  // day abbrew
                                                                 "%A",  // day long
                                                                 "%b",  // month abbrew
                                                                 "%B",  // month long
                                                                 "%Z"}; // timezone

        Timestamp::Timestamp()
        struct Format
        {
            auto err     = bsp::rtc_GetCurrentTimestamp(&time);
            auto curTime = time + utils::time::Time::getTimeZoneOffset();
            if (err) {
                LOG_ERROR("rtc_GetCurrentTimestamp failure!");
            }
            timeinfo = *localtime(&curTime);
            const std::string lowFormat;  /// format used if duration is below 1 hour
            const std::string highFormat; /// format used if duration exceeds 1 hour
        };
        constexpr auto durationFormatH0M0S = "duration_hour_0min_0sec";
        constexpr auto durationFormat0M0S  = "duration_0min_0sec";
        constexpr auto durationFormat0N0S  = "duration_0hmin_0sec";
        constexpr auto durationFormatM0S   = "duration_min_0sec";

        using FormatMap           = std::map<const Duration::DisplayedFormat, const Format>;
        const FormatMap formatMap = {
            {Duration::DisplayedFormat::Fixed0M0S, {durationFormat0N0S, durationFormat0N0S}},
            {Duration::DisplayedFormat::FixedH0M0S, {durationFormatH0M0S, durationFormatH0M0S}},
            {Duration::DisplayedFormat::AutoM, {durationFormatM0S, durationFormatH0M0S}},
            {Duration::DisplayedFormat::Auto0M, {durationFormat0M0S, durationFormatH0M0S}}};
    } // namespace

    Locale tlocale;
    static int msTimeGmtOff = 4 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;

    UTF8 Localer::get_replacement(Replacements val, const struct tm &timeinfo)
    {
        UTF8 retval = "";
        switch (val) {
        case DayLong:
            retval = Locale::get_day(Locale::Day(timeinfo.tm_wday));
            break;
        case DayAbbrev:
            retval = Locale::get_day(Locale::Day(timeinfo.tm_wday)).substr(0, abbrev_len);
            break;
        case MonthLong:
            retval = Locale::get_month(Locale::Month(timeinfo.tm_mon));
            break;
        case MonthAbbrev:
            retval = Locale::get_month(Locale::Month(timeinfo.tm_mon)).substr(0, abbrev_len);
            break;
        case Timezone:
            break;
        }
        return retval;
    }

        void Timestamp::set_time(time_t newtime)
        {
            time     = newtime;
            timeinfo = *localtime(&time);
    Timestamp::Timestamp()
    {
        auto err     = bsp::rtc_GetCurrentTimestamp(&time);
        auto curTime = time + utils::time::Time::getTimeZoneOffset();
        if (err) {
            LOG_ERROR("rtc_GetCurrentTimestamp failure!");
        }
        timeinfo = *localtime(&curTime);
    }

        void Timestamp::set_time(std::string timestr, const char *fmt)
        {
    void Timestamp::set_time(time_t newtime)
    {
        time     = newtime;
        timeinfo = *localtime(&time);
    }

            std::stringstream stream(timestr);
            try {
                stream >> std::get_time(&(this->timeinfo), "%y/%m/%d %H:%M:%S");
    void Timestamp::set_time(std::string timestr, const char *fmt)
    {

                // add missing years, otherwise mktime returns bad timestamp
                timeinfo.tm_year += 100;
                this->time = mktime(&timeinfo);
            }
            catch (std::exception &e) {
                LOG_ERROR("Time::set_time error %s", e.what());
            }
        }
        std::stringstream stream(timestr);
        try {
            stream >> std::get_time(&(this->timeinfo), "%y/%m/%d %H:%M:%S");

        constexpr uint32_t datasize = 128;
        UTF8 Timestamp::str(std::string fmt)
        {
            if (fmt.compare("") != 0) {
                this->format = fmt;
            }
            UTF8 datetimestr = "";
            auto replaceFunc = [&](int idx) { return get_replacement(Replacements(idx), timeinfo); };
            utils::findAndReplaceAll(this->format, specifiers_replacement, replaceFunc);
            auto data = std::unique_ptr<char[]>(new char[datasize]);
            std::strftime(data.get(), datasize, this->format.c_str(), &timeinfo);
            datetimestr = UTF8(data.get());
            return datetimestr;
            // add missing years, otherwise mktime returns bad timestamp
            timeinfo.tm_year += 100;
            this->time = mktime(&timeinfo);
        }

        UTF8 Timestamp::day(bool abbrev)
        {
            if (abbrev) {
                return get_replacement(Replacements::DayAbbrev, timeinfo);
            }
            else {
                return get_replacement(Replacements::DayLong, timeinfo);
            }
        catch (std::exception &e) {
            LOG_ERROR("Time::set_time error %s", e.what());
        }
    }

        UTF8 Timestamp::month(bool abbrev)
        {
            if (abbrev) {
                return get_replacement(Replacements::MonthAbbrev, timeinfo);
            }
            else {
                return get_replacement(Replacements::MonthLong, timeinfo);
            }
    constexpr uint32_t datasize = 128;
    UTF8 Timestamp::str(std::string fmt)
    {
        if (fmt.compare("") != 0) {
            this->format = fmt;
        }

        Duration operator-(const Timestamp &lhs, const Timestamp &rhs)
        {
            return Duration(lhs.time, rhs.time);
        };
        Timestamp operator-(const Timestamp &lhs, const Duration &rhs)
        {
            return Timestamp(lhs.time < rhs.duration ? 0 : lhs.time - rhs.duration);
        };
        Timestamp operator+(const Timestamp &lhs, const Duration &rhs)
        {
            return Timestamp(lhs.time + rhs.duration);
        };
        Timestamp operator+(const Duration &lhs, const Timestamp &rhs)
        {
            return Timestamp(lhs.duration + rhs.time);
        UTF8 datetimestr = "";
        auto replaceFunc = [&](int idx) { return get_replacement(Replacements(idx), timeinfo); };
        utils::findAndReplaceAll(this->format, specifiers_replacement, replaceFunc);
        auto data = std::unique_ptr<char[]>(new char[datasize]);
        std::strftime(data.get(), datasize, this->format.c_str(), &timeinfo);
        datetimestr = UTF8(data.get());
        return datetimestr;
    }

    UTF8 Timestamp::day(bool abbrev)
    {
        if (abbrev) {
            return get_replacement(Replacements::DayAbbrev, timeinfo);
        }

        void DateTime::before_n_sec(time_t val)
        {
            local_time = time;
            if (val) {
                set_time(val);
            }
        else {
            return get_replacement(Replacements::DayLong, timeinfo);
        }
    }

        bool DateTime::isToday()
        {
            auto newer_timeinfo = *localtime(&local_time);
            return (newer_timeinfo.tm_yday == timeinfo.tm_yday && newer_timeinfo.tm_year == timeinfo.tm_year);
    UTF8 Timestamp::month(bool abbrev)
    {
        if (abbrev) {
            return get_replacement(Replacements::MonthAbbrev, timeinfo);
        }
        else {
            return get_replacement(Replacements::MonthLong, timeinfo);
        }
    }

        bool DateTime::isYesterday()
        {
            auto newer_timeinfo = *localtime(&local_time);
            bool is_leap_year =
                (timeinfo.tm_year % 4 == 0 && timeinfo.tm_year % 100 != 0) || timeinfo.tm_year % 400 == 0;

            return (((newer_timeinfo.tm_yday - timeinfo.tm_yday == 1) &&
                     (newer_timeinfo.tm_year == timeinfo.tm_year)) // day difference
                    || (timeinfo.tm_year == 0 &&
                        newer_timeinfo.tm_year + 364 + is_leap_year) // day next year day difference
            );
    Duration operator-(const Timestamp &lhs, const Timestamp &rhs)
    {
        return Duration(lhs.time, rhs.time);
    };
    Timestamp operator-(const Timestamp &lhs, const Duration &rhs)
    {
        return Timestamp(lhs.time < rhs.duration ? 0 : lhs.time - rhs.duration);
    };
    Timestamp operator+(const Timestamp &lhs, const Duration &rhs)
    {
        return Timestamp(lhs.time + rhs.duration);
    };
    Timestamp operator+(const Duration &lhs, const Timestamp &rhs)
    {
        return Timestamp(lhs.duration + rhs.time);
    }

    void DateTime::before_n_sec(time_t val)
    {
        local_time = time;
        if (val) {
            set_time(val);
        }
    }

        UTF8 DateTime::str(std::string format)
        {
            if (format.compare("") != 0) {
                return Timestamp::str(format);
            }
            if (isToday()) // if the same computer day, then return hour.
            {
                return Timestamp::str(Locale::format(Locale::FormatTime12H));
            }
            else if (show_textual_past && isYesterday()) {
                return Locale::yesterday();
            }
            else {
                return Timestamp::str(
                    Locale::format(date_format_long ? Locale::FormatLocaleDateFull : Locale::FormatLocaleDateShort));
            }
    bool DateTime::isToday()
    {
        auto newer_timeinfo = *localtime(&local_time);
        return (newer_timeinfo.tm_yday == timeinfo.tm_yday && newer_timeinfo.tm_year == timeinfo.tm_year);
    }

    bool DateTime::isYesterday()
    {
        auto newer_timeinfo = *localtime(&local_time);
        bool is_leap_year   = (timeinfo.tm_year % 4 == 0 && timeinfo.tm_year % 100 != 0) || timeinfo.tm_year % 400 == 0;

        return (((newer_timeinfo.tm_yday - timeinfo.tm_yday == 1) &&
                 (newer_timeinfo.tm_year == timeinfo.tm_year)) // day difference
                ||
                (timeinfo.tm_year == 0 && newer_timeinfo.tm_year + 364 + is_leap_year) // day next year day difference
        );
    }

    UTF8 DateTime::str(std::string format)
    {
        if (format.compare("") != 0) {
            return Timestamp::str(format);
        }
        UTF8 Timestamp::get_date_time_substr(GetParameters param)
        if (isToday()) // if the same computer day, then return hour.
        {
            auto value = get_date_time_sub_value(param);
            if (value != UINT32_MAX) {
                return UTF8(std::to_string(value));
            }
            return UTF8();
            return Timestamp::str(Locale::format(Locale::FormatTime12H));
        }

        uint32_t Timestamp::get_date_time_sub_value(GetParameters param)
        {
            switch (param) {
            case GetParameters::Hour:
                return timeinfo.tm_hour;
                break;
            case GetParameters::Minute:
                return timeinfo.tm_min;
                break;
            case GetParameters::Day:
                return timeinfo.tm_mday;
                break;
            case GetParameters::Month:
                return timeinfo.tm_mon + 1;
                break;
            case GetParameters::Year:
                return timeinfo.tm_year + 1900;
                break;
            }
            return UINT32_MAX;
        else if (show_textual_past && isYesterday()) {
            return Locale::yesterday();
        }
        UTF8 Date::str(std::string format)
        {
            if (!format.empty()) {
                return Timestamp::str(format);
            }
            else if (show_textual_past) {
                if (isToday()) {
                    return Locale::today();
                }
                else if (isYesterday()) {
                    return Locale::yesterday();
                }
            }

        else {
            return Timestamp::str(
                Locale::format(date_format_long ? Locale::FormatLocaleDateFull : Locale::FormatLocaleDateShort));
        }
    }
    UTF8 Timestamp::get_date_time_substr(GetParameters param)
    {
        auto value = get_date_time_sub_value(param);
        if (value != UINT32_MAX) {
            return UTF8(std::to_string(value));
        }
        return UTF8();
    }

        UTF8 Time::str(std::string format)
        {
            if (!format.empty()) {
                return Timestamp::str(format);
    uint32_t Timestamp::get_date_time_sub_value(GetParameters param)
    {
        switch (param) {
        case GetParameters::Hour:
            return timeinfo.tm_hour;
            break;
        case GetParameters::Minute:
            return timeinfo.tm_min;
            break;
        case GetParameters::Day:
            return timeinfo.tm_mday;
            break;
        case GetParameters::Month:
            return timeinfo.tm_mon + 1;
            break;
        case GetParameters::Year:
            return timeinfo.tm_year + 1900;
            break;
        }
        return UINT32_MAX;
    }
    UTF8 Date::str(std::string format)
    {
        if (!format.empty()) {
            return Timestamp::str(format);
        }
        else if (show_textual_past) {
            if (isToday()) {
                return Locale::today();
            }
            else {
                return Timestamp::str(
                    Locale::format(Locale::FormatTime12H)); // @TODO: M.G. FormatLocaleTime which actually works
            else if (isYesterday()) {
                return Locale::yesterday();
            }
        }

        void Time::setTimeZoneOffset(int tzOffset)
        {
            msTimeGmtOff = tzOffset;
        return Timestamp::str(
            Locale::format(date_format_long ? Locale::FormatLocaleDateFull : Locale::FormatLocaleDateShort));
    }

    UTF8 Time::str(std::string format)
    {
        if (!format.empty()) {
            return Timestamp::str(format);
        }
        else {
            return Timestamp::str(
                Locale::format(Locale::FormatTime12H)); // @TODO: M.G. FormatLocaleTime which actually works
        }
    }

        int Time::getTimeZoneOffset()
        {
            return msTimeGmtOff;
        };
    void Time::setTimeZoneOffset(int tzOffset)
    {
        msTimeGmtOff = tzOffset;
    }

        Duration::Duration(time_t duration) : duration(duration)
        {
            calculate();
        }
    int Time::getTimeZoneOffset()
    {
        return msTimeGmtOff;
    };

        Duration::Duration(time_t stop, time_t start) : Duration(stop - start > 0 ? stop - start : 0)
        {}
    Duration::Duration(time_t duration) : duration(duration)
    {
        calculate();
    }

        Duration::Duration(const Timestamp &stop, const Timestamp &start) : Duration(stop.getTime(), start.getTime())
        {}
    Duration::Duration(time_t stop, time_t start) : Duration(stop - start > 0 ? stop - start : 0)
    {}

        void Duration::fillStr(std::string &format) const
        {
            constexpr auto numberOfLeadingDigits = 2;
            utils::findAndReplaceAll(format, "%H", utils::to_string(hours));
            utils::findAndReplaceAll(format, "%M", utils::to_string(minutes));
            utils::findAndReplaceAll(format, "%N", utils::to_string(hmminutes));
            utils::findAndReplaceAll(format, "%S", utils::to_string(seconds));
            utils::findAndReplaceAll(
                format, "%0H", utils::addLeadingZeros(utils::to_string(hours), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0M", utils::addLeadingZeros(utils::to_string(minutes), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0N", utils::addLeadingZeros(utils::to_string(hmminutes), numberOfLeadingDigits));
            utils::findAndReplaceAll(
                format, "%0S", utils::addLeadingZeros(utils::to_string(seconds), numberOfLeadingDigits));
        }
    Duration::Duration(const Timestamp &stop, const Timestamp &start) : Duration(stop.getTime(), start.getTime())
    {}

        void Duration::calculate()
        {
            hours     = this->duration / secondsInHour;
            hmminutes = this->duration / secondsInMinute;
            minutes   = (this->duration % secondsInHour) / secondsInMinute;
            seconds   = (this->duration % secondsInHour) % secondsInMinute;

            if (verboseConversion) {
                LOG_DEBUG(
                    "duration %" PRIu64 " - %lu hours %lu minutes %lu seconds", duration, hours, minutes, seconds);
            }
    void Duration::fillStr(std::string &format) const
    {
        constexpr auto numberOfLeadingDigits = 2;
        utils::findAndReplaceAll(format, "%H", utils::to_string(hours));
        utils::findAndReplaceAll(format, "%M", utils::to_string(minutes));
        utils::findAndReplaceAll(format, "%N", utils::to_string(hmminutes));
        utils::findAndReplaceAll(format, "%S", utils::to_string(seconds));
        utils::findAndReplaceAll(format, "%0H", utils::addLeadingZeros(utils::to_string(hours), numberOfLeadingDigits));
        utils::findAndReplaceAll(
            format, "%0M", utils::addLeadingZeros(utils::to_string(minutes), numberOfLeadingDigits));
        utils::findAndReplaceAll(
            format, "%0N", utils::addLeadingZeros(utils::to_string(hmminutes), numberOfLeadingDigits));
        utils::findAndReplaceAll(
            format, "%0S", utils::addLeadingZeros(utils::to_string(seconds), numberOfLeadingDigits));
    }

    void Duration::calculate()
    {
        hours     = this->duration / secondsInHour;
        hmminutes = this->duration / secondsInMinute;
        minutes   = (this->duration % secondsInHour) / secondsInMinute;
        seconds   = (this->duration % secondsInHour) % secondsInMinute;

        if (verboseConversion) {
            LOG_DEBUG("duration %" PRIu64 " - %lu hours %lu minutes %lu seconds", duration, hours, minutes, seconds);
        }
    }

        UTF8 Duration::str(DisplayedFormat displayedFormat) const
        {
            // switch between format low and hig
            std::string data = utils::localize.get(hours != 0 ? formatMap.at(displayedFormat).highFormat
                                                              : formatMap.at(displayedFormat).lowFormat);
            fillStr(data);
    UTF8 Duration::str(DisplayedFormat displayedFormat) const
    {
        // switch between format low and hig
        std::string data = utils::localize.get(hours != 0 ? formatMap.at(displayedFormat).highFormat
                                                          : formatMap.at(displayedFormat).lowFormat);
        fillStr(data);

            return data;
        }
        return data;
    }

        Timestamp getCurrentTimestamp()
        {
            return Timestamp{};
        }
    }; // namespace time
};     // namespace utils
    Timestamp getCurrentTimestamp()
    {
        return Timestamp{};
    }
}; // namespace utils::time

M module-utils/time/time_conversion.hpp => module-utils/time/time_conversion.hpp +0 -25
@@ 37,13 37,6 @@ namespace utils
        // helper class to not put everything in time
        struct Localer
        {
            static constexpr auto abbrev_len = 3U;
            /// order matters, it's used in replace_locale with enum Replacements
            const inline static std::vector<std::string> specifiers_replacement = {"%a",  // day abbrew
                                                                                   "%A",  // day long
                                                                                   "%b",  // month abbrew
                                                                                   "%B",  // month long
                                                                                   "%Z"}; // timezone
            /// see specifiers_replacements description above
            enum Replacements
            {


@@ 279,24 272,6 @@ namespace utils
            }

          private:
            static constexpr auto verboseConversion   = false; // debug switch
            static constexpr auto durationFormatH0M0S = "duration_hour_0min_0sec";
            static constexpr auto durationFormat0M0S  = "duration_0min_0sec";
            static constexpr auto durationFormat0N0S  = "duration_0hmin_0sec";
            static constexpr auto durationFormatM0S   = "duration_min_0sec";

            struct Format
            {
                const std::string lowFormat;  /// format used if duration is below 1 hour
                const std::string highFormat; /// format used if duration exceeds 1 hour
            };
            using FormatMap                         = std::map<const DisplayedFormat, const Format>;
            static const inline FormatMap formatMap = {
                {DisplayedFormat::Fixed0M0S, {durationFormat0N0S, durationFormat0N0S}},
                {DisplayedFormat::FixedH0M0S, {durationFormatH0M0S, durationFormatH0M0S}},
                {DisplayedFormat::AutoM, {durationFormatM0S, durationFormatH0M0S}},
                {DisplayedFormat::Auto0M, {durationFormat0M0S, durationFormatH0M0S}}};

            void fillStr(std::string &formatlong) const;
            void calculate();
            time_t duration         = 0;

M module-vfs/CMakeLists.txt => module-vfs/CMakeLists.txt +1 -0
@@ 46,6 46,7 @@ set(SOURCES ""
        ${FREERTOS_FAT_EXTSOURCES}
        vfs-utils.cpp
        vfs.cpp
        vfs_paths.cpp
        vfsNotifier.cpp
        HandleManager.cpp
)

M module-vfs/board/cross/free_rtos_custom/portable/vfs.cpp => module-vfs/board/cross/free_rtos_custom/portable/vfs.cpp +7 -6
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include "vfs_paths.hpp"
#include "ff_eMMC_user_disk.hpp"

vfs::vfs() : emmc()


@@ 17,7 18,7 @@ void vfs::Init()
{
    emmc.Init();

    emmcFFDisk = FF_eMMC_user_DiskInit(purefs::dir::eMMC_disk.c_str(), &emmc);
    emmcFFDisk = FF_eMMC_user_DiskInit(purefs::dir::eMMC_disk, &emmc);

    /* Print out information on the disk. */
    FF_eMMC_user_DiskShowPartition(emmcFFDisk);


@@ 38,14 39,14 @@ void vfs::Init()

    // this should already exist and have user data in it
    // if it does not create an exmpty directory so that sqlite3 does not fault
    if (isDir(purefs::dir::user_disk.c_str()) == false) {
        LOG_ERROR("vfs::Init looks like %s does not exist, try to create it", purefs::dir::user_disk.c_str());
        if (ff_mkdir(purefs::dir::user_disk.c_str()) != 0) {
            LOG_ERROR("vfs::Init can't create %s directory", purefs::dir::user_disk.c_str());
    if (const auto userDiskPath = purefs::dir::getUserDiskPath(); isDir(userDiskPath.c_str()) == false) {
        LOG_ERROR("vfs::Init looks like %s does not exist, try to create it", userDiskPath.c_str());
        if (ff_mkdir(userDiskPath.c_str()) != 0) {
            LOG_ERROR("vfs::Init can't create %s directory", userDiskPath.c_str());
        }
    }
    else {
        LOG_INFO("vfs::Init looks like %s exists", purefs::dir::user_disk.c_str());
        LOG_INFO("vfs::Init looks like %s exists", userDiskPath.c_str());
    }
    chnNotifier.onFileSystemInitialized();
}

M module-vfs/board/linux/free_rtos_custom/portable/vfs.cpp => module-vfs/board/linux/free_rtos_custom/portable/vfs.cpp +7 -6
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
//
#include "vfs.hpp"
#include "vfs_paths.hpp"
#include "ff_image_user_disk.hpp"

namespace


@@ 23,7 24,7 @@ void vfs::Init()
        LOG_WARN("Disk manager already initialized");
        return;
    }
    emmcFFDisk = freertos_fat::internals::diskInit(purefs::dir::eMMC_disk.c_str(), image_name);
    emmcFFDisk = freertos_fat::internals::diskInit(purefs::dir::eMMC_disk, image_name);

    /* Print out information on the disk. */
    freertos_fat::internals::diskShowPartition(emmcFFDisk);


@@ 44,14 45,14 @@ void vfs::Init()

    // this should already exist and have user data in it
    // if it does not create an exmpty directory so that sqlite3 does not fault
    if (isDir(purefs::dir::user_disk.c_str()) == false) {
        LOG_ERROR("vfs::Init looks like %s does not exist, try to create it", purefs::dir::user_disk.c_str());
        if (ff_mkdir(purefs::dir::user_disk.c_str()) != 0) {
            LOG_ERROR("vfs::Init can't create %s directory", purefs::dir::user_disk.c_str());
    if (const auto userDiskPath = purefs::dir::getUserDiskPath(); isDir(userDiskPath.c_str()) == false) {
        LOG_ERROR("vfs::Init looks like %s does not exist, try to create it", userDiskPath.c_str());
        if (ff_mkdir(userDiskPath.c_str()) != 0) {
            LOG_ERROR("vfs::Init can't create %s directory", userDiskPath.c_str());
        }
    }
    else {
        LOG_INFO("vfs::Init looks like %s exists", purefs::dir::user_disk.c_str());
        LOG_INFO("vfs::Init looks like %s exists", userDiskPath.c_str());
    }
    chnNotifier.onFileSystemInitialized();
}

M module-vfs/vfs-utils.cpp => module-vfs/vfs-utils.cpp +5 -3
@@ 7,6 7,8 @@
#include <ticks.hpp>
#include <source/version.hpp>

#include "vfs_paths.hpp"

std::string vfs::generateRandomId(size_t length = 0)
{
    const std::string CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";


@@ 128,7 130,7 @@ const fs::path vfs::getCurrentBootJSON()
        return relativeToRoot(purefs::file::boot_json);
    }

    LOG_INFO("vfs::getCurrentBootJSON crc check failed on %s", purefs::file::boot_json.c_str());
    LOG_INFO("vfs::getCurrentBootJSON crc check failed on %s", purefs::file::boot_json);
    return relativeToRoot(purefs::file::boot_json);
}



@@ 145,7 147,7 @@ bool vfs::loadBootConfig(const fs::path &bootJsonPath)
    if (parseErrors == "") {
        bootConfig.os_type  = bootConfig.boot_json_parsed[purefs::json::main][purefs::json::os_type].string_value();
        bootConfig.os_image = bootConfig.boot_json_parsed[purefs::json::main][purefs::json::os_image].string_value();
        bootConfig.os_root_path = purefs::dir::eMMC_disk / bootConfig.os_type;
        bootConfig.os_root_path = purefs::createPath(purefs::dir::eMMC_disk, bootConfig.os_type);
        bootConfig.boot_json    = bootJsonPath;
        bootConfig.bootloader_verion =
            bootConfig.boot_json_parsed[purefs::json::bootloader][purefs::json::os_version].string_value();


@@ 158,7 160,7 @@ bool vfs::loadBootConfig(const fs::path &bootJsonPath)
    else {
        bootConfig.os_type      = PATH_CURRENT;
        bootConfig.os_image     = purefs::file::boot_bin;
        bootConfig.os_root_path = purefs::dir::eMMC_disk / bootConfig.os_type;
        bootConfig.os_root_path = purefs::createPath(purefs::dir::eMMC_disk, bootConfig.os_type);
        bootConfig.boot_json    = bootJsonPath;
        bootConfig.timestamp    = utils::time::Timestamp().str("%c");
        bootConfig.os_version   = std::string(VERSION);

M module-vfs/vfs.cpp => module-vfs/vfs.cpp +2 -1
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include "vfs_paths.hpp"

#include <memory>



@@ 227,7 228,7 @@ std::string vfs::relativeToRoot(const std::string path)
        if (bootConfig.os_root_path.root_directory() == fsPath.root_directory())
            return fsPath;
        else
            return (purefs::dir::eMMC_disk / fsPath.relative_path()).c_str();
            return purefs::createPath(purefs::dir::eMMC_disk, fsPath.relative_path()).c_str();
    }

    if (path.empty())

M module-vfs/vfs.hpp => module-vfs/vfs.hpp +1 -30
@@ 12,6 12,7 @@
#include <log/log.hpp>
#include <json/json11.hpp>
#include "vfsNotifier.hpp"
#include "vfs_globals.hpp"

#ifndef TARGET_Linux
#include "board/cross/eMMC/eMMC.hpp"


@@ 19,40 20,10 @@

#include "ff_stdio.h"

#define PATH_SYS      "/sys"
#define PATH_USER     "user"
#define PATH_CURRENT  "current"
#define PATH_PREVIOUS "previous"
#define PATH_UPDATES  "updates"
#define PATH_TMP      "tmp"
#define PATH_BACKUP   "backup"
#define PATH_FACTORY  "factory"

// this just concatenates two strings and creates a /user/ subdirectory filename
#define USER_PATH(file) PATH_SYS "/" PATH_USER "/" file

namespace fs = std::filesystem;

namespace purefs
{
    namespace dir
    {
        const inline fs::path eMMC_disk   = PATH_SYS;
        const inline fs::path user_disk   = eMMC_disk / PATH_USER;
        const inline fs::path os_current  = eMMC_disk / PATH_CURRENT;
        const inline fs::path os_previous = eMMC_disk / PATH_PREVIOUS;
        const inline fs::path os_updates  = eMMC_disk / PATH_UPDATES;
        const inline fs::path tmp         = eMMC_disk / PATH_TMP;
        const inline fs::path os_backup   = eMMC_disk / PATH_BACKUP;
        const inline fs::path os_factory  = eMMC_disk / PATH_FACTORY;
    } // namespace dir

    namespace file
    {
        const inline fs::path boot_json = ".boot.json";
        const inline fs::path boot_bin  = "boot.bin";
    }; // namespace file

    namespace extension
    {
        inline constexpr auto crc32 = ".crc32";

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

#pragma once

#define PATH_SYS      "/sys"
#define PATH_USER     "user"
#define PATH_CURRENT  "current"
#define PATH_PREVIOUS "previous"
#define PATH_UPDATES  "updates"
#define PATH_TMP      "tmp"
#define PATH_BACKUP   "backup"
#define PATH_FACTORY  "factory"

// this just concatenates two strings and creates a /user/ subdirectory filename
#define USER_PATH(file) PATH_SYS "/" PATH_USER "/" file

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

#include "vfs_paths.hpp"

namespace purefs
{
    std::filesystem::path createPath(const std::string &parent, const std::string &child) noexcept
    {
        return std::filesystem::path{parent} / child;
    }

    namespace dir
    {
        std::filesystem::path getUserDiskPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_USER;
        }

        std::filesystem::path getCurrentOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_CURRENT;
        }

        std::filesystem::path getPreviousOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_PREVIOUS;
        }

        std::filesystem::path getUpdatesOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_UPDATES;
        }

        std::filesystem::path getTemporaryPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_TMP;
        }

        std::filesystem::path getBackupOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_BACKUP;
        }

        std::filesystem::path getFactoryOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_FACTORY;
        }
    } // namespace dir
} // namespace purefs

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

#pragma once

#include "vfs_globals.hpp"

#include <filesystem>

namespace purefs
{
    std::filesystem::path createPath(const std::string &parent, const std::string &child) noexcept;

    namespace dir
    {
        constexpr inline auto eMMC_disk = PATH_SYS;

        std::filesystem::path getUserDiskPath() noexcept;
        std::filesystem::path getCurrentOSPath() noexcept;
        std::filesystem::path getPreviousOSPath() noexcept;
        std::filesystem::path getUpdatesOSPath() noexcept;
        std::filesystem::path getTemporaryPath() noexcept;
        std::filesystem::path getBackupOSPath() noexcept;
        std::filesystem::path getFactoryOSPath() noexcept;
    } // namespace dir

    namespace file
    {
        constexpr inline auto boot_json = ".boot.json";
        constexpr inline auto boot_bin  = "boot.bin";
    } // namespace file
} // namespace purefs