#include "stm32f10x.h"                  // Device header
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "LED.h"
#include "DHT11.h"
#include "USART.h"
#include "LoRa.h"
#include "Relay.h"

/* 在创建任务前，需要创建一个任务句柄，每个任务句柄与任务一一对应。 */
TaskHandle_t xTaskStateLedHdlr;
TaskHandle_t xTaskLedCtrlHdlr;
TaskHandle_t xTaskFanCtrlHdlr;
TaskHandle_t xTaskDht11Hdlr;
TaskHandle_t xTaskLoRaToGateHdlr;
TaskHandle_t xTaskLoRaMsgRecHdlr;

/* 创建队列句柄 */
QueueHandle_t xQueueTempHdlr;
QueueHandle_t xQueueHumiHdlr;
QueueHandle_t xQueueUsart1IrqHdlr;
QueueHandle_t xQueueUsart2IrqHdlr;
QueueHandle_t xQueueUsart3IrqHdlr;

/* 创建二值信号量句柄 */
SemaphoreHandle_t xSemLedOnHdlr;
SemaphoreHandle_t xSemLedOffHdlr;
SemaphoreHandle_t xSemFanOnHdlr;
SemaphoreHandle_t xSemFanOffHdlr;

/**
  * @brief  LED状态指示任务函数
  * @note   通过LED的闪烁状态指示系统运行状态。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskStateLed(void *pvParameters)
{
    while(1)
    {
        vPc13LedOn();
        vTaskDelay(1000);
        vPc13LedOff();
        vTaskDelay(1000);
    }
}

/**
  * @brief  LED控制任务函数
  * @note   根据信号量控制LED的开关状态。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskLedControl(void *pvParameters)
{
    while (1)
    {
        /* code */
        if (xSemaphoreTake(xSemLedOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            vPc13LedOn();
            xSemaphoreGive(xSemLedOnHdlr);
        } else if (xSemaphoreTake(xSemLedOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            /* code */
            vPc13LedOff();
            xSemaphoreGive(xSemLedOffHdlr);
        }
    }
}

/**
  * @brief  风扇控制任务函数
  * @note   根据信号量控制风扇的开关状态。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskFanControl(void *pvParameters)
{
    while (1)
    {
        /* code */
        if (xSemaphoreTake(xSemFanOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            vFanOn();
        } else if (xSemaphoreTake(xSemFanOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            /* code */
            vFanOff();
        }
    }
}

/**
  * @brief  DHT11数据读取任务函数
  * @note   定期读取DHT11传感器的数据，并将温度和湿度数据发送到相应的队列。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskDht11(void *pvParameters)
{
    DHT11Data_t xDHT11Data;
    /* 数据存储数组。要求与队列参数设置大小一一对应。 */
    uint8_t ucSendTempData = 0, ucSendHumiData = 0;
    if (vDht11Init() != 0)
    {
        /* 初始化失败，进行错误处理 */ 
        ucSendTempData = ucSendHumiData = 0xAA;
        xQueueSend(xQueueTempHdlr, &ucSendTempData, pdMS_TO_TICKS(10));
        xQueueSend(xQueueHumiHdlr, &ucSendHumiData, pdMS_TO_TICKS(10));
    } 
    while (1)
    {
        /* code */
        if (vDht11ReadData(&xDHT11Data.ucTemp,&xDHT11Data.ucHumi) == 0)
        {
            /* code */
            ucSendTempData = xDHT11Data.ucTemp;
            ucSendHumiData = xDHT11Data.ucHumi;
            /* 写队列。第一个参数是队列句柄，第二个是写入队列的地址（如数组），第三个是因队列满造成阻塞时的等待时长，也就是无法写入数据时的等待时长，以操作系统默认时钟节拍为准。 */
            xQueueSend(xQueueTempHdlr, &ucSendTempData, pdMS_TO_TICKS(10));
            xQueueSend(xQueueHumiHdlr, &ucSendHumiData, pdMS_TO_TICKS(10));
        } else
        {
            ucSendTempData = ucSendHumiData = 0xAB;
        }        
    }
}

