/*
 *
 * 基于 Raspberry Pico 的厨房危险(火灾)报警
 * 使用 DS18B20温度传感器
 * 使用 CH4 N55A甲烷气体传感器(进口)
 * 使用 PASCO2V01 CO2二氧化碳传感器模块(进口模块暂时买不到！)
 * 使用 MH-Z14B CO2二氧化碳传感器模块(国产)(0 - 5000ppm)
 * 使用 ME2_CO CO一氧化碳传感器模块(国产)
 *
 * Date: 20240103
 * 
 */

#include "MAIN.hpp"
#include "DTH11.hpp"
#include "HC-12.hpp"
#include "ZC13.hpp"

extern "C" {
    #include "WIFI.h"
}


#ifndef PICO_DEFAULT_LED_PIN
    #warning pio/hello_pio example requires a board with a regular LED
    #define PICO_DEFAULT_LED_PIN 25
#endif

static inline bool uart_rx_program_available(PIO pio, uint sm)
{
    return !pio_sm_is_rx_fifo_empty(pio, sm);
}

// 闪烁LED
static void light_flashing()
{
    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
    gpio_put(PICO_DEFAULT_LED_PIN, 1);
    sleep_ms(100);
    gpio_put(PICO_DEFAULT_LED_PIN, 0);
    sleep_ms(100);

    return;
}

int wifi()
{
    if (cyw43_arch_init()) {
        printf("failed to initialise\n");
        return 1;
    }

    cyw43_arch_enable_sta_mode();

    printf("Connecting to Wi-Fi...\n");
    if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
        printf("failed to connect.\n");
        return 1;
    } else {
        printf("Connected.\n");
    }

    cyw43_arch_deinit();

    return 0;
}

// 获取主板温度
float read_onboard_temperature()
{
    adc_init();
    adc_set_temp_sensor_enabled(true);
    adc_select_input(4);        // Input 4 is the onboard temperature sensor.

    /* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */
    const float conversionFactor = 3.3f / (1 << 12);

    float adc = (float)adc_read() * conversionFactor;
    float tempC = 27.0f - (adc - 0.706f) / 0.001721f;

    //printf("Onboard temperature %.02f°C %.02f°F\n", tempC, (tempC * 9 / 5 + 32));
    return tempC;
}

// 温度传感器
float DS18B20()
{
    float TEMPERATURE = -1;

    One_wire one_wire(DS18B20_PIN);
    one_wire.init();
    rom_address_t address {
    };

    one_wire.single_device_read_rom(address);
    /*
       printf("Device Address: %02x%02x%02x%02x%02x%02x%02x%02x\n",
       address.rom[0], address.rom[1], address.rom[2], address.rom[3],
       address.rom[4], address.rom[5], address.rom[6], address.rom[7]);
     */
    one_wire.convert_temperature(address, true, false);
    TEMPERATURE = one_wire.temperature(address);
    //printf("Temperature: %3.1f°C\n", one_wire.temperature(address));

    return TEMPERATURE;
}

// 甲烷气体传感器
int CH4()
{
    int CH4_TRUE = 0;

    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);

    gpio_init(CH4_PIN);         // 设置 GP14 引脚作为输入引脚
    gpio_set_dir(CH4_PIN, GPIO_IN);

    if (gpio_get(CH4_PIN) == 1) {
        CH4_TRUE = 1;

    }
    sleep_ms(100);
    return CH4_TRUE;
}

