~aleteoryx/muditaos

84f2dc4f02246b6556466c802ec21d595009655d — Wojtek Rzepecki 5 years ago f554354
[EGD-5346] Refactor of battery charger BSP

Pure refactoring of battery charger to privide compliance
 with modern C++ standards. Done before implementation of
battery charging algorithms.
M module-bsp/board/linux/battery-charger/battery_charger.cpp => module-bsp/board/linux/battery-charger/battery_charger.cpp +81 -95
@@ 1,21 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

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

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

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


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

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

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

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

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

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

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

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

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

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

    static void battery_worker(void *pvp);

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

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

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

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

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

    static void battery_worker(void *pvp)
    {

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

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

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

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

            if (readedBytes > 0) {

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

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

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

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

namespace bsp::battery_charger
{

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

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

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

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

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

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

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

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

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

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

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

} // namespace bsp::battery_charger

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

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

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

#include "bsp/battery-charger/battery_charger.hpp"
#include "MAX77818.hpp"
#include "vfs.hpp"

#include "bsp/BoardDefinitions.hpp"
#include "common_data/EventStore.hpp"
#include "drivers/gpio/DriverGPIO.hpp"
#include "drivers/i2c/DriverI2C.hpp"
#include <cstdio>
#include <purefs/filesystem_paths.hpp>
#include <utility>

#define BSP_BATTERY_CHARGER_I2C_ADDR (0xD2 >> 1)
#define BSP_FUEL_GAUGE_I2C_ADDR      (0x6C >> 1)
#define BSP_TOP_CONTROLLER_I2C_ADDR  (0xCC >> 1)
namespace bsp::battery_charger
{
    namespace
    {
        constexpr std::uint32_t i2cSubaddresSize = 1;

static const uint32_t i2cSubaddresSize = 1;
        const auto cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
        const auto cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";

namespace configs
{
    const auto battery_cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
    const auto battery_cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";
} // namespace configs
        constexpr std::uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
            0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
        constexpr std::uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
            0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
        constexpr std::uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
            0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
        constexpr std::uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
            0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
        constexpr std::uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;

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

static const uint16_t battery_nominalCapacitymAh = 3000;
        constexpr std::uint16_t nominalCapacitymAh = 3000;

static const uint8_t battery_fullyChargedPercent = 100;
static const uint8_t battery_DischargedPercent   = 15;
        constexpr std::uint8_t fullyChargedPercent = 100;
        constexpr std::uint8_t DischargedPercent   = 15;

static const uint8_t battery_maxTemperatureDegrees = 50;
static const uint8_t battery_minTemperatureDegrees = 5;
        constexpr std::uint8_t maxTemperatureDegrees = 50;
        constexpr std::uint8_t minTemperatureDegrees = 5;

static constexpr inline uint16_t battery_maxVoltagemV = 4200;
static constexpr inline uint16_t battery_minVoltagemV = 3600;
        constexpr std::uint16_t maxVoltagemV = 4200;
        constexpr std::uint16_t minVoltagemV = 3600;

using namespace drivers;
        std::shared_ptr<drivers::DriverI2C> i2c;
        std::shared_ptr<drivers::DriverGPIO> gpio;

static std::shared_ptr<drivers::DriverI2C> i2c;
static std::shared_ptr<drivers::DriverGPIO> gpio;
        drivers::I2CAddress fuelGaugeAddress      = {FUEL_GAUGE_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress batteryChargerAddress = {BATTERY_CHARGER_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress topControllerAddress  = {TOP_CONTROLLER_I2C_ADDR, 0, i2cSubaddresSize};

static bsp::batteryRetval battery_loadConfiguration(void);
        xQueueHandle IRQQueueHandle = nullptr;

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

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

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

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

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

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

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

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

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

static bsp::batteryRetval battery_setAvgCalcPeriods(void);
            if (ret != sizeof(std::uint8_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

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

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

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

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

static bsp::batteryRetval battery_setChargingDischargingThresholds(uint8_t chargedThresholdPercent,
                                                                   uint8_t dischargedThresholdPercent);
            std::fclose(fd);
            return batteryRetval::OK;
        }

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

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

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

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

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

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

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

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

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

static void s_BSP_BatteryChargerIrqPinsInit();
        batteryRetval setChargingDischargingThresholds(std::uint8_t chargedThresholdPercent,
                                                       std::uint8_t dischargedThresholdPercent)
        {
            uint16_t regVal = (chargedThresholdPercent << 8) | dischargedThresholdPercent;

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

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

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

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

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

    uint16_t battery_get_CHG_INT_OK();

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

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

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

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

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

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

            return batteryRetval::OK;
        }

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

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

            return batteryRetval::OK;
        }

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

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

            return batteryRetval::OK;
        }

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

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

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

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

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

        qHandleIrq = qHandle;
        IRQQueueHandle = queueHandle;

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

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

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

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

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

        s_BSP_BatteryChargerIrqPinsInit();
        IRQPinsInit();

        return 0;
    }

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

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

        qHandleIrq = NULL;
        IRQQueueHandle = nullptr;

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

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

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

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

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

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

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

} // namespace bsp

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return bsp::batteryRetval::battery_OK;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return bsp::batteryRetval::battery_OK;
}

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

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

    return bsp::batteryRetval::battery_OK;
}

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

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

    return bsp::batteryRetval::battery_OK;
}

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

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

