#include "rf_rx.h"

// Includes
#include <stdio.h>
#include <string.h>
#include "led.h"
#include "term.h"
#include "cfg.h"
#include "tools.h"
#include "rf_cmd.h"

// ============================================================================
//                                   GLOBALS
// ============================================================================

rf_rx_t rf_rx;

// ============================================================================
//                                PROTOTYPES
// ============================================================================


// ============================================================================
//                                 FUNCTION
// ============================================================================

void rf_rx_init()
{
    GPIO_InitTypeDef gpio = {0};

    // Init
    rf_rx.dma_read_idx          = 0;
    rf_rx.dma_last_ts           = 0;
    rf_rx.state                 = RF_RX_STATE_WAIT_GAP;
    rf_rx.last_pid              = 0;


    // RF_EN
    gpio.Mode        = GPIO_MODE_OUTPUT_OD;
    gpio.Pull        = GPIO_NOPULL;
    gpio.Speed       = GPIO_SPEED_FREQ_LOW;
    SYSTEM_GPIO_INIT(gpio, RF_RX_EN_PORT, RF_RX_EN_PIN);
    RF_RX_POWER_OFF();

    // RF_DATA
    gpio.Mode        = GPIO_MODE_AF_PP;
    gpio.Pull        = GPIO_PULLUP;
    gpio.Alternate   = RF_RX_TIM_AF;
    gpio.Speed       = GPIO_SPEED_FREQ_VERY_HIGH;
    SYSTEM_GPIO_INIT(gpio, RF_RX_DATA_PORT, RF_RX_DATA_PIN);

    // RF DATA TIM
    RF_RX_TIM_CLK_ENABLE();
    rf_rx.tim.Instance                  = RF_RX_TIM;
    rf_rx.tim.Init.Prescaler            = RF_TX_TIM_PRESCALER;
    rf_rx.tim.Init.CounterMode          = TIM_COUNTERMODE_UP;
    rf_rx.tim.Init.Period               = 0xFFFF;
    rf_rx.tim.Init.ClockDivision        = TIM_CLOCKDIVISION_DIV1;
    rf_rx.tim.Init.RepetitionCounter    = 0;
    rf_rx.tim.Init.AutoReloadPreload    = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_IC_Init(&rf_rx.tim) != HAL_OK) system_die();
    TIM_IC_InitTypeDef sConfigIC = {0};
    sConfigIC.ICPolarity                = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
    sConfigIC.ICSelection               = TIM_ICSELECTION_DIRECTTI;
    sConfigIC.ICPrescaler               = TIM_ICPSC_DIV1;
    sConfigIC.ICFilter                  = 0;
    if (HAL_TIM_IC_ConfigChannel(&rf_rx.tim, &sConfigIC, RF_RX_TIM_CHANNEL) != HAL_OK) system_die();

    // DMA
    RF_RX_DMA_CLK_ENABLE();
    rf_rx.dma.Instance                 = RF_RX_DMA;
    rf_rx.dma.Init.Request             = RF_RX_DMA_REQUEST;
    rf_rx.dma.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    rf_rx.dma.Init.PeriphInc           = DMA_PINC_DISABLE;
    rf_rx.dma.Init.MemInc              = DMA_MINC_ENABLE;
    rf_rx.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // 16 bits
    rf_rx.dma.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;    // 16 bits
    rf_rx.dma.Init.Mode                = DMA_CIRCULAR;                           // Buffer infini
    rf_rx.dma.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
    if (HAL_DMA_Init(&rf_rx.dma) != HAL_OK) system_die();
    // Lier le DMA au Timer
    __HAL_LINKDMA(&rf_rx.tim, hdma[RF_RX_DMA_LINK], rf_rx.dma);

    SYSTEM_ENABLE_IRQ(RF_RX_DMA_IRQ, 3, 0);



/*
    printf("RF_GAP_PULSE_MIN_US       : %u\r\n", RF_GAP_PULSE_MIN_US);
    printf("RF_BIT_PULSE_LONG_MAX_US  : %u\r\n", RF_BIT_PULSE_LONG_MAX_US);
    printf("RF_BIT_PULSE_SHORT_MIN_US : %u\r\n", RF_BIT_PULSE_SHORT_MIN_US);
    printf("RF_BIT_PULSE_SHORT_MAX_US : %u\r\n", RF_BIT_PULSE_SHORT_MAX_US);
*/



}

void rf_rx_task()
{

    uint16_t dma_write_idx = RF_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&rf_rx.dma);

    while(rf_rx.dma_read_idx != dma_write_idx){
        uint16_t ts = rf_rx.dma_buffer[rf_rx.dma_read_idx];
        uint16_t pulse_us;
        if (ts > rf_rx.dma_last_ts){
            pulse_us = ts - rf_rx.dma_last_ts;
        }else{
            pulse_us = (0xFFFF - rf_rx.dma_last_ts) + ts + 1;
        }
        rf_rx.dma_last_ts = ts;

        rf_rx_decode_pulse(pulse_us);

        rf_rx.dma_read_idx++;
        if (rf_rx.dma_read_idx >= RF_RX_DMA_BUFFER_SIZE) rf_rx.dma_read_idx = 0;
    }

}

