#ifndef __PINETIME_PLATFORM_CM4_INTERRUPTGUARDIAN_H__
#define __PINETIME_PLATFORM_CM4_INTERRUPTGUARDIAN_H__

#include <array>

extern "C" {
    #include "nrf52.h"
}

namespace pinetime::platform::cm4 {

class InterruptGuardian
{
public:
    InterruptGuardian();

    enum Cm4IrqN {
        RESET_IRQ = 0,           //!< -15  Reset Vector, invoked on Power up and warm reset
        NON_MASKABLE_INT_IRQ,    //!< -14  Non maskable Interrupt, cannot be stopped or preempted
        HARD_FAULT_IRQ,          //!< -13  Hard Fault, all classes of Fault
        MEMORY_MANAGEMENT_IRQ,   //!< -12  Memory Management, MPU mismatch, including Access Violation and No Match
        BUS_FAULT_IRQ,           //!< -11  Bus Fault, Pre-Fetch-, Memory Access Fault, other address/memory related Fault
        USAGE_FAULT_IRQ,         //!< -10  Usage Fault, i.e. Undef Instruction, Illegal State Transition
        SV_CALL_IRQ,             //!< -5 System Service Call via SVC instruction
        DEBUG_MONITOR_IRQ,       //!< -4 Debug Monitor
        PEND_SV_IRQ,             //!< -2 Pendable request for system service
        SYS_TICK_IRQ,            //!< -1 System Tick Timer
    };

private:
    enum {
        CM4_HANDLER_COUNT = SYS_TICK_IRQ + 1,
    };

public:
    static inline void enable_interrupts() { asm volatile("cpsie i"); }
    static inline void disable_interrupts() { asm volatile("cpsid i"); }
    static inline bool suspend_interrupts()
    {
        uint32_t mask;
        asm volatile("mrs %0, primask" : "=r" (mask));
        asm volatile("cpsid i");
        return(mask & 0x01);
    }
    static inline void resume_interrupts(bool status)
    {
        asm volatile ("msr primask, %0" : : "r" (status) : "memory");
    }

    void register_handler(Cm4IrqN irq_nr, InterruptHandler &);

    static InterruptGuardian instance;

    std::array<InterruptHandler *, CM4_HANDLER_COUNT> cm4_vector;
};

}

#endif
