/*
 * IKW1281Connection.c
 *
 *  Created on: Apr 9, 2025
 *      Author: herli
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "IKW1281Connection.h"
#include "main.h"


static void SendAckPacket(void);

static void WriteComplement(uint8_t b);
static void WriteByteAndDiscardEcho(uint8_t b);
static void WriteByteAndReadAck(uint8_t b);
static void WriteByteRaw(uint8_t b);

uint8_t timeoutdata[] = "TimeoutNigga\r\n";
//uint8_t RxData[1];
uint8_t TxData[KLINE_BUFFER_SIZE];
uint8_t KlineData[KLINE_BUFFER_SIZE];
volatile uint8_t rx_done_flag = 0;
uint8_t connectionAlive = 0;

uint8_t ReadByte(){
	if (!connectionAlive){ return 0;}
	rx_done_flag = 0;
    uint32_t timeout = HAL_GetTick() + 1000;  // 1-second timeout

	while (!rx_done_flag)
	{
	    if (HAL_GetTick() > timeout) {
			// Timeout occurred

	        //HAL_UART_Transmit(&huart2, (uint8_t*)timeoutdata, strlen(timeoutdata), 1000);
	        //CDC_Transmit_FS((uint8_t*)timeoutdata, strlen(timeoutdata));
	        connectionAlive = 0;
	        return 0xFF; // Or some special error code
		}

	    // Optional: add a timeout check here
	    // This loop blocks until RX is done
	}
	/*for (int k = 0; k < KLINE_BUFFER_SIZE ; k++){
		KlineData[k]=KlineData[k+1];
	}
	KlineData[KLINE_BUFFER_SIZE] = 0;
	return KlineData[0];*/
	return RxData[0];
}
uint8_t ReadAndAckByte(void){
	uint8_t b = ReadByte();
	WriteComplement(b);
	return b;
}
void ReadComplement(uint8_t b){
	uint8_t expectedComplement = (uint8_t)~b;
	uint8_t actualComplement = ReadByte();
	//if(actualComplement != expectedComplement){return;}
}
void WriteComplement(uint8_t b){
	uint8_t complement = (uint8_t)~b;
	WriteByteAndDiscardEcho(complement);
}
void WriteByteAndDiscardEcho(uint8_t b){
	WriteByteRaw(b);
	uint8_t echo = ReadByte();
	//if(echo != b){return;}
}

void WriteByteRaw(uint8_t b){
	TxData[0] = b;
	HAL_UART_Transmit(&huart1, TxData, 1, 100);
}

#define MAX_PACKETS 16   // adjust to your needs
static ParsedPacket packets_buffer[MAX_PACKETS];
#define MAX_PACKETS 16

// static buffer, persistent between calls
static ParsedPacket packets_buffer[MAX_PACKETS];

ParsedPacket* ReceivePackets(int *out_count)
{
    int count = 0;

    while (1) {
        if (count >= MAX_PACKETS) {
            // reached max, stop receiving more
            break;
        }

        ParsedPacket packet = ReceivePacket();
        packets_buffer[count++] = packet;

        if (packet.isAckNak) {
            break;
        }

        SendAckPacket();
    }

    if (out_count) {
        *out_count = count;
    }
    return packets_buffer;   // returns pointer to static buffer
}
/*
ParsedPacket* ReceivePackets(int *out_count) {
    int capacity = 16;  // initial capacity
    int count = 0;
    ParsedPacket *packets = malloc(capacity * sizeof(ParsedPacket));
    if (!packets) return NULL;

    while (1) {
        ParsedPacket packet = ReceivePacket();

        // Resize array if needed
        if (count >= capacity) {
            capacity *= 2;
            ParsedPacket *new_packets = realloc(packets, capacity * sizeof(ParsedPacket));
            if (!new_packets) {
                free(packets);
                return NULL;
            }
            packets = new_packets;
        }

        packets[count++] = packet;

        if (packet.isAckNak) break;

        SendAckPacket();
    }

    if (out_count) *out_count = count;
    return packets;
}*/

uint8_t _packetCounter = 0;
uint8_t _packetCounterInitialized = 0;

