~aleteoryx/muditaos

441b9b4667d284698f585f9302eace456861a73f — Maciej Janicki 4 years ago 659570c
[BH-715] Add switches handling

Add Bell switches handling including latch support.
M module-bsp/CMakeLists.txt => module-bsp/CMakeLists.txt +1 -0
@@ 74,6 74,7 @@ target_link_libraries(${PROJECT_NAME}
        eventstore
        module-os
        service-bluetooth
        magic_enum
        ${TARGET_LIBRARIES}
    PRIVATE
        time-constants

M module-bsp/board/linux/hal/key_input/KeyInput.cpp => module-bsp/board/linux/hal/key_input/KeyInput.cpp +1 -1
@@ 84,7 84,7 @@ namespace hal::key_input
        close(fd);
    }

    std::vector<bsp::KeyEvent> LinuxKeyInput::getKeyEvents(std::uint8_t)
    std::vector<bsp::KeyEvent> LinuxKeyInput::getKeyEvents(KeyNotificationSource)
    {
        using namespace bsp;
        KeyEvent keyEvent;

M module-bsp/board/linux/hal/key_input/KeyInput.hpp => module-bsp/board/linux/hal/key_input/KeyInput.hpp +1 -1
@@ 12,6 12,6 @@ namespace hal::key_input
      public:
        void init(xQueueHandle qHandle) final;
        void deinit() final;
        std::vector<bsp::KeyEvent> getKeyEvents(std::uint8_t) final;
        std::vector<bsp::KeyEvent> getKeyEvents(KeyNotificationSource) final;
    };
} // namespace hal::key_input

M module-bsp/board/rt1051/bellpx/CMakeLists.txt => module-bsp/board/rt1051/bellpx/CMakeLists.txt +3 -2
@@ 12,8 12,9 @@ target_sources(
    PRIVATE
        hal/temperature_source/TemperatureSource.cpp
        hal/battery_charger/BatteryCharger.cpp
	    hal/key_input/KeyInput.cpp
	    bsp/eink/eink_pin_config.cpp
        hal/key_input/KeyInput.cpp
        bsp/eink/eink_pin_config.cpp
        bsp/switches/switches.cpp
        bsp/rotary_encoder/rotary_encoder.cpp
        bsp/bell_temp_sensor/bell_temp_sensor.cpp
        pin_mux.c

M module-bsp/board/rt1051/bellpx/board/BoardDefinitions.hpp => module-bsp/board/rt1051/bellpx/board/BoardDefinitions.hpp +10 -0
@@ 143,4 143,14 @@ enum class BoardDefinitions

    BELL_TEMP_SENSOR_I2C          = static_cast<int>(drivers::I2CInstances ::I2C4),
    BELL_TEMP_SENSOR_I2C_BAUDRATE = I2C_STD_BAUDRATE,

    BELL_SWITCHES_GPIO   = static_cast<int>(drivers::GPIOInstances ::GPIO_2),
    BELL_SWITCHES_CENTER = 16, // GPIO_B1_00
    BELL_SWITCHES_LEFT   = 24, // GPIO_B1_08
    BELL_SWITCHES_RIGHT  = 25, // GPIO_B1_09
    BELL_SWITCHES_LATCH  = 26, // GPIO_B1_10
    BELL_SWITCHES_DOME   = 27, // GPIO_B1_11

    BELL_WAKEUP_GPIO = static_cast<int>(drivers::GPIOInstances ::GPIO_5),
    BELL_WAKEUP      = 0, // SNVS_WAKEUP_GPIO5_IO00
};

M module-bsp/board/rt1051/bellpx/board/pin_mux.h => module-bsp/board/rt1051/bellpx/board/pin_mux.h +8 -2
@@ 158,10 158,16 @@ extern "C"
/**
 * BELL DOME SWITCH
 */
#define PINMUX_DOME_SWITCH IOMUXC_GPIO_B0_11_GPIO2_IO11
#define PINMUX_DOME_SWITCH IOMUXC_GPIO_B1_11_GPIO2_IO27
    void PINMUX_DomeSwitch(void);

/**
 * BELL WAKEUP
 */
#define PINMUX_WAKEUP IOMUXC_SNVS_WAKEUP_GPIO5_IO00
    void PINMUX_Wakeup(void);

/**
 * BELL WDOG_B
 */
#define PINMUX_WDOG_B IOMUXC_GPIO_B1_13_GPIO2_IO29


@@ 186,4 192,4 @@ extern "C"

