#include <avr/io.h>
#include <util/delay.h>

#define BAUD 9600
#define BAUD_PRESCALER (((F_CPU / (BAUD * 16UL))) - 1)

void UART_init(void) {
    UBRR0H = (BAUD_PRESCALER >> 8);
    UBRR0L = BAUD_PRESCALER;
    UCSR0B = (1 << TXEN0) | (1 << RXEN0);    // Enable transmitter and receiver
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 8 data bits, 1 stop bit
}

void UART_send_char(char c) {
    while (!(UCSR0A & (1 << UDRE0))); // Wait for empty transmit buffer
    UDR0 = c;
}

void UART_send_string(const char *str) {
    while (*str) {
        UART_send_char(*str++);
    }
}

char UART_receive_char(void) {
    while (!(UCSR0A & (1 << RXC0))); // Wait for data to be received
    return UDR0;                     // Get and return received data from buffer
}

void UART_receive_string(char *buffer, uint8_t buffer_size) {
    uint8_t i = 0;
    char received_char;
    while (i < (buffer_size - 1)) {
        received_char = UART_receive_char();
        if (received_char == '\n') { // Check for newline character
            break;
        }
        buffer[i++] = received_char;
    }
    buffer[i] = '\0'; // Null-terminate the string
}

void ADC_init() {
    ADMUX = (1 << REFS0); // AVcc as reference
    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // Enable ADC, prescaler 64
}

uint16_t ADC_read(uint8_t channel) {
    ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);
    ADCSRA |= (1 << ADSC);
    while (ADCSRA & (1 << ADSC));
    return ADC;
}

int main(void) {
    UART_init();
    ADC_init();

    char buffer[10];
    uint16_t adc_value;
    float temperature;

    while (1) {
        // Send temperature data
        adc_value = ADC_read(0); // Read ADC value from channel 0
        temperature = (adc_value / 1024.0) * 500.0; // Convert to Celsius for LM35

        // Convert temperature to string and send over UART
        snprintf(buffer, sizeof(buffer), "%.2f\n", temperature);
        UART_send_string(buffer);

        _delay_ms(1000); // Send every second

        // Receive a message if available (example usage)
        char received_data[10];
        UART_receive_string(received_data, sizeof(received_data));

        // Here, we could process the received data if needed
        // Example: if (strcmp(received_data, "READ") == 0) { ... }
    }
    return 0;
}