#include "SERIAL.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>


// Configurar UART a 9600 baudios (para 40 MHz)
void init_uart(void) {
    TRISCbits.TRISC6 = 0;   // TX (RC6) como salida
    TRISCbits.TRISC7 = 1;   // RX (RC7) como entrada
    
    SPBRG = 155;             // 9600 baudios @ 40 MHz
    RCSTA = 0x90;     
    TXSTAbits.BRGH = 1;     // Alta velocidad
    TXSTAbits.SYNC = 0;     // Modo asíncrono
    RCSTAbits.SPEN = 1;     // Habilitar puerto serial
    TXSTAbits.TXEN = 1;     // Habilitar transmisión
}

// Enviar cadena por UART
void send_serial(const char *str) {
    while (*str) {
        while (!TXSTAbits.TRMT);
        TXREG = *str++;
    }
}

// Función auxiliar para comparar los próximos caracteres del formato
static uint8_t format_matches(const char **format, const char *match) {
    const char *f = *format;
    const char *m = match;
    
    while (*m != '\0') {
        if (*f != *m) {
            return 0; // No coincide
        }
        f++;
        m++;
    }
    
    // Coincide, avanzamos el puntero del formato
    *format = f;
    return 1;
}

void Serial_Write(const char *format, ...) {
    va_list args;
    va_start(args, format);
    
    while (*format != '\0') {
        if (*format == '%') {
            format++; // Avanzar al caracter después del %
            
            // Manejar los diferentes especificadores de formato
            if (*format == 'c') {
                char c = (char)va_arg(args, int);
                send_char(c);
            }
            else if (*format == 's') {
                char *str = va_arg(args, char*);
                send_string(str);
            }
            else if (*format == 'd') {
                int num = va_arg(args, int);
                send_int(num);
            }
            else if (*format == 'u') {
                format++; // Avanzar al número
                if (*format == '8') {
                    uint8_t num = (uint8_t)va_arg(args, int);
                    send_uint8(num);
                }
                else if (*format == '1' && *(format+1) == '6') {
                    format++; // Saltar el '1'
                    uint16_t num = (uint16_t)va_arg(args, int);
                    send_uint16(num);
                }
                else if (*format == '3' && *(format+1) == '2') {
                    format++; // Saltar el '3'
                    uint32_t num = va_arg(args, uint32_t);
                    send_uint32(num);
                }
                else {
                    // Formato desconocido, enviar literal
                    send_char('%');
                    send_char('u');
                    format--; // Retroceder para mostrar el caracter desconocido
                }
            }

				else if (*format == 'f') {
					char *buffer = va_arg(args, char*);
					send_string(buffer);	

				 }


            else if (*format == 'h') {
                format++; // Avanzar al número
                if (*format == '8') {
                    uint8_t num = (uint8_t)va_arg(args, int);
                    send_serial("0x");
                    send_hex8(num);
                }
                else if (*format == '1' && *(format+1) == '6') {
                    format++; // Saltar el '1'
                    uint16_t num = (uint16_t)va_arg(args, int);
                    send_serial("0x");
                    send_hex16(num);
                }
                else {
                    // Formato desconocido, enviar literal
                    send_char('%');
                    send_char('h');
                    format--; // Retroceder para mostrar el caracter desconocido
                }
            }
            else if (*format == 'o') {
                format++; // Avanzar al número
                if (*format == '8') {
                    uint8_t num = (uint8_t)va_arg(args, int);
                    send_octal8(num);
                }
                else if (*format == '1' && *(format+1) == '6') {
                    format++; // Saltar el '1'
                    uint16_t num = (uint16_t)va_arg(args, int);
                    send_octal16(num);
                }
                else {
                    // Formato desconocido, enviar literal
                    send_char('%');
                    send_char('o');
                    format--; // Retroceder para mostrar el caracter desconocido
                }
            }
            else {
                // Caracter desconocido después de %, lo enviamos tal cual
                send_char('%');
                send_char(*format);
            }
            format++; // Avanzar al siguiente caracter
        } else {
            send_char(*format);
            format++;
        }
    }
    
    va_end(args);
}



// Enviar un solo carácter
void send_char(char c) {
    while (!TXSTAbits.TRMT);
    TXREG = c;
}

// Función auxiliar para enviar dígitos
void send_digits(uint16_t num) {
    if (num >= 10) {
        send_digits(num / 10);
    }
    send_char('0' + (num % 10));
}

// Enviar número entero de 8 bits sin signo
void send_uint8(uint8_t num) {
    if (num == 0) {
        send_char('0');
        return;
    }
    send_digits(num);
}