ParsedPacket ReceivePacket()
{
    ParsedPacket packet = {0};
    uint8_t index = 0;

    uint8_t packetLength = ReadAndAckByte();
    //packet.raw = (uint8_t*)malloc(packetLength*sizeof(uint8_t));

    packet.raw[index++] = packetLength;

    uint8_t packetCounter = ReadPacketCounter();
    packet.raw[index++] = packetCounter;

    uint8_t packetCommand = ReadAndAckByte();
    packet.raw[index++] = packetCommand;

    for (int i = 0; i < packetLength - 3; i++) {
        uint8_t b = ReadAndAckByte();
        packet.raw[index++] = b;
    }

    uint8_t packetEnd = ReadByte();  // no ACK
    packet.raw[index++] = packetEnd;
    packet.length = index; //tiene que ser index

    if (packetEnd != 0x03) {
        // Protocol error handling here
    	return packet;
    }

    // Now classify the packet type
    packet.title = packetCommand;

    switch (packetCommand) {
        case PACKET_CMD_ACK:
            packet.type = PACKET_TYPE_ACK;
            packet.isAckNak = 1;
            break;

        case PACKET_CMD_AsciiData:
            if (packet.raw[3] == 0x00)
                packet.type = PACKET_TYPE_CODING_WSC;
            else
                packet.type = PACKET_TYPE_ASCII_DATA;
            break;

        case PACKET_CMD_ReadEepromResponse:
            packet.type = PACKET_TYPE_READ_EEPROM_RESPONSE;
            break;

        case PACKET_CMD_ReadRomEepromResponse:
            packet.type = PACKET_TYPE_READ_ROM_EEPROM_RESPONSE;
            break;

        case PACKET_CMD_NAK:
            packet.type = PACKET_TYPE_NAK;
            packet.isAckNak = 1;
        default:
            packet.type = PACKET_TYPE_UNKNOWN;
            break;
    }
    return packet;
}
void ResetPacketCounter(){
	_packetCounter = 0;
}
uint8_t ReadPacketCounter()
{
    uint8_t packetCounter = ReadAndAckByte();

    if (!_packetCounterInitialized)
    {
        _packetCounter = packetCounter;
        _packetCounterInitialized = 1;
    }
    else if (packetCounter != _packetCounter)
    {
        // Handle mismatch (drop packet, reset, etc.)
    }

    _packetCounter++;
    return packetCounter;
}
void SendAckPacket()
{
    uint8_t ackByte = (uint8_t)PACKET_CMD_ACK;
    SendPacket(&ackByte, 1);
}
void SendPacket(uint8_t* payload, uint8_t length)
{
    uint8_t packetLength = length + 2;  // +2 for length and counter
    uint8_t packet[packetLength];

    int index = 0;

    packet[index++] = packetLength; 	//0
    packet[index++] = _packetCounter++;	//1

    for (int i = 0; i < length; i++)
    {
        packet[index++] = payload[i];
    }
    for (int i = 0; i < index; i++)
    {
        WriteByteAndReadAck(packet[i]);
        HAL_Delay(5);  // Small delay between bytes
    }
    WriteByteRaw(PACKET_END_EXPECTED);  // End byte, no ACK expected
}

void WriteByteAndReadAck(uint8_t b)
{
    WriteByteRaw(b);
    uint8_t ack = ReadByte();

    uint8_t expectedAck = (uint8_t)~b;
    if (ack != expectedAck)
    {
        // Handle NAK or retry
    }
}

// Placeholder for platform-specific read functions

uint8_t KeepAlive() {
    SendAckPacket();
    ParsedPacket packet = ReceivePacket();
    if(packet.type != PACKET_TYPE_ACK){
    	return 0;
    }
    return 1;
}
void EndCommunication(){
    uint8_t endPacket = (uint8_t)PACKET_CMD_End;
    SendPacket((uint8_t*)endPacket, 1);
    ResetPacketCounter();
}

ParsedPacket* SendCustom(const uint8_t* data, int len, int *out_count) {
    SendPacket((uint8_t*)data, len); //antes &
    int count = 0;
    ParsedPacket* packets = ReceivePackets(&count);
    *out_count = count;
    return packets;
}