// CO2
static uint16_t MH_Z14B(int *MH_Z14B_DATA_IS_OK)
{
    // 初始化UART
    uart_init(UART1, BAUD_RATE);
    gpio_set_function(UART1_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART1_RX_PIN, GPIO_FUNC_UART);
    uart_set_hw_flow(UART1, false, false);
    uart_set_format(UART1, DATA_BITS, STOP_BITS, PARITY);

    // 0x86 读气体浓度值
    uint8_t CMD[9] = { 0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 };
    uart_write_blocking(UART1, CMD, 9);
    sleep_ms(200);

    // 读取
    uint8_t CO2_DATA[9] = { 0 };
    uart_read_blocking(UART1, CO2_DATA, 9);

    // CO2 浓度
    uint16_t CO2_CONC = (256 * CO2_DATA[2]) + CO2_DATA[3];

    // 校验
    uint8_t CHECKSUM = (0xFF - (CO2_DATA[1] + CO2_DATA[2] + CO2_DATA[3] + CO2_DATA[4] + CO2_DATA[5] + CO2_DATA[6] + CO2_DATA[7])) + 1;

    if (CO2_DATA[8] == CHECKSUM && CO2_DATA[1] == 0x86) {
        //printf("CHECKSUM: %X = %X\n", CO2_DATA[8], CHECKSUM);
        //printf("CO2 Concentration: %d ppm\n", CO2_CONC);
        *MH_Z14B_DATA_IS_OK = 1;
    }
    /* 
    else {
        // 校准传感器 零点 （ZERO）
        uint8_t ZERO[] = { 0XFF, 0X01, 0X87, 0X00, 0X00, 0X00, 0X00, 0X00, 0X78 };
        uart_write_blocking(UART1, ZERO, 9);
        sleep_ms(200);

        // 校准传感器 跨度点 （SPAN）
        uint8_t SPAN[] = { 0XFF, 0X01, 0X88, 0X07, 0XD0, 0X00, 0X00, 0X00, 0XA0 };
        uart_write_blocking(UART1, SPAN, 9);
        sleep_ms(200);

        *MH_Z14B_DATA_IS_OK = 0;
        printf("CO2 concentration reading failed!\n");
    }
    */

    return CO2_CONC;
}

// CO
static uint16_t ME2_CO(int IS_ANSWER, int *ME2_CO_DATA_IS_OK)
{
    // 初始化UART
    uart_init(UART0, BAUD_RATE);
    gpio_set_function(UART0_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART0_RX_PIN, GPIO_FUNC_UART);
    uart_set_hw_flow(UART0, false, false);
    uart_set_format(UART0, DATA_BITS, STOP_BITS, PARITY);

    if (IS_ANSWER == 1) {
        // 应答模式
        uint8_t _ANSWER[9] = { 0xFF, 0x01, 0x78, 0x41, 0x00, 0x00, 0x00, 0x00, 0x46 };
        uart_write_blocking(UART0, _ANSWER, 9);
        sleep_ms(100);
    }
    // 读取
    uint8_t CO_DATA[9] = { 0 };
    uart_read_blocking(UART0, CO_DATA, 9);

    // CO 浓度
    uint16_t CO_CONC = (256 * CO_DATA[4]) + CO_DATA[5];

    // 校验
    uint8_t CHECKSUM = (0xFF - (CO_DATA[1] + CO_DATA[2] + CO_DATA[3] + CO_DATA[4] + CO_DATA[5] + CO_DATA[6] + CO_DATA[7])) + 1;

    if (CO_DATA[8] == CHECKSUM && CO_DATA[1] == 0x04) {
        //printf("CHECKSUM: %X = %X\n", CO_DATA[8], CHECKSUM);
        //printf("CO Concentration: %d ppm\n", CO_CONC);
        *ME2_CO_DATA_IS_OK = 1;
    } else {
        *ME2_CO_DATA_IS_OK = 0;
    }

    return CO_CONC;
}

// 433MHZ 无线电发送数据到服务器端（Raspberry pico W WiFi 暂时不实现）
int _433_MHZ(unsigned long val)
{
    const uint RADIO_TRANSMIT_PIN = _433_MHZ_PIN; // 433发射模块引脚
    const uint PULSE_LENGTH = 169; // set this to PULSELENGTH RECIEVED
    const uint REPEAT_TRANSMIT = 4; // set this to whatever works best for you.    // 重复发送
    const uint PROTOCOL = 1;    // set this to PROTOCOL RECIEVED
    const uint BIT_LENGTH = 24; // set this to BIT LENGTH RECIEVED

    gpio_init(RADIO_TRANSMIT_PIN);
    RCSwitch mySwitch = RCSwitch();
    mySwitch.enableTransmit(RADIO_TRANSMIT_PIN);
    mySwitch.setProtocol(PROTOCOL);
    mySwitch.setPulseLength(PULSE_LENGTH);
    mySwitch.setRepeatTransmit(REPEAT_TRANSMIT);

    mySwitch.send(val, BIT_LENGTH);
    sleep_ms(10);

    return 0;
}