// Enviar número entero de 16 bits sin signo
void send_uint16(uint16_t num) {
    if (num == 0) {
        send_char('0');
        return;
    }
    send_digits(num);
}

// Enviar número entero de 32 bits sin signo
void send_uint32(uint32_t num) {
    if (num == 0) {
        send_char('0');
        return;
    }
    send_digits32(num);
}

// Función auxiliar para enviar dígitos de 32 bits
void send_digits32(uint32_t num) {
    if (num >= 10) {
        send_digits32(num / 10);
    }
    send_char('0' + (num % 10));
}


// Enviar número entero con signo
void send_int(int num) {
    if (num < 0) {
        send_char('-');
        num = -num;
    }
    send_uint16((uint16_t)num);
}

void send_float(float num, uint8_t decimales) {
    // Parte entera
    int32_t entero = (int32_t)num;
    if(num < 0) {
        send_char('-');
        entero = -entero;
        num = -num;
    }
    send_digits32(entero);
    
    // Parte decimal
    send_char('.');
    float fraccion = num - (float)entero;
    for(uint8_t i = 0; i < decimales; i++) {
        fraccion *= 10.0f;
        uint8_t digito = (uint8_t)fraccion;
        send_char('0' + digito);
        fraccion -= digito;
    }
}


// Recibir carácter por UART (retorna 0 si no hay dato)
char receive_serial(void) {
    if (PIR1bits.RCIF) {
        if (RCSTAbits.OERR) {
            RCSTAbits.CREN = 0;
            RCSTAbits.CREN = 1;
        }
        return RCREG;
    }
    return 0;
}

// Retardos básicos
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i = 0; i < ms; i++) {
        for(j = 0; j < 1000; j++);
    }
}

void delay_us(unsigned int us) {
    unsigned int i;
    for(i = 0; i < us; i++);
}

// Enviar número en hexadecimal (8 bits)
void send_hex8(uint8_t num) {
    char nibble;
    //send_serial("0x");
    
    // Primer nibble (4 bits superiores)
    nibble = (num >> 4) & 0x0F;
    send_char(nibble > 9 ? ('A' + nibble - 10) : ('0' + nibble));
    
    // Segundo nibble (4 bits inferiores)
    nibble = num & 0x0F;
    send_char(nibble > 9 ? ('A' + nibble - 10) : ('0' + nibble));
}

// Enviar número en hexadecimal (16 bits)
void send_hex16(uint16_t num) {
    //send_serial("0x");
    send_hex8((uint8_t)(num >> 8));  // Byte alto
    send_hex8((uint8_t)num);         // Byte bajo
}

// Enviar número en octal (8 bits)
void send_octal8(uint8_t num) {
    send_char('0'); // Prefijo octal
    if (num < 8) {
        send_char('0' + num);
        return;
    }
    
    char buffer[4]; // Máximo 3 dígitos octal para 8 bits
    uint8_t i = 0;
    
    while (num > 0) {
        buffer[i++] = '0' + (num % 8);
        num /= 8;
    }
    
    // Imprimir en orden inverso
    while (i > 0) {
        send_char(buffer[--i]);
    }
}

// Enviar número en octal (16 bits)
void send_octal16(uint16_t num) {
    send_char('0'); // Prefijo octal
    if (num < 8) {
        send_char('0' + num);
        return;
    }
    
    char buffer[6]; // Máximo 6 dígitos octal para 16 bits
    uint8_t i = 0;
    
    while (num > 0) {
        buffer[i++] = '0' + (num % 8);
        num /= 8;
    }
    
    // Imprimir en orden inverso
    while (i > 0) {
        send_char(buffer[--i]);
    }
}

// Enviar número en binario (8 bits)
void send_binary8(uint8_t num) {
    send_serial("0b");
    for (int8_t i = 7; i >= 0; i--) {
        send_char((num & (1 << i)) ? '1' : '0');
    }
}

// Enviar número en binario (16 bits)
void send_binary16(uint16_t num) {
    send_serial("0b");
    for (int8_t i = 15; i >= 0; i--) {
        send_char((num & (1 << i)) ? '1' : '0');
    }
}

// Función para enviar una variable de cadena (array de caracteres)
void send_string(char *str) {
    while (*str != '\0') {  // Hasta encontrar el carácter nulo
        while (!TXSTAbits.TRMT); // Esperar buffer libre
        TXREG = *str++;
    }
}

uint8_t serial_available(void) {
    // Para PIC18F4550 con UART:
    return PIR1bits.RCIF;  // Retorna 1 si hay datos en el buffer de recepción
    
    // Alternativa genérica si RCIF no está disponible:
    // return RCREG;  // Lee el registro para ver si hay datos
}