/***********************************************************************************************************************
 * EOF
 **********************************************************************************************************************/
\ No newline at end of file
 **********************************************************************************************************************/

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

#include <module-utils/Utils.hpp> // for byte conversion functions. it is included first because of magic enum define

#include <FreeRTOS.h>
#include <mutex.hpp>
#include <queue.h>
#include <task.h>
#include <timers.h>
#include <bsp/switches/switches.hpp>
#include <board/BoardDefinitions.hpp>
#include <board.h>
#include <fsl_common.h>

#include <chrono>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <map>
#include <vector>
#include <magic_enum.hpp>

using namespace drivers;
using namespace utils;

namespace bsp::bell_switches
{
    using namespace std::chrono_literals;

    using TimerCallback = void (*)(TimerHandle_t timerHandle);

    constexpr std::chrono::milliseconds contactOscillationTimeout{30ms};
    constexpr std::chrono::milliseconds centerKeyPressValidationTimeout{100ms};

    enum class DebounceTimerId : unsigned int
    {
        leftSideSwitch = 0,
        rightSideSwitch,
        lightCenterSwitch,
        latchSwitch,
        wakeup,
        Invalid
    };

    enum class NotificationSource : uint16_t
    {
        leftSideKeyPress      = 0x0001,
        leftSideKeyRelease    = 0x0002,
        rightSideKeyPress     = 0x0004,
        rightSideKeyRelease   = 0x0008,
        lightCenterKeyPress   = 0x0010,
        lightCenterKeyRelease = 0x0020,
        latchKeyPress         = 0x0040,
        latchKeyRelease       = 0x0080,
        wakeupEvent           = 0x0400,
        wakeupEventRelease    = 0x0800,
        Invalid               = 0xFFFF
    };

    void debounceTimerCallback(TimerHandle_t timerHandle);

    struct DebounceTimerState
    {
        const DebounceTimerId id{DebounceTimerId::Invalid};
        const NotificationSource notificationSource{NotificationSource::Invalid};
        const std::shared_ptr<drivers::DriverGPIO> gpio;
        const BoardDefinitions pin{-1};
        KeyEvents lastState{KeyEvents::Pressed};
        TimerHandle_t timer{nullptr};

        void createTimer(TimerCallback callback, const std::chrono::milliseconds timeout)
        {
            timer =
                xTimerCreate(magic_enum::enum_name(id).data(), pdMS_TO_TICKS(timeout.count()), false, this, callback);
        }
    };

    static struct LatchEventFlag
    {
      private:
        static constexpr std::chrono::milliseconds latchPressEventTimeout = 1000ms;
        cpp_freertos::MutexStandard latchFlagMutex;
        std::chrono::time_point<std::chrono::system_clock> timeOfLastLatchEvent = std::chrono::system_clock::now();
        bool pressed                                                            = false;

      public:
        void setPressed()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            pressed              = true;
            timeOfLastLatchEvent = std::chrono::system_clock::now();
        }

