/*
 * Copyright (c) 2020, Erich Styger
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "platform.h"

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "led.h"
#include "McuUtility.h"
#include "McuLED.h"
#include "McuLog.h"

#define TAG "Blinky"  /* tag for logging with ESP_LOG */

static McuLED_Handle_t ledHandle;

static TaskHandle_t taskHandle;
static bool blinkyIsRunning = false;
#define LED_OFF_TIME_MS    1000
static uint32_t onTimeMs = 10; /* default on time of LED */

/* red led on the shield is on IO10, LOW active */
#define BLINK_GPIO    (GPIO_NUM_10) /* IO10 */
#define LED_LOW_ACTIVE  (1)

void LED_SetOnTime(uint32_t ms) {
  onTimeMs = ms;
}

void LED_On(void) {
  McuLED_On(ledHandle);
}
void LED_Off(void) {
  McuLED_Off(ledHandle);
}

void LED_Suspend(void) {
  if (taskHandle!=NULL) {
    vTaskSuspend(taskHandle);
    blinkyIsRunning = false;
    LED_Off();
  }
}

void LED_Resume(void) {
  if (taskHandle!=NULL) {
    vTaskResume(taskHandle);
    blinkyIsRunning = true;
  }
}

void LED_GetStatus(unsigned char *buf, size_t bufSize) {
  buf[0] = '\0';
  if (taskHandle!=NULL) {
    eTaskState state;

    state = eTaskGetState(taskHandle);
    switch(state) {
    case eSuspended:
      McuUtility_strcpy(buf, bufSize, (unsigned char*)"suspended");
      break;
    case eRunning:
    case eBlocked:
      McuUtility_strcpy(buf, bufSize, (unsigned char*)"running");
      break;
    default:
    case eDeleted:
      McuUtility_strcpy(buf, bufSize, (unsigned char*)"ERROR!");
      break;
    }
  } else {
    McuUtility_strcpy(buf, bufSize, (unsigned char*)"ERROR: no task!");
  }
}

static void blinkyTask(void *pv) {
  (void)pv;
  blinkyIsRunning = true;
  ESP_LOGI(TAG, "running my blinky task");
  McuLog_info("started blinky task");
  for(;;) {
    LED_On();
    vTaskDelay(pdMS_TO_TICKS(onTimeMs));
    LED_Off();
    vTaskDelay(pdMS_TO_TICKS(LED_OFF_TIME_MS));
  }
}

#if PL_CONFIG_USE_SHELL
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
  McuShell_SendStatusStr((unsigned char*)"led", (unsigned char*)"ESP32 LED status\r\n", io->stdOut);
  McuShell_SendStatusStr((unsigned char*)"  status", blinkyIsRunning?(unsigned char*)"resumed\r\n":(unsigned char*)"suspended\r\n", io->stdOut);
  return ERR_OK;
}

static uint8_t PrintHelp(const McuShell_StdIOType *io) {
  McuShell_SendHelpStr((unsigned char*)"led", (unsigned char*)"Group of ESP32 LED commands\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  help|status", (unsigned char*)"Shows LED help or status\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  suspend", (unsigned char*)"Suspend the LED task\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  resume", (unsigned char*)"Resume the LED task\r\n", io->stdOut);
  return ERR_OK;
}

uint8_t LED_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io) {
  if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, (char*)"led help")==0) {
    *handled = TRUE;
    return PrintHelp(io);
  } else if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_STATUS)==0 || McuUtility_strcmp((char*)cmd, (char*)"led status")==0) {
    *handled = TRUE;
    return PrintStatus(io);
  } else if (McuUtility_strcmp((char*)cmd, (char*)"led suspend")==0) {
    *handled = TRUE;
    LED_Suspend();
  } else if (McuUtility_strcmp((char*)cmd, (char*)"led resume")==0) {
    *handled = TRUE;
    LED_Resume();
  }
  return ERR_OK;
}
#endif /* PL_CONFIG_USE_SHELL */

void LED_Init(void) {
  BaseType_t res;
  McuLED_Config_t config;

  McuLED_GetDefaultConfig(&config);
  config.hw.pin = BLINK_GPIO;
  config.isLowActive = LED_LOW_ACTIVE;
  config.isOnInit = false;
  ledHandle = McuLED_InitLed(&config);
  if (ledHandle==NULL) {
    ESP_LOGE(TAG, "failed creating led handle!");
    return;
  }
  res = xTaskCreate(blinkyTask, "blinkyTask", 4*1024/sizeof(StackType_t), NULL, tskIDLE_PRIORITY, &taskHandle);
  if (res==pdPASS) {
    ESP_LOGI(TAG, "created blinky task");
  } else {
    ESP_LOGE(TAG, "failed creating blinky!");
  }
}