/**
  * @brief  LoRa数据发送任务函数
  * @note   从温湿度队列接收数据，并通过LoRa模块发送到网关。同时处理执行器的控制信号。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskLoRaToGatePkt(void *pvParameters)
{
    char cBuffer[50];
    uint8_t ucRecTempData = 0, ucRecHumiData = 0;
    /* 定义一个返回值判断是否接收成功 */
    BaseType_t xRetvalQueueTemp, xRetvalQueueHumi;
    while (1)
    {
        /* code */
        /* 接收队列：队列句柄、传输转存的目标变量或数组和未接收到数据的等待时长，分3种情况，分别为0、0~portMAX_DELAY和portMAX_DELAY三种，分别对应
         * 一点不等、等一点时间和等最大时间。在等待队列数据的情况下，该接收队列所在的任务会一直处于阻塞态。
         */
        xRetvalQueueTemp = xQueueReceive(xQueueTempHdlr, &ucRecTempData, pdMS_TO_TICKS(10));
        xRetvalQueueHumi = xQueueReceive(xQueueHumiHdlr, &ucRecHumiData, pdMS_TO_TICKS(10));
        /* 发送 */
        vLoRaConnectionPkt(xLoRaGateConfig.ucLoRaGateChannel);
        vLoRaToGateIdPkt(xLoRaNode1Config.ucLoRaNode1Identifier);
        vLoRaToGateSenIdPkt(xLoRaSensorID.ucIdDht11);
        /* 检测接收队列是否成功 */
        if (xRetvalQueueTemp == pdTRUE && xRetvalQueueHumi == pdTRUE)
        {
            /* code */
            vUsartSendArray(USART3, &ucRecTempData, 1);
            vUsartSendArray(USART3, &ucRecHumiData, 1); 
            snprintf(cBuffer, sizeof(cBuffer), "Temp=%d, Humi=%d\r\n", ucRecTempData, ucRecHumiData);
            vUsartSendString(USART1, cBuffer);
            vTaskDelay(1000);
        }
        if (xSemaphoreTake(xSemLedOnHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            /* code */
            vUsartSendArray(USART3, &xLoRaExecutorID.ucIdLed, 1);
            vUsartSendArray(USART3, &xLoRaExecutorCommand.ucCommandOn, 1);
        } else if (xSemaphoreTake(xSemLedOffHdlr, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            /* code */
            vUsartSendArray(USART3, &xLoRaExecutorID.ucIdLed, 1);
            vUsartSendArray(USART3, &xLoRaExecutorCommand.ucCommandOff, 1);
        }
        vTaskDelay(500);
    }
}

/**
  * @brief  LoRa消息接收任务函数
  * @note   从USART3接收LoRa模块传输的执行器控制消息，并根据信号量控制相应的执行器状态。
  * @param  *pvParameters 任务参数，未使用，传入NULL。
  * @retval None
  */
void vTaskLoRaMsgRec(void *pvParameters)
{
    uint8_t ucDataRecNodeId = 0, ucDataRecExeId = 0, ucDataRecExeSta = 0;
    uint8_t ucRetvalQueueNodeId = 0, ucRetvalQueueExeId = 0, ucRetvalQueueExeSta = 0;
    while (1)
    {
        ucRetvalQueueNodeId = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecNodeId, portMAX_DELAY);
        ucRetvalQueueExeId = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecExeId, portMAX_DELAY);
        ucRetvalQueueExeSta = xQueueReceive(xQueueUsart3IrqHdlr, &ucDataRecExeSta, portMAX_DELAY);
        while (ucRetvalQueueNodeId == pdTRUE && ucRetvalQueueExeId == pdTRUE && ucRetvalQueueExeSta == pdTRUE)
        {
            /* code */
            if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusLedOn)
            {
                /* code */
                xSemaphoreGive(xSemLedOnHdlr);
            } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusLedOff)
            {
                /* code */
                xSemaphoreGive(xSemLedOffHdlr);
            } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusFanOn)
            {
                /* code */
                xSemaphoreGive(xSemFanOnHdlr);
            } else if (xLoRaMsgProcess(ucDataRecNodeId, ucDataRecExeId, ucDataRecExeSta) == statusFanOn)
            {
                /* code */
                xSemaphoreGive(xSemFanOffHdlr);
            }
            break;
        }
    }
}

/**
  * @brief  创建任务列表函数
  * @note   创建所有需要的FreeRTOS任务。
  * @param  None
  * @retval None
  */