        void setReleased()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            pressed              = false;
            timeOfLastLatchEvent = std::chrono::system_clock::now();
        }

        bool isPressed()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            return pressed;
        }

        bool wasJustPressed()
        {
            cpp_freertos::LockGuard lock(latchFlagMutex);
            auto ret = ((std::chrono::duration_cast<std::chrono::milliseconds>(
                            std::chrono::system_clock::now() - timeOfLastLatchEvent)) <= latchPressEventTimeout);
            return ret;
        }

    } latchEventFlag;

    static std::map<DebounceTimerId, DebounceTimerState> debounceTimers;

    static xQueueHandle qHandleIrq{};
    std::shared_ptr<DriverGPIO> gpio_sw;
    std::shared_ptr<DriverGPIO> gpio_wakeup;

    void debounceTimerCallback(TimerHandle_t timerHandle)
    {
        auto timerState                     = static_cast<DebounceTimerState *>(pvTimerGetTimerID(timerHandle));
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xTimerStop(timerState->timer, 0);

        auto currentState = timerState->gpio->ReadPin(static_cast<uint32_t>(timerState->pin)) ? KeyEvents::Released
                                                                                              : KeyEvents::Pressed;

        if (currentState == timerState->lastState && qHandleIrq != nullptr) {
            if (currentState == KeyEvents::Pressed) {
                if (timerState->notificationSource == NotificationSource::latchKeyPress) {
                    latchEventFlag.setPressed();
                }
                auto val = static_cast<std::uint16_t>(timerState->notificationSource);
                xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
                timerState->lastState = KeyEvents::Released;
            }
            else {
                if (timerState->notificationSource == NotificationSource::latchKeyPress) {
                    latchEventFlag.setReleased();
                }
                // Using responding release notification source, which is one bit shifted
                auto val = (static_cast<std::uint16_t>(timerState->notificationSource) << 1);
                xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
                timerState->lastState = KeyEvents::Pressed;
            }
        }

        timerState->gpio->EnableInterrupt(1U << static_cast<uint32_t>(timerState->pin));
    }

    void debounceTimerCenterClickCallback(TimerHandle_t timerHandle)
    {
        auto timerState                     = static_cast<DebounceTimerState *>(pvTimerGetTimerID(timerHandle));
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xTimerStop(timerState->timer, 0);

        if (!latchEventFlag.wasJustPressed() && qHandleIrq != nullptr) {
            const auto currentState = timerState->gpio->ReadPin(static_cast<uint32_t>(timerState->pin))
                                          ? KeyEvents::Released
                                          : KeyEvents::Pressed;
            if (currentState != timerState->lastState) {
                auto val = static_cast<std::uint16_t>(timerState->notificationSource);
                xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
            }
        }

        timerState->gpio->EnableInterrupt(1U << static_cast<uint32_t>(timerState->pin));
    }

    void addDebounceTimer(DebounceTimerState timerState)
    {
        debounceTimers.insert({timerState.id, timerState});
        DebounceTimerState &state = debounceTimers.find(timerState.id)->second;

        if (timerState.notificationSource == NotificationSource::lightCenterKeyPress) {
            state.createTimer(debounceTimerCenterClickCallback, centerKeyPressValidationTimeout);
        }
        else {
            state.createTimer(debounceTimerCallback, contactOscillationTimeout);
        }
    }

    void configureSwitch(BoardDefinitions boardSwitch, DriverGPIOPinParams::InterruptMode mode)
    {

        gpio_sw->ClearPortInterrupts(1 << magic_enum::enum_integer(boardSwitch));
        gpio_sw->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                             .irqMode  = mode,
                                             .defLogic = 1,
                                             .pin      = static_cast<uint32_t>(boardSwitch)});
    }

    int32_t init(xQueueHandle qHandle)
    {
        qHandleIrq = qHandle;

        // Switches
        gpio_sw =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::BELL_SWITCHES_GPIO), DriverGPIOParams{});
        // wakeup
        gpio_wakeup =
            DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::BELL_WAKEUP_GPIO), DriverGPIOParams{});

        configureSwitch(BoardDefinitions::BELL_SWITCHES_LATCH,
                        DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge);
        configureSwitch(BoardDefinitions::BELL_SWITCHES_LEFT,
                        DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge);
        configureSwitch(BoardDefinitions::BELL_SWITCHES_RIGHT,
                        DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge);
        configureSwitch(BoardDefinitions::BELL_SWITCHES_CENTER, DriverGPIOPinParams::InterruptMode::IntRisingEdge);
        configureSwitch(BoardDefinitions::BELL_WAKEUP, DriverGPIOPinParams::InterruptMode::IntFallingEdge);

        addDebounceTimer(DebounceTimerState{DebounceTimerId::leftSideSwitch,
                                            NotificationSource::leftSideKeyPress,
                                            gpio_sw,
                                            BoardDefinitions::BELL_SWITCHES_LEFT});
        addDebounceTimer(DebounceTimerState{DebounceTimerId::rightSideSwitch,
                                            NotificationSource::rightSideKeyPress,
                                            gpio_sw,
                                            BoardDefinitions::BELL_SWITCHES_RIGHT});
        addDebounceTimer(DebounceTimerState{DebounceTimerId::lightCenterSwitch,
                                            NotificationSource::lightCenterKeyPress,
                                            gpio_sw,
                                            BoardDefinitions::BELL_SWITCHES_CENTER});
        addDebounceTimer(DebounceTimerState{DebounceTimerId::latchSwitch,
                                            NotificationSource::latchKeyPress,
                                            gpio_sw,
                                            BoardDefinitions::BELL_SWITCHES_LATCH,
                                            KeyEvents::Released});
        addDebounceTimer(DebounceTimerState{
            DebounceTimerId::wakeup, NotificationSource::wakeupEvent, gpio_wakeup, BoardDefinitions::BELL_WAKEUP});

        enableIRQ();

        return kStatus_Success;
    }

    std::int32_t deinit()
    {
        qHandleIrq = nullptr;
        disableIRQ();

        for (const auto &el : debounceTimers) {
            xTimerDelete(el.second.timer, 50);
        }
        debounceTimers.clear();

        gpio_sw.reset();
        gpio_wakeup.reset();

        return kStatus_Success;
    }

    void getDebounceTimer(BaseType_t xHigherPriorityTaskWoken, DebounceTimerId timerId)
    {
        if (debounceTimers.find(timerId) == debounceTimers.end()) {
            LOG_ERROR("Could not find debouncer timer for: %s", magic_enum::enum_name(timerId).data());
            return;
        }
        auto debounceTimerState = debounceTimers.at(timerId);
        debounceTimerState.gpio->DisableInterrupt(1U << static_cast<uint32_t>(debounceTimerState.pin));
        debounceTimerState.lastState = debounceTimerState.gpio->ReadPin(static_cast<uint32_t>(debounceTimerState.pin))
                                           ? KeyEvents::Released
                                           : KeyEvents::Pressed;
        if (debounceTimerState.timer != nullptr) {
            xTimerResetFromISR(debounceTimerState.timer, &xHigherPriorityTaskWoken);
        }
    }

    BaseType_t IRQHandler(uint32_t mask)
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        auto timerId                        = DebounceTimerId::Invalid;

        gpio_sw->ClearPortInterrupts(1U << mask);

        if (mask & (1 << magic_enum::enum_integer(BoardDefinitions::BELL_SWITCHES_LEFT))) {
            timerId = DebounceTimerId::leftSideSwitch;
        }
        else if (mask & (1 << magic_enum::enum_integer(BoardDefinitions::BELL_SWITCHES_RIGHT))) {
            timerId = DebounceTimerId::rightSideSwitch;
        }
        else if (mask & (1 << magic_enum::enum_integer(BoardDefinitions::BELL_SWITCHES_CENTER))) {
            timerId = DebounceTimerId::lightCenterSwitch;
        }
        else if (mask & (1 << magic_enum::enum_integer(BoardDefinitions::BELL_SWITCHES_LATCH))) {
            timerId = DebounceTimerId::latchSwitch;
        }

        getDebounceTimer(xHigherPriorityTaskWoken, timerId);

        return xHigherPriorityTaskWoken;
    }

    BaseType_t wakeupIRQHandler()
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        gpio_wakeup->ClearPortInterrupts(1U << static_cast<uint32_t>(BoardDefinitions::BELL_WAKEUP));

        getDebounceTimer(xHigherPriorityTaskWoken, DebounceTimerId::wakeup);

        return xHigherPriorityTaskWoken;
    }

    void enableIRQ()
    {
        gpio_sw->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_CENTER));
        gpio_sw->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LEFT));
        gpio_sw->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_RIGHT));
        gpio_sw->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LATCH));
    }

    void enableWakeupIRQ()
    {
        gpio_wakeup->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_WAKEUP));
    }

    void disableIRQ()
    {
        gpio_sw->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_CENTER));
        gpio_sw->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LEFT));
        gpio_sw->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_RIGHT));
        gpio_sw->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LATCH));
    }

    void disableWakeupIRQ()
    {
        gpio_wakeup->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BELL_WAKEUP));
    }

    std::vector<KeyEvent> getKeyEvents(KeyNotificationSource notification)
    {
        std::vector<KeyEvent> out;

        if (notification & static_cast<uint16_t>(NotificationSource::leftSideKeyPress)) {
            LOG_DEBUG("leftSideKeyPress");
            KeyEvent keyEvent{KeyCodes::FnLeft, KeyEvents::Pressed};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::leftSideKeyRelease)) {
            LOG_DEBUG("leftSideKeyRelease");
            KeyEvent keyEvent{KeyCodes::FnLeft, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::rightSideKeyPress)) {
            LOG_DEBUG("rightSideKeyPress");
            KeyEvent keyEvent{KeyCodes::FnRight, KeyEvents::Pressed};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint8_t>(NotificationSource::rightSideKeyRelease)) {
            LOG_DEBUG("rightSideKeyRelease");
            KeyEvent keyEvent{KeyCodes::FnRight, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::lightCenterKeyPress)) {
            LOG_DEBUG("lightCenterKeyPress");
            KeyEvent keyEvent{KeyCodes::JoystickEnter, KeyEvents::Pressed};
            out.push_back(keyEvent);
            // workaround for current GUI event processing
            keyEvent = {KeyCodes::JoystickEnter, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::lightCenterKeyRelease)) {
            LOG_DEBUG("lightCenterKeyRelease");
            KeyEvent keyEvent{KeyCodes::JoystickEnter, KeyEvents::Pressed};
            out.push_back(keyEvent);
            // workaround for current GUI event processing
            keyEvent = {KeyCodes::JoystickEnter, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::latchKeyPress)) {
            LOG_DEBUG("latchKeyPress");
            KeyEvent keyEvent{KeyCodes::JoystickRight, KeyEvents::Pressed};
            out.push_back(keyEvent);
            // workaround for current GUI event processing
            keyEvent = {KeyCodes::JoystickRight, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::latchKeyRelease)) {
            LOG_DEBUG("latchKeyRelease");
            KeyEvent keyEvent{KeyCodes::JoystickLeft, KeyEvents::Pressed};
            out.push_back(keyEvent);
            // workaround for current GUI event processing
            keyEvent = {KeyCodes::JoystickLeft, KeyEvents::Released};
            out.push_back(keyEvent);
        }

        if (notification & static_cast<uint16_t>(NotificationSource::wakeupEvent)) {
            /* Implement wakeup event */
        }

        if (notification & static_cast<uint16_t>(NotificationSource::wakeupEventRelease)) {
            KeyEvent keyEvent;
            /* Implement wakeup event */
        }

        return out;
    }

} // namespace bsp::bell_switches

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

