~aleteoryx/muditaos

8222ab528ded901b42f7fc5fc0976c0c92596359 — Maciej Gibowicz 2 years ago 6ed82f3
[BH-1733] Add Harmony version information

In the Settings->About section, we will have information
about which version of Harmony the user has.

co-author @Lefucjusz
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 20,6 20,7 @@
* Added possibility to detect device's case colour
* Added extended information to crashdump filename
* Added extended information to log filename
* Added Harmony version information in about section

### Changed / Improved


M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +1 -1
@@ 63,7 63,7 @@
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_serial_number": "Seriennummer",
    "app_bell_settings_about_info_title": "Handbuch & Zertifikat-Info",
    "app_bell_settings_about_product": "Mudita Harmony",
    "app_bell_settings_about_product": "Harmony",
    "app_bell_settings_about_storage_text": "<text>Verbraucht <token>$USED_MEMORY</token>MB von <token>$TOTAL_MEMORY</token>MB</text>",
    "app_bell_settings_about_storage_title": "Speicher",
    "app_bell_settings_about_version": "<text>OS-Version: <token>$VERSION</token></text>",

M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +1 -1
@@ 97,7 97,7 @@
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_serial_number": "Serial number",
    "app_bell_settings_about_info_title": "Manual & certification info",
    "app_bell_settings_about_product": "Mudita Harmony",
    "app_bell_settings_about_product": "Harmony",
    "app_bell_settings_about_storage_text": "<text><token>$USED_MEMORY</token>MB of <token>$TOTAL_MEMORY</token>MB used</text>",
    "app_bell_settings_about_storage_title": "Storage",
    "app_bell_settings_about_version": "<text>OS version: <token>$VERSION</token></text>",

M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +1 -1
@@ 62,7 62,7 @@
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_serial_number": "Número de serie",
    "app_bell_settings_about_info_title": "Manual y certificaci\u00f3n",
    "app_bell_settings_about_product": "Mudita Harmony",
    "app_bell_settings_about_product": "Harmony",
    "app_bell_settings_about_storage_text": "<text>Usados <token>$USED_MEMORY</token>MB de <token>$TOTAL_MEMORY</token>MB</text>",
    "app_bell_settings_about_storage_title": "Almacenamiento",
    "app_bell_settings_about_version": "<text>Versi\u00f3n del SO: <token>$VERSION</token></text>",

M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +1 -1
@@ 64,7 64,7 @@
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_serial_number": "Numéro de série",
    "app_bell_settings_about_info_title": "Manuel et certification",
    "app_bell_settings_about_product": "Mudita Harmony",
    "app_bell_settings_about_product": "Harmony",
    "app_bell_settings_about_storage_text": "<text><token>$USED_MEMORY</token> Mo sur <token>$TOTAL_MEMORY</token> Mo utilis\u00e9s</text>",
    "app_bell_settings_about_storage_title": "Stockage",
    "app_bell_settings_about_version": "<text>Version du syst\u00e8me: <token>$VERSION</token></text>",

M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +1 -1
@@ 63,7 63,7 @@
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_serial_number": "Numer seryjny",
    "app_bell_settings_about_info_title": "Instrukcja i informacje dot. certyfikacji",
    "app_bell_settings_about_product": "Mudita Harmony",
    "app_bell_settings_about_product": "Harmony",
    "app_bell_settings_about_storage_text": "<text>Zu\u017cyto <token>$USED_MEMORY</token>MB z <token>$TOTAL_MEMORY</token>MB</text>",
    "app_bell_settings_about_storage_title": "Pami\u0119\u0107",
    "app_bell_settings_about_version": "<text>Wersja OS: <token>$VERSION</token></text>",

M module-services/service-db/test/lang/English.json => module-services/service-db/test/lang/English.json +1 -1
@@ 644,7 644,7 @@
  "app_bell_settings_language": "Language",
  "app_bell_settings_layout": "Clock face",
  "app_bell_settings_about": "About",
  "app_bell_settings_about_product": "Mudita Harmony",
  "app_bell_settings_about_product": "Harmony",
  "app_bell_settings_about_version": "<text>OS version: <token>$VERSION</token></text>",
  "app_bell_settings_about_storage_title": "Storage",
  "app_bell_settings_about_storage_text": "<text><token>$USED_MEMORY</token>MB of <token>$TOTAL_MEMORY</token>MB used</text>",