// 简单编码通过433MHZ发送
int addDigit(int number, int digit)
{
    char TEMP[BUFER] = { 0 };

    snprintf(TEMP, sizeof(TEMP), "%d%d%d", digit, number, digit);

    return atoi(TEMP);
}

// 核心0发送数据到核心1, 核心1判断是否有数据到来.
static void core1_main()
{

    while (1) {
        multicore_fifo_push_blocking(CH4());
        watchdog_update();

        sleep_ms(1000);
    }

    return;
}


#define TARGET_SSID "cpyfb-01"  // 替换为你要连接的 SSID
#define TARGET_PASSWORD "aa1122334" // 替换为你的 Wi-Fi 密码
static bool is_target_ssid_found = false;  // 标志：目标 SSID 是否被找到

// 扫描结果处理函数
static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
    if (result) {
        // 输出每个扫描结果的信息
        printf("ssid: %-32s rssi: %4d chan: %3d mac: %02x:%02x:%02x:%02x:%02x:%02x sec: %u\n",
            result->ssid, result->rssi, result->channel,
            result->bssid[0], result->bssid[1], result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5],
            result->auth_mode);

        // 检查是否是目标 SSID
        if (!is_target_ssid_found && strcmp((const char*)result->ssid, TARGET_SSID) == 0) {
            printf("Found target SSID: %s\n", TARGET_SSID);
            is_target_ssid_found = true;
        }
    }
    return 0;
}

// 执行 Wi-Fi 扫描
int wifi_scan() {
    cyw43_wifi_scan_options_t scan_options = {0};
    int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
    if (err != 0) {
        printf("Failed to start Wi-Fi scan: %d\n", err);
        return err;
    }
    return 0;
}