#pragma once

#include <hal/key_input/KeyEventDefinitions.hpp>

#include <cstdint>
#include <vector>

namespace bsp::bell_switches
{
    std::vector<KeyEvent> getKeyEvents(KeyNotificationSource notification);

    std::int32_t init(xQueueHandle qHandle);

    std::int32_t deinit();

    void enableIRQ();

    void disableIRQ();

    BaseType_t IRQHandler(uint32_t mask);

    BaseType_t wakeupIRQHandler();
} // namespace bsp::bell_switches

M module-bsp/board/rt1051/bellpx/hal/key_input/KeyInput.cpp => module-bsp/board/rt1051/bellpx/hal/key_input/KeyInput.cpp +15 -10
@@ 4,6 4,8 @@
#include "KeyInput.hpp"

#include <hal/GenericFactory.hpp>
#include <bsp/switches/switches.hpp>
#include <board/BoardDefinitions.hpp>

namespace hal::key_input
{


@@ 12,25 14,28 @@ namespace hal::key_input
        return hal::impl::factory<KeyInput, AbstractKeyInput>();
    }

    void KeyInput::init(xQueueHandle)
    {}
    void KeyInput::init(xQueueHandle queueHandle)
    {
        bsp::bell_switches::init(queueHandle);
    }

    void KeyInput::deinit()
    {}

    std::vector<bsp::KeyEvent> KeyInput::getKeyEvents(std::uint8_t)
    {
        return std::vector<bsp::KeyEvent>{};
        bsp::bell_switches::deinit();
    }

    BaseType_t generalIRQHandler()
    std::vector<bsp::KeyEvent> KeyInput::getKeyEvents(KeyNotificationSource notification)
    {
        return 0;
        return bsp::bell_switches::getKeyEvents(notification);
    }

    BaseType_t rightFunctionalIRQHandler()
    BaseType_t generalIRQHandler(std::uint32_t irqMask)
    {
        return 0;
        return bsp::bell_switches::IRQHandler(irqMask);
    }

    BaseType_t wakeupIRQHandler()
    {
        return bsp::bell_switches::wakeupIRQHandler();
    }
} // namespace hal::key_input