M products/BellHybrid/apps/application-bell-settings/models/AboutYourBellModel.cpp => products/BellHybrid/apps/application-bell-settings/models/AboutYourBellModel.cpp +9 -4
@@ 15,6 15,7 @@
namespace
{
    constexpr auto factoryDataSerialPath = "factory_data/serial";
    constexpr auto factoryDataVersionPath = "factory_data/device_version";
}

namespace app::bell_settings


@@ 48,14 49,18 @@ namespace app::bell_settings

    void AboutYourBellModel::createData()
    {
        const auto productSerialNumber = settings.getValue(factoryDataSerialPath, settings::SettingsScope::Global);
        const auto productVersion      = settings.getValue(factoryDataVersionPath, settings::SettingsScope::Global);
        const auto productName =
            utils::translate("app_bell_settings_about_product") + std::string(" ") + productVersion;

        internalData.push_back(
            new gui::AboutYourBellListItem(utils::translate("app_bell_settings_about_product"),
            new gui::AboutYourBellListItem(productName,
                                           utils::translate("app_bell_settings_about_version"),
                                           gui::AboutYourBellListItem::TokenMap({{"$VERSION", std::string(VERSION)}})));

        internalData.push_back(
            new gui::AboutYourBellListItem(utils::translate("app_bell_settings_about_serial_number"),
                                           settings.getValue(factoryDataSerialPath, settings::SettingsScope::Global)));
        internalData.push_back(new gui::AboutYourBellListItem(utils::translate("app_bell_settings_about_serial_number"),
                                                              productSerialNumber));

#if CONFIG_SHOW_MEMORY_INFO == 1
        struct statvfs stat

M products/BellHybrid/serial-number-parser/CMakeLists.txt => products/BellHybrid/serial-number-parser/CMakeLists.txt +5 -0
@@ 4,6 4,7 @@ add_library(serial-number-parser STATIC)
target_sources(serial-number-parser
    PUBLIC
        SerialNumberParser.cpp
        DeviceMetadata.cpp
)

target_include_directories(serial-number-parser


@@ 15,3 16,7 @@ target_link_libraries(serial-number-parser
    PRIVATE
    module-vfs
)

if (${ENABLE_TESTS})
    add_subdirectory(tests)
endif ()

A products/BellHybrid/serial-number-parser/DeviceMetadata.cpp => products/BellHybrid/serial-number-parser/DeviceMetadata.cpp +60 -0
@@ 0,0 1,60 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <serial-number-parser/DeviceMetadata.hpp>
#include <serial-number-parser/SerialNumberParser.hpp>
#include <purefs/vfs_subsystem.hpp>
#include <log/log.hpp>

namespace serial_number_parser
{
    namespace
    {
        /* Block device constants */
        constexpr auto blkdevName  = "emmc0sys1";
        constexpr auto blockSize   = 512;
        constexpr auto blockToRead = 2;
        constexpr auto blocksCount = 1;

        constexpr auto serialNumberOffset = 0;
        constexpr auto serialNumberLength = 13;

        const auto unknownVersionMetadata = VersionMetadata(unknownColour, unknownVersion);
        const auto unknownDeviceMetadata  = DeviceMetadata(unknownSerialNumber, unknownVersionMetadata);

        std::string readSerialNumber()
        {
            char block[blockSize];

            const auto diskManager = purefs::subsystem::disk_mgr();
            if (diskManager == nullptr) {
                return "";
            }

            const auto status = diskManager->read(blkdevName, block, blockToRead, blocksCount);
            if (status != 0) {
                return "";
            }

            return std::string(&block[serialNumberOffset], serialNumberLength);
        }
    } // namespace

    DeviceMetadata getDeviceMetadata()
    {
        const auto serialNumber = readSerialNumber();
        if (serialNumber.empty()) {
            LOG_ERROR("Error reading serial number from eMMC!");
            return unknownDeviceMetadata;
        }

        const auto deviceVersionMetadata = getDeviceVersionMetadata(serialNumber);
        if (!deviceVersionMetadata.has_value()) {
            LOG_ERROR("Failed to read device version metadata for device with serial number '%s'!",
                      serialNumber.c_str());
            return DeviceMetadata(serialNumber, unknownVersionMetadata);
        }

        return DeviceMetadata(serialNumber, deviceVersionMetadata.value());
    }
} // namespace serial_number_parser

M products/BellHybrid/serial-number-parser/SerialNumberParser.cpp => products/BellHybrid/serial-number-parser/SerialNumberParser.cpp +28 -71
@@ 2,9 2,9 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <serial-number-parser/SerialNumberParser.hpp>
#include <purefs/vfs_subsystem.hpp>
#include <Utils.hpp>
#include <cstring>
#include <map>

/*
 * Old SN is in MMYYWWNNNNNNN form, where:


@@ 30,89 30,46 @@ namespace serial_number_parser
{
    namespace
    {
        /* Block device constants */
        constexpr auto blkdevName  = "emmc0sys1";
        constexpr auto blockSize   = 512;
        constexpr auto blockToRead = 2;
        constexpr auto blocksCount = 1;

        /* Common constants */
        constexpr auto serialNumberOffset  = 0;
        constexpr auto serialNumberLength  = 13;
        constexpr auto unknownSerialNumber = "0000000000000";
        constexpr auto unknownColour       = "unknown";

        /* Old serial number constants */
        constexpr auto idStringOffset = 0;
        constexpr auto idStringLength = 6;

        /* ID string to colour map for already released batches */
        const std::map<std::string, std::string> idStringToColourMap{
            {"042148", "gray"}, {"042213", "gray"}, {"042242", "black"}};
        /* ID string to version metadata map for already released batches */
        const std::map<std::string, VersionMetadata> idStringToVersionInfoMap{
            {"042148", VersionMetadata(grayColor, firstVersion)},
            {"042213", VersionMetadata(grayColor, firstVersion)},
            {"042242", VersionMetadata(blackColor, secondVersion)}};

        /* New serial number constants */
        constexpr auto colourCodeOffset = 4;
        const std::map<char, std::string> colourCodeToColourMap{{'G', "gray"}, {'B', "black"}};

        bool isOldSerialNumberFormat(const std::string &serialNumber)
        {
            return (serialNumber.find_first_not_of("0123456789") == std::string::npos);
        }

        std::string readSerialNumber()
        {
            char block[blockSize];
        const std::map<char, std::string> colourCodeToColourMap{{'G', grayColor}, {'B', blackColor}};
    } // namespace

            const auto diskManager = purefs::subsystem::disk_mgr();
            if (diskManager == nullptr) {
                return "";
            }
    bool isOldSerialNumberFormat(const std::string &serialNumber)
    {
        return (serialNumber.find_first_not_of("0123456789") == std::string::npos);
    }

            const auto status = diskManager->read(blkdevName, block, blockToRead, blocksCount);
            if (status != 0) {
                return "";
    std::optional<VersionMetadata> getDeviceVersionMetadata(const std::string &serialNumber)
    {
        if (isOldSerialNumberFormat(serialNumber)) {
            LOG_INFO("Device has old serial number format");
            const auto idString = serialNumber.substr(idStringOffset, idStringLength);
            const auto item     = idStringToVersionInfoMap.find(idString);
            if (item == idStringToVersionInfoMap.end()) {
                return std::nullopt;
            }

            return std::string(&block[serialNumberOffset], serialNumberLength);
            return item->second;
        }

        std::string getDeviceColour(const std::string &serialNumber)
        {
            if (isOldSerialNumberFormat(serialNumber)) {
                LOG_INFO("Device has old serial number format");
                const auto idString = serialNumber.substr(idStringOffset, idStringLength);
                const auto item     = idStringToColourMap.find(idString);
                if (item == idStringToColourMap.end()) {
                    return "";
                }
                return item->second;
            }
            else {
                LOG_INFO("Device has new serial number format");
                const auto colourCode = serialNumber[colourCodeOffset];
                const auto item       = colourCodeToColourMap.find(colourCode);
                if (item == colourCodeToColourMap.end()) {
                    return "";
                }
                return item->second;
        else {
            LOG_INFO("Device has new serial number format");
            const auto colourCode = serialNumber[colourCodeOffset];
            const auto item       = colourCodeToColourMap.find(colourCode);
            if (item == colourCodeToColourMap.end()) {
                return std::nullopt;
            }
        }
    } // namespace

    std::pair<std::string, std::string> getDeviceMetadata()
    {
        const auto serialNumber = readSerialNumber();
        if (serialNumber.empty()) {
            LOG_ERROR("Error reading serial number from eMMC!");
            return {unknownSerialNumber, unknownColour};
        }

        const auto deviceColour = getDeviceColour(serialNumber);
        if (deviceColour.empty()) {
            LOG_ERROR("Failed to read colour for device with serial number '%s'!", serialNumber.c_str());
            return {serialNumber, unknownColour};
            return VersionMetadata(item->second, secondVersion);
        }

        return {serialNumber, deviceColour};
    }
} // namespace serial_number_parser

A products/BellHybrid/serial-number-parser/include/serial-number-parser/Common.hpp => products/BellHybrid/serial-number-parser/include/serial-number-parser/Common.hpp +24 -0
@@ 0,0 1,24 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <string>

namespace serial_number_parser
{
    constexpr auto grayColor     = "gray";
    constexpr auto blackColor    = "black";
    constexpr auto unknownColour = "unknown";

    constexpr auto unknownSerialNumber = "0000000000000";

    constexpr auto firstVersion   = 1;
    constexpr auto secondVersion  = 2;
    constexpr auto unknownVersion = 0;

    using SerialNumber    = std::string;
    using CaseColor       = std::string;
    using VersionNumber   = unsigned;
    using VersionMetadata = std::pair<CaseColor, VersionNumber>;
    using DeviceMetadata  = std::pair<SerialNumber, VersionMetadata>;
} // namespace serial_number_parser

A products/BellHybrid/serial-number-parser/include/serial-number-parser/DeviceMetadata.hpp => products/BellHybrid/serial-number-parser/include/serial-number-parser/DeviceMetadata.hpp +10 -0
@@ 0,0 1,10 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "Common.hpp"

namespace serial_number_parser
{
    DeviceMetadata getDeviceMetadata();
} // namespace serial_number_parser

M products/BellHybrid/serial-number-parser/include/serial-number-parser/SerialNumberParser.hpp => products/BellHybrid/serial-number-parser/include/serial-number-parser/SerialNumberParser.hpp +4 -2
@@ 2,9 2,11 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <string>
#include "Common.hpp"
#include <optional>

namespace serial_number_parser
{
    std::pair<std::string, std::string> getDeviceMetadata();
    bool isOldSerialNumberFormat(const std::string &serialNumber);
    std::optional<VersionMetadata> getDeviceVersionMetadata(const std::string &serialNumber);
} // namespace serial_number_parser

A products/BellHybrid/serial-number-parser/tests/CMakeLists.txt => products/BellHybrid/serial-number-parser/tests/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
add_catch2_executable(
        NAME
        bell-serial-number-parser
        SRCS
        test-BellSerialNumberParser.cpp
        LIBS
        serial-number-parser
        INCLUDE
        $<TARGET_PROPERTY:serial-number-parser,INCLUDE_DIRECTORIES>
)

A products/BellHybrid/serial-number-parser/tests/test-BellSerialNumberParser.cpp => products/BellHybrid/serial-number-parser/tests/test-BellSerialNumberParser.cpp +99 -0
@@ 0,0 1,99 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include <serial-number-parser/SerialNumberParser.hpp>

namespace
{
    namespace oldSerialNumbers
    {
        std::string grey1_FirstVersion{"0421481234567"};
        std::string grey2_FirstVersion{"0422131234567"};
        std::string black_SecondVersion{"0422421234567"};
        std::string invalidNumber{"0123456789123"};
    } // namespace oldSerialNumbers
    namespace newSerialNumbers
    {
        std::string grey_SecondVersion{"04P1G23091234"};
        std::string black_SecondVersion{"04P1B23091234"};
        std::string invalidNumber{"0123456789123"};
        std::string invalidColor{"04P1R23091234"};
    } // namespace newSerialNumbers

} // namespace

TEST_CASE("Serial number format")
{
    SECTION("Check old serial numbers")
    {
        CHECK(serial_number_parser::isOldSerialNumberFormat(oldSerialNumbers::grey1_FirstVersion));
        CHECK(serial_number_parser::isOldSerialNumberFormat(oldSerialNumbers::grey2_FirstVersion));
        CHECK(serial_number_parser::isOldSerialNumberFormat(oldSerialNumbers::black_SecondVersion));
    }
    SECTION("Check new serial numbers")
    {
        CHECK(not serial_number_parser::isOldSerialNumberFormat(newSerialNumbers::grey_SecondVersion));
        CHECK(not serial_number_parser::isOldSerialNumberFormat(newSerialNumbers::black_SecondVersion));
    }
}

TEST_CASE("Serial number metadata")
{
    SECTION("Check case color")
    {
        SECTION("Case color for valid serial numbers")
        {
            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey1_FirstVersion).has_value());
            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey1_FirstVersion).value().first ==
                  serial_number_parser::grayColor);

            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey2_FirstVersion).has_value());
            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey2_FirstVersion).value().first ==
                  serial_number_parser::grayColor);

            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::black_SecondVersion).has_value());
            CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::black_SecondVersion).value().first ==
                  serial_number_parser::blackColor);

            CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::grey_SecondVersion).has_value());
            CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::grey_SecondVersion).value().first ==
                  serial_number_parser::grayColor);

            CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::black_SecondVersion).has_value());
            CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::black_SecondVersion).value().first ==
                  serial_number_parser::blackColor);
        }
        SECTION("Case color for invalid serial numbers")
        {
            CHECK(not serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::invalidColor).has_value());
        }
    }
    SECTION("Check Harmony version")
    {
        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey1_FirstVersion).has_value());
        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey1_FirstVersion).value().second ==
              serial_number_parser::firstVersion);

        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey2_FirstVersion).has_value());
        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::grey2_FirstVersion).value().second ==
              serial_number_parser::firstVersion);

        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::black_SecondVersion).has_value());
        CHECK(serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::black_SecondVersion).value().second ==
              serial_number_parser::secondVersion);

        CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::grey_SecondVersion).has_value());
        CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::grey_SecondVersion).value().second ==
              serial_number_parser::secondVersion);

        CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::black_SecondVersion).has_value());
        CHECK(serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::black_SecondVersion).value().second ==
              serial_number_parser::secondVersion);
    }
    SECTION("Check invalid serial numbers")
    {
        CHECK(not serial_number_parser::getDeviceVersionMetadata(oldSerialNumbers::invalidNumber).has_value());
        CHECK(not serial_number_parser::getDeviceVersionMetadata(newSerialNumbers::invalidNumber).has_value());
    }
}

