#include <freertos/message_buffer.h>
#include "DHTesp.h"

#define DHT_PIN 15
#define LDR_PIN 5

#define BUFFER_SIZE 512   // 缓冲区大小

#define PH {0X55, 0XAA, 0X89}  // 包头固定字符串
const char HEAD[3]=PH;
typedef struct{           // 数据包结构体
  char head[3];           // 数据表其实标志(包头,包花)
  uint8_t data_type;      // 数据包类型
  uint8_t data_length;    // 数据包包体长度
  char reserve[3];        // 无实际用途,用于数据对齐
}Package_Head;

typedef struct{           // DHP22 数据结构体
  Package_Head head;      // 包头
  float temperature;      // 温度
  float humidity;         // 湿度
}DHT22_Package;

typedef struct{           // LDR 数据结构体
  Package_Head head;      // 包头
  float lux;              // 光照度
}LDR_Package;

MessageBufferHandle_t xMessageBuffer = NULL;   // 消息缓冲区句柄

// 温湿度传感器数据获取线程
void dht22_task(void* param_t){
  DHTesp dhtSensor;
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  size_t psize = sizeof(DHT22_Package);   // 数据包大小
  Package_Head head = {PH, 1, psize- sizeof(Package_Head)};
  DHT22_Package pck = {head, 0, 0};
  size_t size;
  while(1){
    TempAndHumidity  data = dhtSensor.getTempAndHumidity();
    // 灌装数据
    pck.temperature = data.temperature;
    pck.humidity = data.humidity;
    size = xMessageBufferSend(xMessageBuffer,   // 消息缓冲句柄
                              (void*)&pck,      // 传输的消息体首地址指针
                              psize,            // 本次传输的数据大小
                              portMAX_DELAY);   // 传输等待超时时间
    if(size != psize){
      printf("[DHTP] 数据发送失败,可能造成数据不完整的混乱\n");
    }else{
      // printf("[DHTP] 数据发送成功,大小 : %d\n",size);
    }
    vTaskDelay(random(1000,3000));
  }
}

// 光照度传感器数据获取线程
void ldr_task(void* param_t){
  const float GAMMA = 0.7;
  const float RL10 = 50;
  size_t psize = sizeof(LDR_Package);   // 数据包大小
  Package_Head head = {PH, 2, psize- sizeof(Package_Head)};
  LDR_Package pck = {head, 0};
  size_t size;
  while(1){
    int analogValue = analogRead(LDR_PIN);  // 读取引脚的模拟量
    // 一下是一顿猛如虎的操作,具体做了些什么请参照LDR的文档,8191是精度,表示13位精度
    float voltage = analogValue / 8191. * 5;
    float resistance = 2000 * voltage / (1 - voltage / 5);
    float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
    pck.lux = lux;
    size = xMessageBufferSend(xMessageBuffer,   // 消息缓冲句柄
                              (void*)&pck,      // 传输的消息体首地址指针
                              psize,            // 本次传输的数据大小
                              portMAX_DELAY);   // 传输等待超时时间
    if(size != psize){
      printf("[LDRP] 数据发送失败,可能造成数据不完整的混乱\n");
    }else{
      // printf("[DHTP] 数据发送成功,大小 : %d\n",size);
    }
    vTaskDelay(random(1000,3000));
  }
}

// 消息处理器
void processor(char *data, size_t size){
  /* 正确的消息处理方式如下:
   * 1. 首先判断包头是否正确,如果不正确则直接扔掉数据包
   * 2. 判断长度是否正确,如果不正确则扔掉数据包
   * 3. 取出数据
   */
   if(data[0] == HEAD[0] && data[1] == HEAD[1] && data[2] == HEAD[2]){
       Package_Head *head= (Package_Head *)data;
     if(head->data_length == size-sizeof(Package_Head)){
      //  printf("[PROC] 数据包到达,类型 :%02X , 长度 : %d\n", data[3], head->data_length);
       switch(data[3]){
          case 0x01:   // DHT22类型数据
          {
            DHT22_Package *pak = (DHT22_Package *)data;
            printf("[PROC] DHT22数据到达,Temperature : %.2f°C , Humidity : %.2f%%\n",
                              pak->temperature, pak->humidity);
            break;
          }
          case 0x02:    // LDR类型数据
          {
            LDR_Package *pak = (LDR_Package *)data;
            printf("[PROC] LDR数据到达,光照 : %.2f\n",
                              pak->lux);
            break;
          }
          default:
          {
            printf("[PROC] 未知数据包 : %02X\n",data[3]);
          }
       }
     }else{
       printf("[PROC] 数据长度检测失败 : %d\n", data[4]);
     }
   }else{
      printf("[PROC] 包头检测失败 : %02X , %02X , %02X\n", data[0], data[1], data[2]);
   }
}
/** 
 * @brief 数据处理器线程
 * 该函数优先级建议比数据存入线程高,保证数据先处理(视具体情况而定)
 * 当发现缓冲区中有数据时,先处理缓冲区数据,确保所有数据处理完成之后再进行下一次等待
 **/
void processor_task(void* param_t){
  size_t msize;   // 消息的长度
  size_t size;    // 接收的长度
  while(1){
    msize = xMessageBufferNextLengthBytes(xMessageBuffer);   // 获得下一条消息的长度
    while(msize>0){
      char *data = (char *)pvPortMalloc(msize);       // 开辟空间准备接收消息
      size = xMessageBufferReceive(xMessageBuffer,    // 消息缓冲区句柄
                                  (void *)data,       // 接收数据的首地址
                                  msize,              // 最大接收数据长度
                                  portMAX_DELAY);     // 等待时间
      if(size == msize){
        // 正确收到了消息
        processor(data, size);
      }else{
        printf("[PROC] 消息接收错误,应接收 : %d , 实际接收 : %d\n", msize, size);
      }
      vPortFree(data);    // 释放空间
      msize = xMessageBufferNextLengthBytes(xMessageBuffer);   // 获得下一条消息的长度
    }
    vTaskDelay(1000);
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Hello, ESP32-S3!");
  
  xMessageBuffer = xMessageBufferCreate(BUFFER_SIZE);   // 初始化消息缓冲区
  if (xMessageBuffer == NULL)
  {
    printf("创建缓冲区失败,内存不足!\n");
  }
  else
  {
    // 创建线程
    xTaskCreate(dht22_task, "DHT22", 1024 * 4, NULL, 1, NULL);
    xTaskCreate(ldr_task, "LDR", 1024 * 4, NULL, 1, NULL);
    xTaskCreate(processor_task, "PROC", 1024 * 4, NULL, 1, NULL);
  }
}

void loop() {
  delay(10);
}
esp:0
esp:1
esp:2
esp:3
esp:4
esp:5
esp:6
esp:7
esp:8
esp:9
esp:10
esp:11
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:20
esp:21
esp:35
esp:36
esp:37
esp:38
esp:39
esp:40
esp:41
esp:42
esp:45
esp:46
esp:47
esp:48
esp:3V3.1
esp:3V3.2
esp:RST
esp:5V
esp:GND.1
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:GND.4
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
ldr1:VCC
ldr1:GND
ldr1:DO
ldr1:AO