M module-bsp/board/rt1051/bellpx/hal/key_input/KeyInput.hpp => module-bsp/board/rt1051/bellpx/hal/key_input/KeyInput.hpp +3 -1
@@ 12,6 12,8 @@ namespace hal::key_input
      public:
        void init(xQueueHandle) final;
        void deinit() final;
        std::vector<bsp::KeyEvent> getKeyEvents(std::uint8_t) final;
        std::vector<bsp::KeyEvent> getKeyEvents(KeyNotificationSource) final;

        BaseType_t wakeupIRQHandler();
    };
} // namespace hal::key_input

M module-bsp/board/rt1051/bellpx/irq_gpio.cpp => module-bsp/board/rt1051/bellpx/irq_gpio.cpp +30 -7
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "board/irq_gpio.hpp"
#include <module-utils/Utils.hpp>

#include "board.h"
#include "FreeRTOS.h"


@@ 10,7 11,7 @@

#include "board/rt1051/bsp/eink/bsp_eink.h"
#include <hal/battery_charger/AbstractBatteryCharger.hpp>
#include <hal/key_input/AbstractKeyInput.hpp>
#include <hal/key_input/KeyInput.hpp>
#include "board/BoardDefinitions.hpp"
#include "bsp/light_sensor/light_sensor.hpp"



