/**
 * @file rtos_drv.c
 * @author June6 (https://github.com/Junedoubling6)
 * @brief
 * @version 0.2
 * @date 2023-03-03
 *
 * @copyright Copyright (c) 2022 - , All rights reserved.
 *
 */
/****** Precompiled items need to be set ******/
#include "rtos_drv.h"

#include "log.h"

/* NOTE: June6 任务周期delay模式 */
#define DELAY_MODE 1

static const char *TAG = "rtos_drv";

/* 信号量 */
SemaphoreHandle_t lvgl_mutex_semaphore_handler;

/* 队列句柄 */

/* 任务句柄 */
TaskHandle_t lcd_panel_ui_task_handler = NULL;
StackType_t lcd_panel_ui_task_stack_buffer[LCD_PANEL_UI_STK_SIZE];
StaticTask_t lcd_panel_ui_task_buffer;
#if CONFIG_LCD_CONTROLLER_SLEEP_WAKEUP
TaskHandle_t lcd_panel_restart_task_handler = NULL;
StackType_t lcd_panel_restart_task_stack_buffer[LCD_PANEL_RESTART_STK_SIZE];
StaticTask_t lcd_panel_restart_task_buffer;
#endif
TaskHandle_t update_screen_content_task_handler;
StackType_t update_screen_content_stack_task_buffer[UPDATE_SCREEN_CONTENT_STK_SIZE];
StaticTask_t update_screen_content_task_buffer;

/* 事件标志组句柄 */

/**
 * @brief Delete timer.
 *
 * @param timer_handle
 * @return ErrorStatus
 */
ErrorStatus timer_delete(TimerHandle_t timer_handle) {
  if (timer_handle == NULL) return USER_ERROR;

  xTimerDelete(timer_handle, 0);

  return USER_SUCCESS;
}

/**
 * @brief timer start.
 *
 * @param from_isr_flag
 * @param timer_handle
 * @param cmd
 * @param detecte_active_flag
 * @return ErrorStatus
 */
ErrorStatus timer_start(bool from_isr_flag, TimerHandle_t timer_handle,
                        bool cmd, bool detecte_active_flag) {
  if (timer_handle == NULL) return USER_ERROR;

  if (detecte_active_flag) {
    BaseType_t timer_active = xTimerIsTimerActive(timer_handle);
    if (((cmd) && (timer_active == pdTRUE)) ||
        ((!cmd) && (timer_active == pdFALSE)))
      return USER_SUCCESS;
  }
  BaseType_t ret = pdFALSE;
  if (from_isr_flag) {
    if (cmd)
      ret = xTimerStartFromISR(timer_handle, 0);
    else
      ret = xTimerStopFromISR(timer_handle, 0);
  } else {
    if (cmd)
      ret = xTimerStart(timer_handle, 0);
    else
      ret = xTimerStop(timer_handle, 0);
  }

  if (ret != pdPASS) return USER_ERROR;

  return USER_SUCCESS;
}

/**
 * @brief Change timer period.
 *
 * @param from_isr_flag
 * @param timer_handle
 * @param period_ms
 * @return ErrorStatus
 */
ErrorStatus timer_period_change(bool from_isr_flag, TimerHandle_t timer_handle,
                                uint32_t period_ms) {
  if (timer_handle == NULL) return USER_ERROR;

  BaseType_t ret = pdFALSE;
  TickType_t tick = pdMS_TO_TICKS(period_ms);
  BaseType_t timer_active = xTimerIsTimerActive(timer_handle);

  if (from_isr_flag) {
    if (timer_active == pdTRUE) xTimerStopFromISR(timer_handle, 0);
    // ret = xTimerReset(timer_handle, 0);
    // if (ret != pdPASS) return USER_ERROR;
    ret = xTimerChangePeriodFromISR(timer_handle, tick, 0);
  } else {
    if (timer_active == pdTRUE) xTimerStop(timer_handle, 0);
    // ret = xTimerResetFromISR(timer_handle, 0);
    // if (ret != pdPASS) return USER_ERROR;
    ret = xTimerChangePeriod(timer_handle, tick, 0);
  }
  /* NOTE: June6 更改周期后自动启动 */
  // if (timer_active == pdTRUE) xTimerStart(timer_handle, 0);

  if (ret != pdPASS) return USER_ERROR;

  return USER_SUCCESS;
}