M products/BellHybrid/services/db/BellFactorySettings.cpp => products/BellHybrid/services/db/BellFactorySettings.cpp +5 -3
@@ 5,17 5,19 @@
#include <log/log.hpp>
#include <service-db/SettingsMessages.hpp>
#include <service-db/agents/settings/Settings_queries.hpp>
#include <serial-number-parser/SerialNumberParser.hpp>
#include <serial-number-parser/DeviceMetadata.hpp>

namespace settings
{
    auto BellFactorySettings::getMfgEntries() const -> std::unique_ptr<QueryResult>
    {
        const auto [serialNumber, colour] = serial_number_parser::getDeviceMetadata();
        auto factoryData                  = std::make_unique<QueryResult>();
        const auto [serialNumber, deviceVersionMetadata] = serial_number_parser::getDeviceMetadata();
        const auto [colour, version]                     = deviceVersionMetadata;
        auto factoryData                                 = std::make_unique<QueryResult>();

        factoryData->addRow({Field(factory::serial_number_key), Field(serialNumber.c_str())});
        factoryData->addRow({Field(factory::case_colour_key), Field(colour.c_str())});
        factoryData->addRow({Field(factory::device_version_key), Field(std::to_string(version).c_str())});

        return factoryData;
    }

M products/BellHybrid/services/db/include/db/BellFactorySettings.hpp => products/BellHybrid/services/db/include/db/BellFactorySettings.hpp +5 -0
@@ 11,6 11,11 @@

namespace settings
{
    namespace factory
    {
        static constexpr auto device_version_key = "device_version";
    }

    class BellFactorySettings : public FactorySettings
    {
      public: