/*
 * A DMX receiver that filters out one channel and
 * sends it out via soft uart
 * used to display HD images on a Raspberry PI
 *
 * ATmega48A @ 8 MHz
 *
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "main.h"

volatile uint16_t soft_tx;          // data for soft UART
volatile uint8_t soft_tx_active;    // just for info, maybe needed later?

// main

int main(void) {

    // IO init

    DDRB  = (1<<PB1) | (1<<PB0);   // PB1: soft UART tx, PB0: TEST
    PORTB = 0xFF;       // internal pull ups
    DDRC  = 0x0;        // internal pull ups
    PORTC = 0xFF;
    DDRD  = 0;          // internal pull ups
    PORTD = 0xFF;

    // UART init
 
    UBRR0H = UBRR_VAL >> 8;
    UBRR0L = UBRR_VAL & 0xFF;

    // timer 1 init 
    // OCRA1 for soft UART tx
    // mode 0, prescaler 1

    TCCR1A = 0;
    TCCR1B = (1<<CS10);
 
    // activate UART for DMX reception
    UCSR0B = (1<<RXCIE0) | (1<<RXEN0);
    sei();

// endless main loop

    while (1) {
        set_sleep_mode(SLEEP_MODE_IDLE);
        sleep_mode();
    }
}

// UART RX complete interrupt

ISR(USART_RX_vect) {
    uint8_t status, data;
    static int16_t i, dmx_adr;

    // read UART data, also clears interrupt flag            
    status = UCSR0A;
    data = UDR0;

    if (status & (1<<FE0)) {                // frame error     
        if (data==0) {                      // break -> DMX Reset
            //TEST_HIGH;
            i = -1;
            READ_DMX_ADR;
            //SEND_SOFT_UART(dmx_adr);
        }
    } else {                                // normal reception
        //TEST_LOW;
        i++;
        if (i == dmx_adr && !soft_tx_active) {            
            // send data via soft UART
            SEND_SOFT_UART(data);
            TEST_HIGH;
        } else TEST_LOW;
    }
    
}

// Timer 1 Output COMPARE A Interrupt
// driver for hybrid UART TX

ISR(TIMER1_COMPA_vect) {

    uint16_t tmp = soft_tx;

    if (tmp == 0) {
        TIMSK1 &= ~(1<<OCIE1A);   // disable ISR, we are done
        soft_tx_active = 0;
    } else {   
        // next bit
        OCR1A += BIT_TIME;
        if (tmp & 1) {                          // UART sends LSB first
            TCCR1A = (1<<COM1A1) | (1<<COM1A0); // set output
        } else {
            TCCR1A = (1<<COM1A1);               // clear output
        }
        soft_tx = tmp >> 1;
    }
}