~aleteoryx/muditaos

4e0f72e70ac08cd9278e1f380b6733662d55114a — Piotr Tanski 5 years ago caa4ece
[EGD-4696] Several stabilization patches. (#1192)

M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +1 -1
@@ 160,7 160,7 @@ namespace gui

    bool MessagesMainWindow::onDatabaseMessage(sys::Message *msgl)
    {
        auto *msgNotification = dynamic_cast<db::NotificationMessage *>(msgl);
        auto msgNotification = dynamic_cast<db::NotificationMessage *>(msgl);
        if (msgNotification != nullptr) {
            if (msgNotification->interface == db::Interface::Name::SMSThread ||
                msgNotification->interface == db::Interface::Name::SMS) {

M module-bsp/board/linux/usb_cdc/usb_cdc.cpp => module-bsp/board/linux/usb_cdc/usb_cdc.cpp +1 -3
@@ 45,9 45,7 @@ namespace bsp

    int usbCDCSend(std::string *sendMsg)
    {
        ssize_t t = write(fd, (*sendMsg).c_str(), (*sendMsg).length());
        delete sendMsg;

        ssize_t t = write(fd, sendMsg->c_str(), sendMsg->length());
        if (t >= 0) {
            LOG_DEBUG("[ServiceDesktop:BSP_Driver] Send: %d signs", static_cast<int>(t));
            return 0;

M module-db/Database/Database.cpp => module-db/Database/Database.cpp +62 -54
@@ 5,16 5,19 @@
#include "DatabaseInitializer.hpp"

#include "log/log.hpp"
#include <assert.h>
#include <memory>

#include <purefs/filesystem_paths.hpp>
#include <gsl/gsl_util>

#include <cassert>
#include <cstring>
#include <memory>

/* Declarations *********************/
extern sqlite3_vfs *sqlite3_ecophonevfs(void);

extern "C"
{

    int sqlite3_os_init(void)
    {
        /*


@@ 39,7 42,6 @@ extern "C"
         */

        sqlite3_vfs_register(sqlite3_ecophonevfs(), 1);

        return SQLITE_OK;
    }



@@ 52,7 54,6 @@ extern "C"
     */
    int sqlite3_os_end(void)
    {

        return SQLITE_OK;
    }



@@ 64,86 65,99 @@ extern "C"
}

Database::Database(const char *name)
    : dbConnection(nullptr), dbName(name), isInitialized_(false),
    : dbConnection(nullptr), dbName(name), queryStatementBuffer{nullptr}, isInitialized_(false),
      initializer(std::make_unique<DatabaseInitializer>(this))
{
    LOG_INFO("creating database: %s", dbName.c_str());
    auto rc = sqlite3_open(name, &dbConnection);
    if (rc != SQLITE_OK) {
    LOG_INFO("Creating database: %s", dbName.c_str());
    if (const auto rc = sqlite3_open(name, &dbConnection); rc != SQLITE_OK) {
        LOG_ERROR("SQLITE INITIALIZATION ERROR! rc=%d dbName=%s", rc, name);
        throw DatabaseInitialisationError{"Failed to initialize the sqlite db"};
    }
    assert(rc == SQLITE_OK);

    initQueryStatementBuffer();
    pragmaQuery("PRAGMA integrity_check;");
    pragmaQuery("PRAGMA locking_mode=EXCLUSIVE");

    const auto filePath = (purefs::dir::getUserDiskPath() / "db");
    LOG_INFO("running scripts: %s", filePath.c_str());
    isInitialized_ = initializer->run(filePath.c_str(), INIT_SCRIPTS_EXT);
    LOG_INFO("Running scripts: %s", filePath.c_str());
    isInitialized_ = initializer->run(filePath.c_str(), InitScriptExtension);
}

void Database::initQueryStatementBuffer()
{
    queryStatementBuffer = static_cast<char *>(sqlite3_malloc(maxQueryLen));
    if (queryStatementBuffer == nullptr) {
        LOG_ERROR("Unable to allocate memory for query statement buffer.");
        throw DatabaseInitialisationError{"Failed to initialize the query statement buffer"};
    }
    clearQueryStatementBuffer();
}

void Database::clearQueryStatementBuffer()
{
    std::memset(queryStatementBuffer, 0, maxQueryLen);
}

Database::~Database()
{
    sqlite3_free(queryStatementBuffer);
    sqlite3_close(dbConnection);
}

void Database::initialize()
bool Database::initialize()
{
    sqlite3_config(
        SQLITE_CONFIG_LOG,
        errorLogCallback,
        (void *)1); //(void*)1 is taken from official SQLITE examples and it appears that it ends variable args list
    sqlite3_initialize();
    if (const auto code = sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, (void *)1); code != SQLITE_OK) {
        //(void*)1 is taken from official SQLITE examples and it appears that it ends variable args list
        return false;
    }
    return sqlite3_initialize() == SQLITE_OK;
}
void Database::deinitialize()

bool Database::deinitialize()
{
    sqlite3_shutdown();
    return sqlite3_shutdown() == SQLITE_OK;
}

bool Database::execute(const char *format, ...)
{
    if (!format) {
    if (format == nullptr) {
        return false;
    }

    auto cleanup = gsl::finally([this] { clearQueryStatementBuffer(); });

    va_list ap;
    char *szQuery = static_cast<char *>(sqlite3_malloc(maxQueryLen));
    va_start(ap, format);
    sqlite3_vsnprintf(maxQueryLen, (char *)szQuery, format, ap);
    sqlite3_vsnprintf(maxQueryLen, queryStatementBuffer, format, ap);
    va_end(ap);

    int result = sqlite3_exec(dbConnection, szQuery, NULL, NULL, NULL);
    if (result != SQLITE_OK)
        LOG_ERROR("Execution of \'%s\' failed with %d", szQuery, result);

    sqlite3_free(szQuery);

    return result != SQLITE_OK ? false : true;
    if (const int result = sqlite3_exec(dbConnection, queryStatementBuffer, nullptr, nullptr, nullptr);
        result != SQLITE_OK) {
        LOG_ERROR("Execution of \'%s\' failed with %d", queryStatementBuffer, result);
        return false;
    }
    return true;
}

std::unique_ptr<QueryResult> Database::query(const char *format, ...)
{

    if (!format) {
    if (format == nullptr) {
        return nullptr;
    }

    auto cleanup = gsl::finally([this] { clearQueryStatementBuffer(); });

    va_list ap;
    char *szQuery = static_cast<char *>(sqlite3_malloc(maxQueryLen));
    va_start(ap, format);
    szQuery[0] = 0;
    sqlite3_vsnprintf(maxQueryLen, szQuery, format, ap);
    sqlite3_vsnprintf(maxQueryLen, queryStatementBuffer, format, ap);
    va_end(ap);

    auto queryResult = std::make_unique<QueryResult>();

    int result = sqlite3_exec(dbConnection, szQuery, queryCallback, queryResult.get(), NULL);
    if (result != SQLITE_OK) {
        LOG_ERROR("SQL query \'%s\' failed selecting : %d", szQuery, result);
    if (const int result = sqlite3_exec(dbConnection, queryStatementBuffer, queryCallback, queryResult.get(), nullptr);
        result != SQLITE_OK) {
        LOG_ERROR("SQL query \'%s\' failed selecting : %d", queryStatementBuffer, result);
        return nullptr;
    }

    sqlite3_free(szQuery);

    return queryResult;
}



@@ 173,9 187,8 @@ uint32_t Database::getLastInsertRowId()

void Database::pragmaQuery(const std::string &pragmaStatemnt)
{
    auto results = query(pragmaStatemnt.c_str());
    if (results) {
        uint32_t fieldsCount = results->getFieldCount();
    if (auto results = query(pragmaStatemnt.c_str()); results) {
        const auto fieldsCount = results->getFieldCount();
        do {
            for (uint32_t i = 0; i < fieldsCount; i++) {
                Field field = (*results)[i];


@@ 191,15 204,10 @@ void Database::pragmaQuery(const std::string &pragmaStatemnt)
bool Database::storeIntoFile(const std::string &backupPath)
{
    LOG_INFO("Backup database: %s, into file: %s - STARTED", dbName.c_str(), backupPath.c_str());

    auto rc = execute("VACUUM INTO '%q';", backupPath.c_str());

    if (rc == true) {
        LOG_INFO("Backup database: %s, into file: %s - SUCCEDED", dbName.c_str(), backupPath.c_str());
    }
    else {
    if (const auto rc = execute("VACUUM INTO '%q';", backupPath.c_str()); !rc) {
        LOG_ERROR("Backup database: %s, into file: %s - FAILED", dbName.c_str(), backupPath.c_str());
        return false;
    }

    return rc;
    LOG_INFO("Backup database: %s, into file: %s - SUCCEDED", dbName.c_str(), backupPath.c_str());
    return true;
}

M module-db/Database/Database.hpp => module-db/Database/Database.hpp +22 -14
@@ 4,21 4,23 @@
#pragma once

#include "sqlite3.h"

#include "QueryResult.hpp"

#include <memory>
#include <set>
#include <stdexcept>

class DatabaseInitializer;

class Database
class DatabaseInitialisationError : public std::runtime_error
{
    static constexpr char INIT_SCRIPTS_EXT[] = "sql";

  public:
    Database(const char *name);
    using std::runtime_error::runtime_error;
};

class Database
{
  public:
    explicit Database(const char *name);
    virtual ~Database();

    std::unique_ptr<QueryResult> query(const char *format, ...);


@@ 26,27 28,32 @@ class Database
    bool execute(const char *format, ...);

    // Must be invoked prior creating any database object in order to initialize database OS layer
    static void initialize();
    // Must be invoked before closing system in order to properly close OS layer
    static void deinitialize();
    static bool initialize();

    bool isInitialized() const
    {
        return isInitialized_;
    }
    // Must be invoked before closing system in order to properly close OS layer
    static bool deinitialize();

    bool storeIntoFile(const std::string &backupPath);

    uint32_t getLastInsertRowId();
    void pragmaQuery(const std::string &pragmaStatemnt);

    [[nodiscard]] bool isInitialized() const noexcept
    {
        return isInitialized_;
    }

    [[nodiscard]] std::string getName() const
    {
        return dbName;
    }

  private:
    const uint32_t maxQueryLen = (8 * 1024);
    static constexpr auto InitScriptExtension  = "sql";
    static constexpr std::uint32_t maxQueryLen = (8 * 1024);

    void initQueryStatementBuffer();
    void clearQueryStatementBuffer();

    /*
     * Arguments:


@@ 61,6 68,7 @@ class Database
  protected:
    sqlite3 *dbConnection;
    std::string dbName;
    char *queryStatementBuffer;
    bool isInitialized_;
    std::unique_ptr<DatabaseInitializer> initializer;
};

M module-db/Tables/AlarmsStatusTable.cpp => module-db/Tables/AlarmsStatusTable.cpp +1 -2
@@ 19,8 19,7 @@ bool AlarmsStatusTable::add(AlarmsStatusRow entry)
uint32_t AlarmsStatusTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM alarmStatuses;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/AlarmsTable.cpp => module-db/Tables/AlarmsTable.cpp +1 -3
@@ 149,8 149,7 @@ std::vector<AlarmsTableRow> AlarmsTable::getLimitOffsetByField(uint32_t offset,
uint32_t AlarmsTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM alarms;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }



@@ 160,7 159,6 @@ uint32_t AlarmsTable::count()
uint32_t AlarmsTable::countByFieldId(const char *field, uint32_t id)
{
    auto queryRet = db->query("SELECT COUNT(*) FROM alarms WHERE %q=%lu;", field, id);

    if ((queryRet == nullptr) || (queryRet->getRowCount() == 0)) {
        return 0;
    }

M module-db/Tables/ContactsAddressTable.cpp => module-db/Tables/ContactsAddressTable.cpp +2 -2
@@ 124,7 124,7 @@ uint32_t ContactsAddressTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM contact_address;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }



@@ 140,4 140,4 @@ uint32_t ContactsAddressTable::countByFieldId(const char *field, uint32_t id)
    }

    return uint32_t{(*queryRet)[0].getUInt32()};
}
\ No newline at end of file
}

M module-db/Tables/ContactsGroups.cpp => module-db/Tables/ContactsGroups.cpp +7 -7
@@ 109,9 109,9 @@ void ContactsGroupsTable::updateGroups(uint32_t contactId, std::set<ContactsGrou
ContactsGroupsTableRow ContactsGroupsTable::getById(uint32_t id)
{
    if (id != DB_ID_NONE) {
        auto qureryResult = db->query(statements::getById, id);
        if (qureryResult->getRowCount() == 1) {
            return {(*qureryResult)[0].getUInt32(), (*qureryResult)[1].getString()};
        auto queryResult = db->query(statements::getById, id);
        if (queryResult && queryResult->getRowCount() == 1) {
            return {(*queryResult)[0].getUInt32(), (*queryResult)[1].getString()};
        }
    }
    return ContactsGroupsTableRow();


@@ 187,7 187,7 @@ uint32_t ContactsGroupsTable::getId(const std::string &name)
{
    if (!name.empty()) {
        auto queryRet = db->query(statements::getId, name.c_str());
        if (queryRet->getRowCount() != 0) {
        if (queryRet && queryRet->getRowCount() != 0) {
            return (*queryRet)[0].getUInt32();
        }
    }


@@ 197,7 197,7 @@ uint32_t ContactsGroupsTable::getId(const std::string &name)
std::set<ContactsGroupsTableRow> ContactsGroupsTable::getGroupsForContact(uint32_t contactId)
{
    auto queryResult = db->query(statements::getGroupsForContact, contactId);
    if (queryResult->getRowCount() != 0) {
    if (queryResult && queryResult->getRowCount() != 0) {
        std::set<ContactsGroupsTableRow> results;
        do {
            results.insert(ContactsGroupsTableRow((*queryResult)[0].getUInt32(), (*queryResult)[1].getString()));


@@ 221,7 221,7 @@ std::set<uint32_t> ContactsGroupsTable::getContactsForGroup(uint32_t groupId)
{
    (void)(&groupId);
    auto queryResults = db->query(statements::getContactsForGroup, groupId);
    if (queryResults->getRowCount() != 0) {
    if (queryResults && queryResults->getRowCount() != 0) {
        std::set<uint32_t> contacts;
        do {
            contacts.insert((*queryResults)[0].getUInt32());


@@ 234,7 234,7 @@ std::set<uint32_t> ContactsGroupsTable::getContactsForGroup(uint32_t groupId)
uint32_t ContactsGroupsTable::getIdOrCount(const char *queryString) const
{
    auto queryRet = db->query(queryString);
    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }
    return (*queryRet)[0].getUInt32();

M module-db/Tables/ContactsNameTable.cpp => module-db/Tables/ContactsNameTable.cpp +1 -1
@@ 125,7 125,7 @@ uint32_t ContactsNameTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM contact_name;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/ContactsNumberTable.cpp => module-db/Tables/ContactsNumberTable.cpp +1 -1
@@ 148,7 148,7 @@ uint32_t ContactsNumberTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM contact_number;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/ContactsRingtonesTable.cpp => module-db/Tables/ContactsRingtonesTable.cpp +1 -1
@@ 112,7 112,7 @@ uint32_t ContactsRingtonesTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM contact_ringtones;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/ContactsTable.cpp => module-db/Tables/ContactsTable.cpp +1 -1
@@ 419,7 419,7 @@ uint32_t ContactsTable::count()
                              "        AND cg.name = 'Temporary' "
                              "    ); ");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/CountryCodesTable.cpp => module-db/Tables/CountryCodesTable.cpp +1 -1
@@ 37,7 37,7 @@ uint32_t CountryCodesTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM codes;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-db/Tables/NotesTable.cpp => module-db/Tables/NotesTable.cpp +1 -1
@@ 139,7 139,7 @@ std::vector<NotesTableRow> NotesTable::getByText(const std::string &text)
std::uint32_t NotesTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM notes;");
    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }
    return (*queryRet)[0].getUInt32();

M module-db/Tables/SMSTemplateTable.cpp => module-db/Tables/SMSTemplateTable.cpp +1 -1
@@ 98,7 98,7 @@ uint32_t SMSTemplateTable::count()
{
    auto queryRet = db->query("SELECT COUNT(*) FROM templates;");

    if (queryRet->getRowCount() == 0) {
    if (!queryRet || queryRet->getRowCount() == 0) {
        return 0;
    }


M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +19 -5
@@ 69,6 69,9 @@
#include <ucs2/UCS2.hpp>
#include <utf8/UTF8.hpp>

#include <module-db/queries/messages/sms/QuerySMSUpdate.hpp>
#include <module-db/queries/messages/sms/QuerySMSAdd.hpp>

#include <algorithm>
#include <bits/exception.h>
#include <cassert>


@@ 1323,7 1326,7 @@ bool ServiceCellular::sendSMS(SMSRecord record)
        LOG_INFO("SMS sending failed.");
        record.type = SMSType::FAILED;
    }
    DBServiceAPI::SMSUpdate(this, record);
    DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<db::query::SMSUpdate>(record));

    channel->cmd(at::AT::SMS_GSM);
    return result;


@@ 1780,15 1783,26 @@ SMSRecord ServiceCellular::createSMSRecord(const UTF8 &decodedMessage,

bool ServiceCellular::dbAddSMSRecord(const SMSRecord &record)
{
    if (DBServiceAPI::SMSAdd(this, record) == DB_ID_NONE) {
        return false;
    }
    auto query = std::make_unique<db::query::SMSAdd>(record);
    query->setQueryListener(db::QueryCallback::fromFunction([this](auto response) {
        auto result = dynamic_cast<db::query::SMSAddResult *>(response);
        if (result == nullptr || !result->result) {
            return false;
        }

        onSMSReceived();
        return true;
    }));
    return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::move(query));
}

void ServiceCellular::onSMSReceived()
{
    DBServiceAPI::GetQuery(this,
                           db::Interface::Name::Notifications,
                           std::make_unique<db::query::notifications::Increment>(NotificationsRecord::Key::Sms));
    const std::string ringtone_path = "assets/audio/SMS-drum2.mp3";
    AudioServiceAPI::PlaybackStart(this, audio::PlaybackType::TextMessageRingtone, ringtone_path);
    return true;
}

bool ServiceCellular::handleListMessages(const at::AT &command, DLC_channel *channel)

M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +1 -0
@@ 229,6 229,7 @@ class ServiceCellular : public sys::Service
                                            const time_t messageDate,
                                            const SMSType &smsType = SMSType::INBOX) const noexcept;
    bool dbAddSMSRecord(const SMSRecord &record);
    void onSMSReceived();
    [[nodiscard]] bool handleListMessages(const at::AT &command, DLC_channel *channel);
    /// @}


M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +0 -373
@@ 41,144 41,6 @@ namespace sys
} // namespace sys
struct NotesRecord;

uint32_t DBServiceAPI::SMSAdd(sys::Service *serv, const SMSRecord &rec)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSAdd, rec);

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return (*smsResponse->records)[0].ID;
    }
    else {
        return DB_ID_NONE;
    }
}

bool DBServiceAPI::SMSRemove(sys::Service *serv, const SMSRecord &rec)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSRemove);
    msg->record                       = rec;

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::SMSUpdate(sys::Service *serv, const SMSRecord &rec)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSUpdate, rec);

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

SMSRecord DBServiceAPI::SMSGetLastRecord(sys::Service *serv)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSGetLastRecord);

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return (*smsResponse->records)[0];
    }
    else {
        return SMSRecord();
    }
}

std::unique_ptr<std::vector<SMSRecord>> DBServiceAPI::SMSGetLimitOffset(sys::Service *serv,
                                                                        uint32_t offset,
                                                                        uint32_t limit)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSGetSMSLimitOffset);
    msg->offset                       = offset;
    msg->limit                        = limit;

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return std::move(smsResponse->records);
    }
    else {
        return std::make_unique<std::vector<SMSRecord>>();
    }
}

std::unique_ptr<std::vector<SMSRecord>> DBServiceAPI::SMSGetLimitOffsetByThreadID(sys::Service *serv,
                                                                                  uint32_t offset,
                                                                                  uint32_t limit,
                                                                                  uint32_t id)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSMessage>(MessageType::DBSMSGetSMSLimitOffsetByThreadID);
    msg->offset                       = offset;
    msg->limit                        = limit;
    msg->id                           = id;

    auto ret                          = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBSMSResponseMessage *smsResponse = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (smsResponse->retCode == true)) {
        return std::move(smsResponse->records);
    }
    else {
        return std::make_unique<std::vector<SMSRecord>>();
    }
}

uint32_t DBServiceAPI::SMSGetCount(sys::Service *serv)
{
    std::shared_ptr<DBSMSMessage> msg = std::make_shared<DBSMSGetCount>();

    auto ret  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto *sms = reinterpret_cast<DBSMSResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (sms->retCode == true)) {
        return sms->count;
    }
    else {
        return 0;
    }
}

std::unique_ptr<ThreadRecord> DBServiceAPI::ThreadGet(sys::Service *serv, uint32_t id)
{
    std::shared_ptr<DBThreadMessage> msg = std::make_shared<DBThreadMessage>(MessageType::DBThreadGet);
    msg->id                              = id;

    auto ret                                = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBThreadResponseMessage *threadResponse = reinterpret_cast<DBThreadResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (threadResponse->retCode == true)) {
        return std::make_unique<ThreadRecord>((*threadResponse->records)[0]);
    }
    else {
        return nullptr;
    }
}

std::unique_ptr<ThreadRecord> DBServiceAPI::ThreadGetByContact(sys::Service *serv, uint32_t contact)
{
    std::shared_ptr<DBThreadMessageGet> msg =
        std::make_shared<DBThreadMessageGet>(MessageType::DBThreadGetForContact, contact);
    auto ret                                = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBThreadResponseMessage *threadResponse = reinterpret_cast<DBThreadResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (threadResponse->retCode == true)) {
        return std::make_unique<ThreadRecord>((*threadResponse->records)[0]);
    }
    else {
        return nullptr;
    }
}

std::unique_ptr<ThreadRecord> DBServiceAPI::ThreadGetByNumber(sys::Service *serv,
                                                              const utils::PhoneNumber::View &phoneNumber,
                                                              std::uint32_t timeout)


@@ 200,21 62,6 @@ std::unique_ptr<ThreadRecord> DBServiceAPI::ThreadGetByNumber(sys::Service *serv
    return nullptr;
}

bool DBServiceAPI::ThreadRemove(sys::Service *serv, uint32_t id)
{
    std::shared_ptr<DBThreadMessage> msg = std::make_shared<DBThreadMessage>(MessageType::DBThreadRemove);
    msg->id                              = id;

    auto ret                                = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBThreadResponseMessage *threadResponse = reinterpret_cast<DBThreadResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (threadResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit)
{
    std::shared_ptr<DBThreadMessage> msg = std::make_shared<DBThreadMessage>(MessageType::DBThreadGetLimitOffset);


@@ 240,97 87,6 @@ uint32_t DBServiceAPI::ThreadGetCount(sys::Service *serv, EntryState state)
    }
}

bool DBServiceAPI::ThreadUpdate(sys::Service *serv, const ThreadRecord &rec)
{
    std::shared_ptr<DBThreadMessage> msg = std::make_shared<DBThreadMessage>(MessageType::DBThreadUpdate, rec);

    sys::Bus::SendUnicast(msg, service::name::db, serv);
    return true;
}

bool DBServiceAPI::SMSTemplateAdd(sys::Service *serv, const SMSTemplateRecord &rec)
{
    auto msg = std::make_shared<DBSMSTemplateMessage>(MessageType::DBSMSTemplateAdd, rec);

    auto ret  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto resp = dynamic_cast<DBSMSTemplateResponseMessage *>(ret.second.get());
    if (ret.first == sys::ReturnCodes::Success && resp != nullptr) {
        return resp->retCode;
    }

    return false;
}

bool DBServiceAPI::SMSTemplateRemove(sys::Service *serv, uint32_t id)
{
    auto msg = std::make_shared<DBSMSTemplateMessage>(MessageType::DBSMSTemplateRemove);
    msg->id  = id;

    auto ret  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto resp = dynamic_cast<DBSMSTemplateResponseMessage *>(ret.second.get());
    if (ret.first == sys::ReturnCodes::Success && resp != nullptr) {
        return resp->retCode;
    }

    return false;
}

bool DBServiceAPI::SMSTemplateUpdate(sys::Service *serv, const SMSTemplateRecord &rec)
{
    auto msg = std::make_shared<DBSMSTemplateMessage>(MessageType::DBSMSTemplateUpdate, rec);

    auto ret  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto resp = dynamic_cast<DBSMSTemplateResponseMessage *>(ret.second.get());
    if (ret.first == sys::ReturnCodes::Success && resp != nullptr) {
        return resp->retCode;
    }

    return false;
}

uint32_t DBServiceAPI::SMSTemplateGetCount(sys::Service *serv)
{
    auto msg = std::make_shared<DBSMSTemplateGetCount>();

    auto ret  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto resp = dynamic_cast<DBSMSTemplateResponseMessage *>(ret.second.get());
    if (ret.first == sys::ReturnCodes::Success && resp != nullptr) {
        return resp->count;
    }

    return 0;
}

bool DBServiceAPI::SMSTemplateGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit)
{
    auto msg    = std::make_shared<DBSMSTemplateMessage>(MessageType::DBSMSTemplateGetLimitOffset);
    msg->offset = offset;
    msg->limit  = limit;

    return sys::Bus::SendUnicast(msg, service::name::db, serv);
}

std::unique_ptr<std::vector<ContactRecord>> DBServiceAPI::ContactGetByName(sys::Service *serv,
                                                                           UTF8 primaryName,
                                                                           UTF8 alternativeName)
{

    ContactRecord rec;
    rec.primaryName     = primaryName;
    rec.alternativeName = alternativeName;

    std::shared_ptr<DBContactMessage> msg = std::make_shared<DBContactMessage>(MessageType::DBContactGetByName, rec);

    auto ret                                  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBContactResponseMessage *contactResponse = reinterpret_cast<DBContactResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode == true)) {
        return std::move(contactResponse->records);
    }
    else {
        return std::make_unique<std::vector<ContactRecord>>();
    }
}

std::unique_ptr<std::vector<ContactRecord>> DBServiceAPI::ContactGetByID(sys::Service *serv, uint32_t contactID)
{
    ContactRecord rec;


@@ 505,47 261,6 @@ bool DBServiceAPI::ContactUpdate(sys::Service *serv, const ContactRecord &rec)
    }
}

bool DBServiceAPI::ContactBlock(sys::Service *serv, uint32_t id, const bool shouldBeBlocked)
{
    std::shared_ptr<DBContactBlock> msg =
        std::make_shared<DBContactBlock>(MessageType::DBContactBlock, id, shouldBeBlocked);

    auto ret                                  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBContactResponseMessage *contactResponse = reinterpret_cast<DBContactResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

uint32_t DBServiceAPI::ContactGetCount(sys::Service *serv, bool favourites)
{
    std::shared_ptr<DBContactMessage> msg =
        std::make_shared<DBContactMessage>(MessageType::DBContactGetCount, ContactRecord{}, favourites);

    auto ret                                  = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBContactResponseMessage *contactResponse = reinterpret_cast<DBContactResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode == true)) {
        return contactResponse->count;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::ContactGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit)
{
    std::shared_ptr<DBContactMessage> msg =
        std::make_shared<DBContactMessage>(MessageType::DBContactGetLimitOffset, ContactRecord{});
    msg->offset = offset;
    msg->limit  = limit;

    sys::Bus::SendUnicast(msg, service::name::db, serv);
    return true;
}

std::unique_ptr<std::vector<ContactRecord>> DBServiceAPI::ContactSearch(sys::Service *serv,
                                                                        UTF8 primaryName,
                                                                        UTF8 alternativeName,


@@ 567,73 282,6 @@ std::unique_ptr<std::vector<ContactRecord>> DBServiceAPI::ContactSearch(sys::Ser
    }
}

bool DBServiceAPI::NotesAdd(sys::Service *serv, const NotesRecord &rec)
{
    std::shared_ptr<DBNotesMessage> msg = std::make_shared<DBNotesMessage>(MessageType::DBNotesAdd, rec);

    auto ret                              = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBNotesResponseMessage *notesResponse = reinterpret_cast<DBNotesResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (notesResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::NotesRemove(sys::Service *serv, uint32_t id)
{
    std::shared_ptr<DBNotesMessage> msg = std::make_shared<DBNotesMessage>(MessageType::DBNotesRemove);
    msg->id                             = id;

    auto ret                              = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBNotesResponseMessage *notesResponse = reinterpret_cast<DBNotesResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (notesResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::NotesUpdate(sys::Service *serv, const NotesRecord &rec)
{
    std::shared_ptr<DBNotesMessage> msg = std::make_shared<DBNotesMessage>(MessageType::DBNotesUpdate, rec);

    auto ret                              = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBNotesResponseMessage *notesResponse = reinterpret_cast<DBNotesResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (notesResponse->retCode == true)) {
        return true;
    }
    else {
        return false;
    }
}

uint32_t DBServiceAPI::NotesGetCount(sys::Service *serv)
{
    std::shared_ptr<DBNotesMessage> msg = std::make_shared<DBNotesMessage>(MessageType::DBNotesGetCount);

    auto ret                              = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    DBNotesResponseMessage *notesResponse = reinterpret_cast<DBNotesResponseMessage *>(ret.second.get());
    if ((ret.first == sys::ReturnCodes::Success) && (notesResponse->retCode == true)) {
        return notesResponse->count;
    }
    else {
        return false;
    }
}

bool DBServiceAPI::NotesGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit)
{
    std::shared_ptr<DBNotesMessage> msg = std::make_shared<DBNotesMessage>(MessageType::DBNotesGetLimitOffset);
    msg->offset                         = offset;
    msg->limit                          = limit;

    sys::Bus::SendUnicast(msg, service::name::db, serv);
    return true;
}

CalllogRecord DBServiceAPI::CalllogAdd(sys::Service *serv, const CalllogRecord &rec)
{
    std::shared_ptr<DBCalllogMessage> msg = std::make_shared<DBCalllogMessage>(MessageType::DBCalllogAdd, rec);


@@ 738,24 386,3 @@ bool DBServiceAPI::DBBackup(sys::Service *serv, std::string backupPath)
        return false;
    }
}

std::unique_ptr<utils::PhoneNumber::View> DBServiceAPI::GetNumberById(sys::Service *serv,
                                                                      std::uint32_t numberId,
                                                                      std::uint32_t timeout)
{
    auto [code, msg] = DBServiceAPI::GetQueryWithReply(
        serv, db::Interface::Name::Contact, std::make_unique<db::query::NumberGetByID>(numberId), timeout);

    if (code == sys::ReturnCodes::Success && msg != nullptr) {
        auto queryResponse = dynamic_cast<db::QueryResponse *>(msg.get());
        assert(queryResponse != nullptr);

        auto numberResponse = queryResponse->getResult();
        auto numberResult   = dynamic_cast<db::query::NumberGetByIDResult *>(numberResponse.get());
        assert(numberResult != nullptr);

        return std::make_unique<utils::PhoneNumber::View>(std::move(numberResult->getNumber()));
    }

    return nullptr;
}

M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +3 -1
@@ 532,7 532,9 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::

sys::ReturnCodes ServiceDB::InitHandler()
{
    Database::initialize();
    if (const auto isSuccess = Database::initialize(); !isSuccess) {
        return sys::ReturnCodes::Failure;
    }

    // Create databases
    contactsDB      = std::make_unique<ContactsDB>((purefs::dir::getUserDiskPath() / "contacts.db").c_str());

M module-services/service-db/agents/file_indexer/FileIndexerAgent.hpp => module-services/service-db/agents/file_indexer/FileIndexerAgent.hpp +2 -0
@@ 6,6 6,8 @@
#include <service-db/DatabaseAgent.hpp>
#include <service-db/FileIndexerMessages.hpp>

#include <set>

class FileIndexerAgent : public DatabaseAgent
{
  public:

M module-services/service-db/service-db/DBServiceAPI.hpp => module-services/service-db/service-db/DBServiceAPI.hpp +0 -48
@@ 50,45 50,12 @@ class DBServiceAPI
        noError
    };

    /**
     * @brief Function is adding new SMS to SMSDB.
     * @param serv Pointer to Service based object that is sending request.
     * @param rec Record to add.
     * @return dbID of added record.
     */
    static uint32_t SMSAdd(sys::Service *serv, const SMSRecord &rec);
    static bool SMSRemove(sys::Service *serv, const SMSRecord &rec);
    static bool SMSUpdate(sys::Service *serv, const SMSRecord &rec);
    static std::unique_ptr<std::vector<SMSRecord>> SMSGetLimitOffset(sys::Service *serv,
                                                                     uint32_t offset,
                                                                     uint32_t limit);
    static std::unique_ptr<std::vector<SMSRecord>> SMSGetLimitOffsetByThreadID(sys::Service *serv,
                                                                               uint32_t offset,
                                                                               uint32_t limit,
                                                                               uint32_t id);
    static uint32_t SMSGetCount(sys::Service *serv);
    /**
     * @brief Function is getting last modified SMS record.
     * @param serv Pointer to Service based object that is sending request.
     * @return record.
     */
    static SMSRecord SMSGetLastRecord(sys::Service *serv);

    static std::unique_ptr<ThreadRecord> ThreadGet(sys::Service *serv, uint32_t id);
    static std::unique_ptr<ThreadRecord> ThreadGetByContact(sys::Service *serv, uint32_t contactID);
    static std::unique_ptr<ThreadRecord> ThreadGetByNumber(sys::Service *serv,
                                                           const utils::PhoneNumber::View &phoneNumber,
                                                           std::uint32_t timeout = DefaultTimeoutInMs);
    static bool ThreadRemove(sys::Service *serv, uint32_t id);
    static bool ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit);
    static uint32_t ThreadGetCount(sys::Service *serv, EntryState state = EntryState::ALL);
    static bool ThreadUpdate(sys::Service *serv, const ThreadRecord &rec);

    static bool SMSTemplateAdd(sys::Service *serv, const SMSTemplateRecord &rec);
    static bool SMSTemplateRemove(sys::Service *serv, uint32_t id);
    static bool SMSTemplateUpdate(sys::Service *serv, const SMSTemplateRecord &rec);
    static uint32_t SMSTemplateGetCount(sys::Service *serv);
    static bool SMSTemplateGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit);
    static auto GetQuery(sys::Service *serv, db::Interface::Name database, std::unique_ptr<db::Query> query) -> bool;
    static sys::SendResult GetQueryWithReply(sys::Service *serv,
                                             db::Interface::Name database,


@@ 110,9 77,6 @@ class DBServiceAPI
     */
    static ContactVerificationError verifyContact(sys::Service *serv, const ContactRecord &rec);
    static std::string getVerificationErrorString(const ContactVerificationError err);
    static std::unique_ptr<std::vector<ContactRecord>> ContactGetByName(sys::Service *serv,
                                                                        UTF8 primaryName,
                                                                        UTF8 alternativeName);
    static std::unique_ptr<std::vector<ContactRecord>> ContactGetByID(sys::Service *serv, uint32_t contactID);
    static std::unique_ptr<std::vector<ContactRecord>> ContactGetByIDWithTemporary(sys::Service *serv,
                                                                                   uint32_t contactID);


@@ 137,22 101,10 @@ class DBServiceAPI
    static bool ContactAdd(sys::Service *serv, const ContactRecord &rec);
    static bool ContactRemove(sys::Service *serv, uint32_t id);
    static bool ContactUpdate(sys::Service *serv, const ContactRecord &rec);
    static bool ContactBlock(sys::Service *serv, uint32_t id, const bool shouldBeBlocked = true);
    static uint32_t ContactGetCount(sys::Service *serv, bool favourites = false);
    static bool ContactGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit);
    static std::unique_ptr<std::vector<ContactRecord>> ContactSearch(sys::Service *serv,
                                                                     UTF8 primaryName,
                                                                     UTF8 alternativeName,
                                                                     UTF8 number);
    static std::unique_ptr<utils::PhoneNumber::View> GetNumberById(sys::Service *serv,
                                                                   std::uint32_t numberId,
                                                                   std::uint32_t timeout = DefaultTimeoutInMs);

    static bool NotesAdd(sys::Service *serv, const NotesRecord &rec);
    static bool NotesRemove(sys::Service *serv, uint32_t id);
    static bool NotesUpdate(sys::Service *serv, const NotesRecord &rec);
    static uint32_t NotesGetCount(sys::Service *serv);
    static bool NotesGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit);

    static CalllogRecord CalllogAdd(sys::Service *serv, const CalllogRecord &rec);
    static bool CalllogRemove(sys::Service *serv, uint32_t id);

M module-services/service-desktop/WorkerDesktop.cpp => module-services/service-desktop/WorkerDesktop.cpp +7 -10
@@ 57,30 57,27 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)
    const auto &qname = queue->GetQueueName();

    LOG_INFO("handleMessage received data from queue: %s", qname.c_str());

    static std::string *sendMsg = nullptr;
    static std::string receivedMsg;

    if (qname == sdesktop::RECEIVE_QUEUE_BUFFER_NAME) {
        if (!queue->Dequeue(&receivedMsg, 0)) {
            LOG_ERROR("handleMessage failed to receive from \"%s\"", sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
            return false;
        }
        else {
            parser.processMessage(receivedMsg);
        }
        parser.processMessage(receivedMsg);
    }
    else if (qname == sdesktop::SEND_QUEUE_BUFFER_NAME) {
        if (!queue->Dequeue(&sendMsg, 0)) {
            LOG_ERROR("handleMessage xQueueReceive failed for %s size %d bytes",
                      sdesktop::SEND_QUEUE_BUFFER_NAME,
                      static_cast<unsigned int>(sendMsg->length()));
            LOG_ERROR("handleMessage xQueueReceive failed for %s.", sdesktop::SEND_QUEUE_BUFFER_NAME);
            return false;
        }
        else {
            LOG_DEBUG("handeMessage sending %d bytes using usbCDCSend", static_cast<unsigned int>(sendMsg->length()));
        }

        LOG_DEBUG("handeMessage sending %d bytes using usbCDCSend", static_cast<unsigned int>(sendMsg->length()));
        bsp::usbCDCSend(sendMsg);

        delete sendMsg;
        sendMsg = nullptr;
    }
    else {
        LOG_INFO("handeMessage got message on an unhandled queue");

M module-services/service-gui/Common.hpp => module-services/service-gui/Common.hpp +2 -2
@@ 5,5 5,5 @@

namespace service::name
{
    constexpr char gui[] = "ServiceGUI";
};
    constexpr inline auto gui = "ServiceGUI";
}

M module-services/service-gui/ServiceGUI.cpp => module-services/service-gui/ServiceGUI.cpp +2 -2
@@ 43,7 43,7 @@ namespace sgui
    ServiceGUI::ServiceGUI(const std::string &name, std::string parent, uint32_t screenWidth, uint32_t screenHeight)
        : sys::Service(name, parent, 4096, sys::ServicePriority::Idle), renderContext{nullptr},
          transferContext{nullptr}, renderFrameCounter{1}, transferedFrameCounter{0}, screenWidth{screenWidth},
          screenHeight{screenHeight}, semCommands{NULL}, worker{nullptr}
          screenHeight{screenHeight}, semCommands{NULL}
    {

        LOG_INFO("[ServiceGUI] Initializing");


@@ 117,7 117,7 @@ namespace sgui
        }
        xSemaphoreGive(semCommands);

        worker = new WorkerGUI(this);
        worker = std::make_unique<WorkerGUI>(this);
        std::list<sys::WorkerQueueInfo> list;
        worker->init(list);
        worker->run();

M module-services/service-gui/ServiceGUI.hpp => module-services/service-gui/ServiceGUI.hpp +1 -1
@@ 63,7 63,7 @@ namespace sgui
        // semaphore used to protect commands vector while commands are taken from service to worker.
        SemaphoreHandle_t semCommands;

        WorkerGUI *worker;
        std::unique_ptr<WorkerGUI> worker;

        /**
         * Flag controls process of redrawing screen when suspend is in progress.

M module-sys/Service/Service.cpp => module-sys/Service/Service.cpp +5 -2
@@ 79,10 79,13 @@ namespace sys
    void Service::Run()
    {
        while (enableRunLoop) {
            auto msg           = mailbox.pop();
            uint32_t timestamp = cpp_freertos::Ticks::GetTicks();
            auto msg = mailbox.pop();
            if (!msg) {
                continue;
            }

            // Remove all staled messages
            uint32_t timestamp = cpp_freertos::Ticks::GetTicks();
            staleUniqueMsg.erase(std::remove_if(staleUniqueMsg.begin(),
                                                staleUniqueMsg.end(),
                                                [&](const auto &id) {

M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +6 -2
@@ 51,8 51,9 @@ namespace sys

        // in shutdown we need to wait till event manager tells us that it's ok to stfu
        while (state == State::Running) {
            auto msg = mailbox.pop();
            msg->Execute(this);
            if (auto msg = mailbox.pop(); msg) {
                msg->Execute(this);
            }
        }

        while (state == State::Shutdown) {


@@ 63,6 64,9 @@ namespace sys
            else {
                // await from EvtManager for info that red key was pressed / timeout
                auto msg = mailbox.pop();
                if (!msg) {
                    continue;
                }
                if (msg->sender != service::name::evt_manager) {
                    LOG_ERROR("Ignored msg from: %s on shutdown", msg->sender.c_str());
                    continue;