/**
 * @brief Get timer period.
 *
 * @param timer_handle
 * @return TickType_t
 */
TickType_t timer_period_get(TimerHandle_t timer_handle) {
  if (timer_handle == NULL) return 0;

  return xTimerGetPeriod(timer_handle);
}

/**
 * @brief Get timer remaining time.
 *
 * @param from_isr_flag
 * @param timer_handle
 * @param get_remain_flag
 * @return TickType_t
 */
TickType_t timer_remaining_time_get(bool from_isr_flag,
                                    TimerHandle_t timer_handle,
                                    TickType_t timer_period_ms,
                                    bool get_remain_flag) {
  if (timer_handle == NULL) return 0;

  TickType_t tick_count = 0;
  if (from_isr_flag)
    tick_count = xTaskGetTickCountFromISR();
  else
    tick_count = xTaskGetTickCount();

  if (get_remain_flag)
    return timer_period_ms - (xTimerGetExpiryTime(timer_handle) - tick_count);
  else
    return xTimerGetExpiryTime(timer_handle) - tick_count;
}

/**
 * @brief Task delay.
 *
 * @param tick
 */
void rtos_task_delay(TickType_t tick) {
#if (DELAY_MODE == 0)
  vTaskDelay(tick);
#elif (DELAY_MODE == 1)
  TickType_t last_wake_time = xTaskGetTickCount();
  const TickType_t delay_ms = pdMS_TO_TICKS(tick);
  vTaskDelayUntil(&last_wake_time, delay_ms);
#endif
}

/**
 * @brief Send data byte queue.
 *
 * @param queue_handle
 * @param data
 * @return ErrorStatus
 */
ErrorStatus byte_queue_send(QueueHandle_t queue_handle, uint32_t data) {
  if (queue_handle == NULL) return USER_ERROR;

  BaseType_t ret = xQueueSend(queue_handle, &data, QUEUE_SEND_WAIT_TICK);
  if (ret == errQUEUE_FULL) {
    USER_LOGW(TAG, "Queue is full");
    return USER_ERROR;
  }

  return USER_SUCCESS;
}

/**
 * @brief Send data server queue.
 *
 * @param from_isr_flag
 * @param queue_handle
 * @param data
 * @return ErrorStatus
 */
ErrorStatus server_queue_send(bool from_isr_flag, QueueHandle_t queue_handle,
                              ServerData_t *data) {
  if (queue_handle == NULL) return USER_ERROR;

  BaseType_t ret = errQUEUE_FULL;
  if (from_isr_flag)
    ret = xQueueSendFromISR(queue_handle, data, QUEUE_SEND_WAIT_TICK);
  else
    ret = xQueueSend(queue_handle, data, QUEUE_SEND_WAIT_TICK);

  if (ret == errQUEUE_FULL) {
    USER_LOGW(TAG, "Queue is full");
    return USER_ERROR;
  }

  return USER_SUCCESS;
}

/**
 * @brief Send dataset server queue.
 *
 * @param from_isr_flag
 * @param queue_handle
 * @param data
 * @return ErrorStatus
 */
ErrorStatus server_dataset_queue_send(bool from_isr_flag,
                                      QueueHandle_t queue_handle,
                                      ServerDataSet_t *data) {
  if (queue_handle == NULL) return USER_ERROR;

  BaseType_t ret = errQUEUE_FULL;
  if (from_isr_flag)
    ret = xQueueSendFromISR(queue_handle, data, QUEUE_SEND_WAIT_TICK);
  else
    ret = xQueueSend(queue_handle, data, QUEUE_SEND_WAIT_TICK);

  if (ret == errQUEUE_FULL) {
    USER_LOGW(TAG, "Queue is full");
    return USER_ERROR;
  }

  return USER_SUCCESS;
}