void vCreateTasksList(void)
{
    // #if defined __LED_H__
    #if LED_PC13_WORK_MODE == STM32_STATE_MODE
    /* 创建任务，参数分别为任务函数名称、任务名字、栈大小、返回参数值、优先级、任务句柄。 */
        xTaskCreate(
                   (TaskFunction_t        ) vTaskStateLed,
                   (char *                ) "TaskName_StateLed", 
                   (configSTACK_DEPTH_TYPE) 256,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskStateLedHdlr);
    #else
        xTaskCreate(
                   (TaskFunction_t        ) vTaskLedControl,
                   (char *                ) "TaskName_LedControl", 
                   (configSTACK_DEPTH_TYPE) 256,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskLedCtrlHdlr);
    #endif
    // #endif
    // #if defined __RELAY_H__
        xTaskCreate(
                   (TaskFunction_t        ) vTaskFanControl,
                   (char *                ) "TaskName_FanControl", 
                   (configSTACK_DEPTH_TYPE) 256,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskFanCtrlHdlr);
    // #endif
    // #if defined __DHT11_H__
        xTaskCreate(
                   (TaskFunction_t        ) vTaskDht11,
                   (char *                ) "TaskName_DHT11", 
                   (configSTACK_DEPTH_TYPE) 512,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskDht11Hdlr);
    // #endif
    // #if defined __LORA_H__
        xTaskCreate(
                   (TaskFunction_t        ) vTaskLoRaToGatePkt,
                   (char *                ) "TaskName_LoRaSendToGateway", 
                   (configSTACK_DEPTH_TYPE) 512,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskLoRaToGateHdlr);
        xTaskCreate(
                   (TaskFunction_t        ) vTaskLoRaMsgRec,
                   (char *                ) "TaskName_LoRaReceivedMessage", 
                   (configSTACK_DEPTH_TYPE) 512,
                   (void *                ) NULL, 
                   (UBaseType_t           ) 2,
                   (TaskHandle_t *        ) &xTaskLoRaMsgRecHdlr);
    // #endif
}

/**
  * @brief  创建队列列表函数
  * @note   创建所有需要的FreeRTOS队列。
  * @param  None
  * @retval None
  */
void vCreateQueuesList(void)
{
    /* 创建队列有两个参数，第一个是队列的长度,也就是这个队列能存放多少个数据；
     * 第二个参数就是每个数据的大小，单位为字节，在stm32中uint8_t指针的长度一般是4字节。
     * 原函数的返回值就是队列句柄的结构体，所以需要在上面定义一个变量接收队列句柄。 */
    xQueueTempHdlr      = xQueueCreate(
                                      (UBaseType_t) 5,
                                      (UBaseType_t) sizeof(uint8_t));
    xQueueHumiHdlr      = xQueueCreate(
                                      (UBaseType_t) 5,
                                      (UBaseType_t) sizeof(uint8_t));
    xQueueUsart3IrqHdlr = xQueueCreate(
                                      (UBaseType_t) 64,
                                      (UBaseType_t) sizeof(uint8_t *));
    if (xQueueTempHdlr == NULL || xQueueHumiHdlr == NULL || xQueueUsart3IrqHdlr == NULL)
    {
        /* code */
        vUsartPrintf(USART1, "Queue Init Failed.\r\n");
    }
}

/**
  * @brief  创建信号量列表函数
  * @note   创建所有需要的FreeRTOS信号量。
  * @param  None
  * @retval None
  */
void vCreateSemaphoresList(void)
{
    xSemLedOnHdlr  = xSemaphoreCreateBinary();
    xSemLedOffHdlr = xSemaphoreCreateBinary();
    xSemFanOnHdlr  = xSemaphoreCreateBinary();
    xSemFanOffHdlr = xSemaphoreCreateBinary();
}

/**
  * @brief  主函数
  * @note   初始化系统各模块，创建队列、信号量和任务，并启动调度器。
  * @param  None
  * @retval None
  */
int main(void)
{
    vFanRelayInit();
    vDelayInit();
    vPc13LedInit();
    vUsartInit(USART1, 115200);
    vUsartInit(USART3, 115200);
    vCreateQueuesList();
    vCreateSemaphoresList();
    vCreateTasksList();
    vTaskStartScheduler();
    while(1)
    {
    
    }
}
