#include "irqhandler.h"


TaskHandle_t irqHandlerTask = NULL;

// irq handler task, handles all our application level interrupts
void irqHandler(void *pvParameters) {
  _ASSERT((uint32_t)pvParameters == 1); // FreeRTOS check

  uint32_t irqSource;

  // task remains in blocked state until it is notified by an irq
  for (;;) {
    xTaskNotifyWait(0x00,           // Don't clear any bits on entry
                    ULONG_MAX,      // Clear all bits on exit
                    &irqSource,     // Receives the notification value
                    portMAX_DELAY); // wait forever

    if (irqSource & UNMASK_IRQ) // interrupt handler to be enabled?
      irqSource &= ~MASK_IRQ;   // then clear irq mask flag
    // else suppress processing if interrupt handler is disabled
    // or time critical lmic jobs are pending in next 100ms
    else if ((irqSource & MASK_IRQ)
#if (HAS_LORA)
             || os_queryTimeCriticalJobs(ms2osticks(100))
#endif
    )
      continue;

// button pressed?
#ifdef HAS_BUTTON
    if (irqSource & BUTTON_IRQ)
      readButton();
#endif

// display needs refresh?
#ifdef HAS_DISPLAY
    if (irqSource & DISPLAY_IRQ)
      dp_refresh();
#endif

// LED Matrix display needs refresh?
#ifdef HAS_MATRIX_DISPLAY
    if (irqSource & MATRIX_DISPLAY_IRQ)
      refreshTheMatrixDisplay();
#endif

#if (TIME_SYNC_INTERVAL)
    // is time to be synced?
    if (irqSource & TIMESYNC_IRQ) {
      calibrateTime();
    }
#endif

// BME sensor data to be read?
#if (HAS_BME)
    if (irqSource & BME_IRQ)
      bme_storedata(&bme_status);
#endif

    // are cyclic tasks due?
    if (irqSource & CYCLIC_IRQ)
      doHousekeeping();

// do we have a power event?
#ifdef HAS_PMU
    if (irqSource & PMU_IRQ)
      AXP192_powerevent_IRQ();
#endif

    // is time to send the payload?
    if (irqSource & SENDCYCLE_IRQ) {
      sendData();
      // goto sleep if we have a sleep cycle
      if (cfg.sleepcycle)
#ifdef HAS_BUTTON
        enter_deepsleep(cfg.sleepcycle * 10UL, (gpio_num_t)HAS_BUTTON);
#else
        enter_deepsleep(cfg.sleepcycle * 10UL, GPIO_NUM_MAX);
#endif
    }
  } // for
} // irqHandler()

// timer triggered interrupt service routines
// they notify the irq handler task

void IRAM_ATTR doIRQ(int irq) {
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  xTaskNotifyFromISR(irqHandlerTask, irq, eSetBits, &xHigherPriorityTaskWoken);
  if (xHigherPriorityTaskWoken)
    portYIELD_FROM_ISR();
}

#ifdef HAS_DISPLAY
void IRAM_ATTR DisplayIRQ() { doIRQ(DISPLAY_IRQ); }
#endif

#ifdef HAS_MATRIX_DISPLAY
void IRAM_ATTR MatrixDisplayIRQ() { doIRQ(MATRIX_DISPLAY_IRQ); }
#endif

void mask_user_IRQ() { xTaskNotify(irqHandlerTask, MASK_IRQ, eSetBits); }

void unmask_user_IRQ() { xTaskNotify(irqHandlerTask, UNMASK_IRQ, eSetBits); }