// 连接 Wi-Fi
int wifi_connect() {
    printf("Connecting to Wi-Fi...\n");
    if (cyw43_arch_wifi_connect_timeout_ms(TARGET_SSID, TARGET_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
        printf("Wi-Fi connection failed.\n");
        return -1;
    } else {
        printf("Wi-Fi connected successfully.\n");
        return 0;
    }
}

// 主程序
int main(int argc, char *argv[]) {
    stdio_init_all();
    sleep_ms(3000);

    // 初始化 CYW43 模块
    if (cyw43_arch_init()) {
        printf("CYW43 initialization failed\n");
        return 1;
    }

    cyw43_arch_enable_sta_mode();

    // 执行扫描并等待找到目标 SSID
    while (!is_target_ssid_found) {
        int scan_result_code = wifi_scan();
        if (scan_result_code != 0) {
            cyw43_arch_deinit();
            return 1;
        }

        sleep_ms(7000);  // 每隔 7 秒重新扫描一次
    }

    // 目标 Wi-Fi 已找到，连接 Wi-Fi
    if (wifi_connect() != 0) {
        cyw43_arch_deinit();
        return 1;
    }

    // 连接成功，执行 TCP 客户端测试
    while (1) {
        float ONBOARD_TEMPERATURE = read_onboard_temperature();
        printf("Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));

        char ONBOARD_TEMPERATURE_TEMP[BUFER] = { 0 };
        sprintf(ONBOARD_TEMPERATURE_TEMP, "PICO_W CPU temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));

        run_tcp_client_test(ONBOARD_TEMPERATURE_TEMP);
        sleep_ms(3000);
    }

    cyw43_arch_deinit();
    return 0;
}



/*
int main(int argc, char *argv[])
{
    stdio_init_all();
    sleep_ms(1000);

    set_sys_clock_khz(250000, true);

    int FIFO_ = -1;
    float TEMPERATURE = -1;
    float ONBOARD_TEMPERATURE = -1;
    uint16_t CO2_DATA = -1;
    uint16_t CO_DATA = -1;
    int MH_Z14B_DATA_IS_OK = 0;
    int ME2_CO_DATA_IS_OK = 0;

    // core1
    multicore_reset_core1();
    multicore_launch_core1(core1_main);

    if (watchdog_caused_reboot()) { // 判断是否从看门狗启动或者正常启动
        printf("Rebooted by Watchdog!\n");
    } else {
        printf("Clean boot\n");
    }
    watchdog_enable(8300, 1);   // 8秒检测是否重新加载看门狗计数器. (不更新计数器则重启硬件, 最高8秒)
    watchdog_start_tick(12);

    _HC_12_INIT();
    ZC13_INIT();

    while (1) {

        watchdog_update();      // 喂狗

        // RP2040温度
        ONBOARD_TEMPERATURE = read_onboard_temperature();
        if (ONBOARD_TEMPERATURE != -1) {
            printf("Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));
            //_433_MHZ(addDigit(ONBOARD_TEMPERATURE, SIGN_RP2040));

            char ONBOARD_TEMPERATURE_TEMP[BUFER] = { 0 };
            sprintf(ONBOARD_TEMPERATURE_TEMP, "Onboard temperature %.02f°C %.02f°F\n", ONBOARD_TEMPERATURE, (ONBOARD_TEMPERATURE * 9 / 5 + 32));
            _HC_12(ONBOARD_TEMPERATURE_TEMP);
        }
        watchdog_update();      // 喂狗

        // CH4
        FIFO_ = multicore_fifo_pop_blocking();
        if (FIFO_ == 1) {
            printf("Kitchen danger (fire) alarm detects CH4!!!\n");
            light_flashing();
            FIFO_ = -1;
            //_433_MHZ(addDigit(4, SIGN_CH4));
        }
        watchdog_update();      // 喂狗


        // DS18B20
        TEMPERATURE = DS18B20();
        if (TEMPERATURE != -1) {
            if (TEMPERATURE >= 10) {
                printf("Temperature: %.3f°C\n", TEMPERATURE);
            }
            //_433_MHZ(addDigit(TEMPERATURE, SIGN_DS18B20));

            if (TEMPERATURE != 85) {
                char TEMPERATURE_TEMP[BUFER] = { 0 };
                sprintf(TEMPERATURE_TEMP, "Temperature: %.3f°C\n", TEMPERATURE);
                _HC_12(TEMPERATURE_TEMP);

                TEMPERATURE = -1;
            }

        }
        watchdog_update();      // 喂狗

        // ZC13 CH4 传感器
        char CH4_DATA[BUFER] = { 0 };
        sprintf(CH4_DATA, "CH4 Concentration: %d\n", ZC13("ZC05"));
        _HC_12(CH4_DATA);
        watchdog_update();      // 喂狗

        // ME2_CO CO
        // 50 ppm（百万分之一）：长时间暴露可能会导致头痛、恶心、疲劳等不适症状。
        // 200 ppm：短时间暴露可能会导致轻微的头痛、疲劳和呼吸困难。
        // 800 ppm：短时间暴露可能会导致头晕、恶心和死亡。
        // 1600 ppm：短时间暴露可能会导致昏迷、危及生命。
        CO_DATA = ME2_CO(0, &ME2_CO_DATA_IS_OK);
        if (CO_DATA != -1 && ME2_CO_DATA_IS_OK == 1) {
            printf("CO Concentration: %d ppm\n", CO_DATA);
            //_433_MHZ(addDigit(CO_DATA, SIGN_CO));

            char CO_DATA_TEMP[BUFER] = { 0 };
            sprintf(CO_DATA_TEMP, "CO Concentration: %d ppm\n", CO_DATA);
            _HC_12(CO_DATA_TEMP);
        }
        watchdog_update();      // 喂狗

        // MH_Z14B CO2
        CO2_DATA = MH_Z14B(&MH_Z14B_DATA_IS_OK);
        if (CO2_DATA != -1 && MH_Z14B_DATA_IS_OK == 1) {
            printf("CO2 Concentration: %d ppm\n", CO2_DATA);
            //_433_MHZ(addDigit(CO2_DATA, SIGN_CO2));

            char CO2_DATA_TEMP[BUFER] = { 0 };
            sprintf(CO2_DATA_TEMP, "CO2 Concentration: %d ppm\n", CO2_DATA);
            _HC_12(CO2_DATA_TEMP);
        }
        printf("\r\n");

        watchdog_update();      // 喂狗
        sleep_ms(5000);
        watchdog_update();      // 喂狗
    }

    return 0;
}
*/