@@ 24,15 25,18 @@ namespace bsp
        DisableIRQ(GPIO2_Combined_0_15_IRQn);
        DisableIRQ(GPIO2_Combined_16_31_IRQn);
        DisableIRQ(GPIO3_Combined_16_31_IRQn);
        DisableIRQ(GPIO5_Combined_0_15_IRQn);

        GPIO_PortDisableInterrupts(GPIO1, UINT32_MAX);
        GPIO_PortDisableInterrupts(GPIO2, UINT32_MAX);
        GPIO_PortDisableInterrupts(GPIO3, UINT32_MAX);
        GPIO_PortClearInterruptFlags(GPIO5, UINT32_MAX);

        // Clear all IRQs
        GPIO_PortClearInterruptFlags(GPIO1, UINT32_MAX);
        GPIO_PortClearInterruptFlags(GPIO2, UINT32_MAX);
        GPIO_PortClearInterruptFlags(GPIO3, UINT32_MAX);
        GPIO_PortClearInterruptFlags(GPIO5, UINT32_MAX);

        EnableIRQ(GPIO1_Combined_0_15_IRQn);
        NVIC_SetPriority(GPIO1_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);


@@ 48,6 52,9 @@ namespace bsp

        EnableIRQ(GPIO3_Combined_16_31_IRQn);
        NVIC_SetPriority(GPIO3_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);

        EnableIRQ(GPIO5_Combined_0_15_IRQn);
        NVIC_SetPriority(GPIO5_Combined_0_15_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
    }

    extern "C"


@@ 90,10 97,6 @@ namespace bsp
                xHigherPriorityTaskWoken |= hal::battery::IRQHandler();
            }

            if (irq_mask & (1 << static_cast<uint32_t>(BoardDefinitions::LIGHT_SENSOR_IRQ))) {
                xHigherPriorityTaskWoken |= bsp::light_sensor::IRQHandler();
            }

            // Clear all IRQs
            GPIO_PortClearInterruptFlags(GPIO2, irq_mask);



@@ 106,8 109,11 @@ namespace bsp
            BaseType_t xHigherPriorityTaskWoken = 0;
            uint32_t irq_mask                   = GPIO_GetPinsInterruptFlags(GPIO2);

            if (irq_mask & (1 << BOARD_KEYBOARD_IRQ_GPIO_PIN)) {
                xHigherPriorityTaskWoken |= hal::key_input::generalIRQHandler();
            if (irq_mask & ((1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_CENTER)) |
                            (1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_RIGHT)) |
                            (1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LEFT)) |
                            (1 << static_cast<uint32_t>(BoardDefinitions::BELL_SWITCHES_LATCH)))) {
                xHigherPriorityTaskWoken |= hal::key_input::generalIRQHandler(irq_mask);
            }

            // Clear all IRQs


@@ 133,5 139,22 @@ namespace bsp
            // Switch context if necessary
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        }

        void GPIO5_Combined_0_15_IRQHandler(void)
        {
            BaseType_t xHigherPriorityTaskWoken = 0;
            uint32_t irq_mask                   = GPIO_GetPinsInterruptFlags(GPIO5);

            if (irq_mask & (1 << static_cast<uint32_t>(BoardDefinitions::BELL_WAKEUP))) {

                xHigherPriorityTaskWoken |= hal::key_input::wakeupIRQHandler();
            }

            // Clear all IRQs on the GPIO5 port
            GPIO_PortClearInterruptFlags(GPIO5, irq_mask);

            // Switch context if necessary
            portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        }
    }
} // namespace bsp

M module-bsp/board/rt1051/bellpx/pin_mux.c => module-bsp/board/rt1051/bellpx/pin_mux.c +22 -9
@@ 304,6 304,7 @@ void PINMUX_InitBootPins(void)
    PINMUX_InitButtons();
    PINMUX_InitRotaryEncoder();
    PINMUX_DomeSwitch();
    PINMUX_Wakeup();
    PINMUX_WDOG_B_Init();
    PINMUX_InitI2C4();
}