static void s_BSP_BatteryChargerIrqPinsInit()
{

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

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

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

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

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

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

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

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


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

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

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

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

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

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

#ifndef MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#define MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#pragma once

#include <cstdint>
namespace bsp{

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

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

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

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

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

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

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

	enum class batteryRetval{
		battery_OK = 0,
		battery_ChargerError,
		battery_ChargerNotCharging,
		battery_ChargerCharging
		OK,
		ChargerError,
		ChargerNotCharging,
		ChargerCharging
	};

	enum class batteryIRQSource{


@@ 107,24 33,24 @@ namespace bsp{
		SOCOnePercentChange = 1 << 7
	};

	int battery_Init(xQueueHandle qHandle);
	int init(xQueueHandle queueHandle);

	void battery_Deinit(void);
	void deinit();

	void battery_getBatteryLevel(uint8_t& levelPercent);
	StateOfCharge getBatteryLevel();

	void battery_getChargeStatus( bool& status);
	bool getChargeStatus();

	void battery_ClearAllIRQs(void);
	void clearAllIRQs();

	void battery_clearFuelGuageIRQ(void);
	void clearFuelGuageIRQ();

	std::uint16_t battery_getStatusRegister();
}
	std::uint16_t getStatusRegister();

	BaseType_t INOKB_IRQHandler();

BaseType_t BSP_BatteryChargerINOKB_IRQHandler();
	BaseType_t INTB_IRQHandler();
} // bsp::battery_charger

BaseType_t BSP_BatteryChargerINTB_IRQHandler();


#endif /* MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_*/

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +11 -14
@@ 91,28 91,25 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
        if (!queue->Dequeue(&notification, 0)) {
            return false;
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INTB)) {
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INTB)) {
            LOG_DEBUG("Battery INTB");
            const auto status = bsp::battery_getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::minVAlert)) {
            const auto status = bsp::battery_charger::getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::minVAlert)) {
                auto messageBrownout = std::make_shared<sevm::BatteryBrownoutMessage>();
                sys::Bus::SendUnicast(messageBrownout, service::name::system_manager, this->service);
            }
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::SOCOnePercentChange)) {
                std::uint8_t battLevel = 0;
                bsp::battery_getBatteryLevel(battLevel);
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::SOCOnePercentChange)) {
                bsp::battery_charger::StateOfCharge battLevel = bsp::battery_charger::getBatteryLevel();
                auto message = std::make_shared<sevm::BatteryLevelMessage>(battLevel, false);
                sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
                battery_level_check::checkBatteryLevelCritical();
            }
            bsp::battery_ClearAllIRQs();
            bsp::battery_charger::clearAllIRQs();
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INOKB)) {
            bool status;
            bsp::battery_getChargeStatus(status);
            bsp::battery_ClearAllIRQs();
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INOKB)) {
            bsp::battery_charger::clearAllIRQs();
            auto message     = std::make_shared<sevm::BatteryPlugMessage>();
            message->plugged = status;
            message->plugged = bsp::battery_charger::getChargeStatus();
            sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
        }
    }


@@ 193,7 190,7 @@ bool WorkerEvent::init(std::list<sys::WorkerQueueInfo> queuesList)
    bsp::vibrator::init();
    bsp::keyboard_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueKeyboardIRQ)]->GetQueueHandle());
    bsp::headset::Init(queues[static_cast<int32_t>(WorkerEventQueues::queueHeadsetIRQ)]->GetQueueHandle());
    bsp::battery_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::battery_charger::init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::rtc_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueRTC)]->GetQueueHandle());
    bsp::cellular::init(queues[static_cast<int32_t>(WorkerEventQueues::queueCellular)]->GetQueueHandle());
    bsp::magnetometer::init(queues[static_cast<int32_t>(WorkerEventQueues::queueMagnetometerIRQ)]->GetQueueHandle());


@@ 216,7 213,7 @@ bool WorkerEvent::deinit(void)
    Worker::deinit();
    bsp::keyboard_Deinit();
    bsp::headset::Deinit();
    bsp::battery_Deinit();
    bsp::battery_charger::deinit();
    bsp::torch::deinit();
    bsp::keypad_backlight::deinit();
    bsp::eink_frontlight::deinit();