void rf_rx_decode_pulse(uint16_t pulse_us)
{

    // Anyway, check for GAP to reset
    if (pulse_us > RF_GAP_PULSE_MIN_US && pulse_us < RF_GAP_PULSE_MAX_US){
        // Reset
        rf_rx.state             = RF_RX_STATE_WAIT_SYNC;
        rf_rx.reg_sync          = 0x0000;
        rf_rx.is_high_level     = 0;    // We are sure level is L now
        rf_rx.half_bit          = -1;   // Not half bit store yet
        return;
    }

    // We wait for GAP only (to know the next pulse level)
    if (rf_rx.state == RF_RX_STATE_WAIT_GAP) return;

    // Ignore noise/glitch (filter)
    if (pulse_us < RF_BIT_PULSE_NOISE_MAX_US) return;

    // Bad pulse
    if (pulse_us > RF_BIT_PULSE_LONG_MAX_US) {
        rf_rx.state = RF_RX_STATE_WAIT_GAP;
        return;
    }

    // Invert pulse level
    rf_rx.is_high_level = !rf_rx.is_high_level; // Next level

    // Manchester decoding
    uint8_t bit;

    // Long Pulse (2T)
    if (pulse_us > RF_BIT_PULSE_SHORT_MAX_US){
        if (rf_rx.half_bit != -1){
            bit = rf_rx.half_bit;
            rf_rx.half_bit = rf_rx.is_high_level;
        }else{
            rf_rx.state = RF_RX_STATE_WAIT_GAP;
            //term_msg("F");
            return;
        }
    // Short pulse (T)
    }else{
        if (rf_rx.half_bit == -1){
            rf_rx.half_bit = rf_rx.is_high_level;
            return;
        }else{
            bit = rf_rx.half_bit;
            rf_rx.half_bit = -1;
        }
    }

    // Wait for SYNC WORD
    if (rf_rx.state == RF_RX_STATE_WAIT_SYNC){
        rf_rx.reg_sync = (rf_rx.reg_sync << 1) | bit;
        if (rf_rx.reg_sync == RF_SYNC_WORD){
            rf_rx.state             = RF_RX_STATE_WAIT_DATA;
            rf_rx.reg_byte          = 0;
            rf_rx.reg_bit_cnt       = 0;
            rf_rx.packet_idx        = 0;
            rf_rx.packet_size       = RF_PACKET_MIN_BYTE;
        }
        return;
    }

    // Wait data, build byte
    rf_rx.reg_byte = (rf_rx.reg_byte << 1) | bit;
    rf_rx.reg_bit_cnt++;
    if (rf_rx.reg_bit_cnt < 8) return;

    // Get byte and reset
    uint8_t byte = rf_rx.reg_byte;
    rf_rx.reg_byte = 0;
    rf_rx.reg_bit_cnt = 0;

    // Get packet byte
    if (rf_rx.packet_idx < RF_PACKET_MAX_BYTE){
        rf_rx.packet[rf_rx.packet_idx] = byte;
    }

    // Check for size update
    if (rf_rx.packet_idx == RF_PACKET_FID_FLAGS){
        rf_rx.packet_size = RF_PACKET_MIN_BYTE + RF_FLAGS_GET_PSIZE(byte);
    }

    // Increment next byte
    rf_rx.packet_idx++;

    // Check of end of packet
    if (rf_rx.packet_idx < rf_rx.packet_size) return;

    // Reset decoder
    rf_rx.state = RF_RX_STATE_WAIT_GAP;

    // Here we are, Check CRC
    uint8_t crc = crc8(rf_rx.packet, rf_rx.packet_size - 1);
    if (crc != rf_rx.packet[rf_rx.packet_size - 1]){
        return;
    }

    /*
    term_out_hex(rf_rx.packet[RF_PACKET_FID_PID], 2);
    term_out_hex(rf_rx.packet[RF_PACKET_FID_FLAGS], 2);
    term_out_hex(rf_rx.packet[RF_PACKET_FID_ADDR], 2);
    term_out_hex(rf_rx.packet[RF_PACKET_FID_CMD], 2);
    */

    // Check packet ID
    uint8_t pid = rf_rx.packet[RF_PACKET_FID_PID];
    if (pid == rf_rx.last_pid) return;
    rf_rx.last_pid = pid;

    // Check Address / Group
    uint8_t flags   = rf_rx.packet[RF_PACKET_FID_FLAGS];
    uint8_t addr    = rf_rx.packet[RF_PACKET_FID_ADDR];
    if (addr != 0){
        if (RF_FLAGS_GET_GRP(flags) == 0){
            // Check address
            if (addr != cfg.factory.addr) return;
        }else{
            // Check group
            if (!cfg_group_is_member(addr)) return;
        }
    }
    // Command
    uint8_t cmd = rf_rx.packet[RF_PACKET_FID_CMD];

    /*
    term_out_str("RX ");
    term_out_hex(cmd, 2);
    term_out_str("\r\n");
    */

    // Compute frame delay
    uint32_t delay = 0;
    if (RF_CMD_IS_SYNC(cmd)){
        uint32_t fremain = RF_RETRY - 1 - RF_FLAGS_GET_TRY(flags);
        uint32_t fduration = (RF_FRAME_MIN_DURATION_US + (RF_FLAGS_GET_PSIZE(flags) * RF_BYTE_DURATION_US)) / 1000;
        delay = fremain * fduration;
    }

    // Add command
    rf_cmd.tick         = HAL_GetTick();
    rf_cmd.delay        = delay;
    rf_cmd.cmd          = cmd;
    rf_cmd.psize        = RF_FLAGS_GET_PSIZE(flags);
    memcpy(rf_cmd.payload, &rf_rx.packet[RF_PACKET_FID_PAYLOAD], rf_cmd.psize);
    rf_cmd.is_ready     = true;




}