@@ 1125,6 1126,8 @@ void PINMUX_InitEinkFrontlight(void)

void PINMUX_InitButtons(void)
{
    CLOCK_EnableClock(kCLOCK_Iomuxc);

    IOMUXC_SetPinMux(PINMUX_BUTTON_SW1, 0U); /* Software Input On Field: Input Path is determined by functionality */

    IOMUXC_SetPinMux(PINMUX_BUTTON_SW2, 0U); /* Software Input On Field: Input Path is determined by functionality */


@@ 1135,24 1138,22 @@ void PINMUX_InitButtons(void)
                     0U); /* Software Input On Field: Input Path is determined by functionality */

    IOMUXC_SetPinConfig(PINMUX_BUTTON_SW1,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_100kOhm);
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_22kOhm);

    IOMUXC_SetPinConfig(PINMUX_BUTTON_SW2,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_100kOhm);
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_22kOhm);

    IOMUXC_SetPinConfig(PINMUX_BUTTON_SW_ENC,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_100kOhm);
                            PAD_CONFIG_DRIVER_STRENGTH_LVL_6 | PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_PULL |
                            PAD_CONFIG_PULL_UP_100kOhm);

    IOMUXC_SetPinConfig(PINMUX_BUTTON_SW_PUSH,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_100kOhm);
                            PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_22kOhm |
                            PAD_CONFIG_HYSTERESIS_ENABLED);
}

void PINMUX_InitRotaryEncoder(void)


@@ 1174,7 1175,7 @@ void PINMUX_InitRotaryEncoder(void)

void PINMUX_DomeSwitch(void)
{
    IOMUXC_SetPinMux(PINMUX_DOME_SWITCH, 0U); /* Software Input On Field: Input Path is determined by functionality */
    IOMUXC_SetPinMux(PINMUX_DOME_SWITCH, 1U); /* Software Input On Field: Input Path is determined by functionality */

    IOMUXC_SetPinConfig(PINMUX_DOME_SWITCH,



@@ 1225,6 1226,18 @@ void PINMUX_InitI2C4(void)
                            PAD_CONFIG_SELECT_KEEPER | PAD_CONFIG_PULL_UP_22kOhm);
}

void PINMUX_Wakeup(void)
{
    CLOCK_EnableClock(kCLOCK_IomuxcSnvs);

    IOMUXC_SetPinMux(PINMUX_WAKEUP, 1U); /* Software Input On Field: Input Path is determined by functionality */

    IOMUXC_SetPinConfig(PINMUX_WAKEUP,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_DISABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_UP_100kOhm);
}

/***********************************************************************************************************************
 * EOF
 **********************************************************************************************************************/

M module-bsp/board/rt1051/puretx/CMakeLists.txt => module-bsp/board/rt1051/puretx/CMakeLists.txt +1 -1
@@ 11,7 11,7 @@ target_sources(

    PRIVATE
        hal/battery_charger/BatteryCharger.cpp
	hal/key_input/KeyInput.cpp
        hal/key_input/KeyInput.cpp
        bsp/battery_charger/battery_charger.cpp
        bsp/eink/eink_pin_config.cpp
        bsp/keyboard/keyboard.cpp

M module-bsp/board/rt1051/puretx/bsp/keyboard/keyboard.cpp => module-bsp/board/rt1051/puretx/bsp/keyboard/keyboard.cpp +1 -1
@@ 203,7 203,7 @@ namespace bsp::keyboard
        return kStatus_Success;
    }

    std::vector<KeyEvent> getKeyEvents(std::uint8_t notification)
    std::vector<KeyEvent> getKeyEvents(KeyNotificationSource notification)
    {
        std::vector<KeyEvent> out;
        if (notification & static_cast<std::uint8_t>(NotificationSource::regularKey)) {

M module-bsp/board/rt1051/puretx/bsp/keyboard/keyboard.hpp => module-bsp/board/rt1051/puretx/bsp/keyboard/keyboard.hpp +1 -1
@@ 10,7 10,7 @@

namespace bsp::keyboard
{
    std::vector<KeyEvent> getKeyEvents(std::uint8_t notification);
    std::vector<KeyEvent> getKeyEvents(KeyNotificationSource notification);

    std::int32_t init(xQueueHandle qHandle);


M module-bsp/board/rt1051/puretx/hal/key_input/KeyInput.cpp => module-bsp/board/rt1051/puretx/hal/key_input/KeyInput.cpp +2 -2
@@ 23,12 23,12 @@ namespace hal::key_input
        bsp::keyboard::deinit();
    }

    std::vector<bsp::KeyEvent> KeyInput::getKeyEvents(std::uint8_t notification)
    std::vector<bsp::KeyEvent> KeyInput::getKeyEvents(KeyNotificationSource notification)
    {
        return bsp::keyboard::getKeyEvents(notification);
    }

    BaseType_t generalIRQHandler()
    BaseType_t generalIRQHandler(std::uint32_t irqMask)
    {
        return bsp::keyboard::IRQHandler();
    }

M module-bsp/board/rt1051/puretx/hal/key_input/KeyInput.hpp => module-bsp/board/rt1051/puretx/hal/key_input/KeyInput.hpp +1 -1
@@ 12,6 12,6 @@ namespace hal::key_input
      public:
        void init(xQueueHandle queueHandle) final;
        void deinit() final;
        std::vector<bsp::KeyEvent> getKeyEvents(std::uint8_t) final;
        std::vector<bsp::KeyEvent> getKeyEvents(KeyNotificationSource) final;
    };
} // namespace hal::key_input

M module-bsp/board/rt1051/puretx/irq_gpio.cpp => module-bsp/board/rt1051/puretx/irq_gpio.cpp +2 -2
@@ 10,7 10,7 @@

#include "board/rt1051/bsp/eink/bsp_eink.h"
#include <hal/battery_charger/AbstractBatteryCharger.hpp>
#include <hal/key_input/AbstractKeyInput.hpp>
#include <hal/key_input/KeyInput.hpp>
#include "bsp/cellular/bsp_cellular.hpp"
#include "bsp/headset/headset.hpp"
#include "board/BoardDefinitions.hpp"


@@ 142,7 142,7 @@ namespace bsp
            uint32_t irq_mask                   = GPIO_GetPinsInterruptFlags(GPIO2);

            if (irq_mask & (1 << BOARD_KEYBOARD_IRQ_GPIO_PIN)) {
                xHigherPriorityTaskWoken |= hal::key_input::generalIRQHandler();
                xHigherPriorityTaskWoken |= hal::key_input::generalIRQHandler(irq_mask);
            }

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

M module-bsp/hal/key_input/AbstractKeyInput.hpp => module-bsp/hal/key_input/AbstractKeyInput.hpp +6 -5
@@ 4,6 4,7 @@
#pragma once

#include "KeyEventDefinitions.hpp"

#include <FreeRTOS.h>
#include <queue.h>



@@ 22,12 23,12 @@ namespace hal::key_input

        virtual ~AbstractKeyInput() = default;

        virtual void init(xQueueHandle)                               = 0;
        virtual void deinit()                                         = 0;
        virtual std::vector<bsp::KeyEvent> getKeyEvents(std::uint8_t) = 0;
        virtual void init(xQueueHandle)                                        = 0;
        virtual void deinit()                                                  = 0;
        virtual std::vector<bsp::KeyEvent> getKeyEvents(KeyNotificationSource) = 0;
    };

    BaseType_t generalIRQHandler();
    BaseType_t generalIRQHandler(std::uint32_t irqMask);
    BaseType_t rightFunctionalIRQHandler();

    BaseType_t wakeupIRQHandler();
} // namespace hal::key_input

M module-bsp/hal/key_input/KeyEventDefinitions.hpp => module-bsp/hal/key_input/KeyEventDefinitions.hpp +3 -2
@@ 5,9 5,10 @@

#include <magic_enum.hpp>

using KeyNotificationSource = uint16_t;

namespace bsp
{

    enum class KeyCodes
    {
        Undefined     = 0,


@@ 44,7 45,7 @@ namespace bsp

        HeadsetOk      = 71,
        HeadsetVolUp   = 72,
        HeadsetVolDown = 73
        HeadsetVolDown = 73,
    };

    enum class KeyEvents

M products/BellHybrid/keymap/include/keymap/KeyMap.hpp => products/BellHybrid/keymap/include/keymap/KeyMap.hpp +1 -0
@@ 9,6 9,7 @@
/// GUI design
enum class KeyMap
{
    Frontlight    = static_cast<int>(gui::KeyCode::KEY_LF),
    Back          = static_cast<int>(gui::KeyCode::KEY_RF),
    LightPress    = static_cast<int>(gui::KeyCode::KEY_ENTER),
    RotateLeft    = static_cast<int>(gui::KeyCode::KEY_DOWN),