// ============================================================================
//                                 DEBUG
// ============================================================================

/*
void fr_rx_dma_dump(uint16_t offset, uint16_t count, uint16_t ref)
{
    HAL_TIM_IC_Stop_DMA(&rf_rx.tim, RF_RX_DMA_CHANNEL);
    printf("=== DMA DUMP ===\r\n");
    if (offset >= RF_RX_DMA_BUFFER_SIZE) count = RF_RX_DMA_BUFFER_SIZE-1;
    if (count > RF_RX_DMA_BUFFER_SIZE) count = RF_RX_DMA_BUFFER_SIZE;
    uint16_t delta, ts, prev_ts = rf_rx.dma_buffer[offset];
    int8_t bit, half_bit = 1;
    uint8_t level;
    uint8_t is_sync = 0;
    char *level_str;
    char *bit_str;
    char *pulse_str;


    for(int i = 0; i < count; i++){
        // Ts
        ts = rf_rx.dma_buffer[offset];
        if (ts >= prev_ts) delta = ts - prev_ts;
        else delta = (0xFFFF - prev_ts) + ts + 1;
        prev_ts = ts;

        // Search GAP
        if (delta > 2000){
            level       = 0;
            half_bit    = -1;
            bit         = -1;
            is_sync     = 1;
            pulse_str   = "GAP";
            level_str   = "L";
            bit_str     = "";
        }else if (!is_sync){
            level_str   = "?";
            bit_str     = "";
            pulse_str   = "";
        }else{
            // Level
            level = !level;
            level_str = (level ? "H" : "L");

            // Reset bit
            bit = -1;

            // Filed
            if (delta < 30){
                pulse_str = "NOISE" ;
            }else if (delta > 400){
                pulse_str = "ERROR" ;
                is_sync = 0;
            }else if (delta > 190){
                pulse_str = "LONG" ;
                if (half_bit != -1) {
                    bit = half_bit;
                    half_bit = level;
                }else{
                    pulse_str = "BAD LONG";
                    is_sync = 0;
                }
            }else{
                pulse_str = "SHORT";
                if (half_bit == -1) {
                    half_bit = level;
                }else{
                    bit = half_bit;
                    half_bit = -1;

                }
            }

             if (bit == -1){
               bit_str = "";
            }else{
                bit_str = (bit ? "1" : "0");
            }

        }


        printf("%c %3d  %04d  %5d %-1s %-8s %s\r\n", (ref == offset ? '*' : ' '), i, offset, delta, level_str, pulse_str, bit_str);

        // Loop
        offset++;
        if (offset >= RF_RX_DMA_BUFFER_SIZE) offset = 0;
    }
    printf("=== END DUMP ===\r\n");

    memset(rf_rx.dma_buffer, 0, sizeof(rf_rx.dma_buffer));
    rf_rx.dma_read_idx = 0;
    rf_rx.dma_last_ts = 0;
    rf_rx.state = RF_RX_STATE_WAIT_GAP;
    HAL_TIM_IC_Start_DMA(&rf_rx.tim, RF_RX_DMA_CHANNEL, (uint32_t*)rf_rx.dma_buffer, RF_RX_DMA_BUFFER_SIZE);
}
*/

// ============================================================================
//                                 IRQ HANDLER
// ============================================================================

/*
void RF_TIM_IRQ_HANDLER(void)
{
    HAL_TIM_IRQHandler(&rf_rx.tim);
}
*/

void RF_RX_DMA_IRQ_HANDLER(void)
{
    HAL_DMA_IRQHandler(&rf_rx.dma);
}


// ============================================================================
//                                 CALLBACK
// ============================================================================
/*
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{

}
*/





/*
    if (rf_rx.packet_idx > 0){
        rf_rx.packet_idx = 0;
        int offset = (int)rf_rx.dma_read_idx - 512;
        if (offset < 0) offset += RF_RX_DMA_BUFFER_SIZE;
        fr_rx_dma_dump((uint16_t)offset, 640, rf_rx.dma_read_idx);
    }
*/

/*
    HAL_Delay(60);
    int offset = (int)rf_rx.dma_read_idx - 64;
    if (offset < 0) offset += RF_RX_DMA_BUFFER_SIZE;
    fr_rx_dma_dump((uint16_t)offset, 512, rf_rx.dma_read_idx);
*/
