/* Name: main.c
 * Author: <insert your name here>
 * Copyright: <insert your copyright message here>
 * License: <insert your license reference here>
 */

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

#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 100 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define settle_delay() _delay_us(100) // settle delay
#define char_delay() _delay_ms(10) // char delay
#define nloop 100 // loops to accumulate

#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB2)
#define transmit_port PORTB
#define transmit_direction DDRB
#define transmit_pin (1 << PB4)

#define led_port PORTB
#define led_direction DDRB
#define led0_pin (1 << PB0)
#define led1_pin (1 << PB1)

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
    //
    // send character in txchar on port pin
    //    assumes line driver (inverts bits)
    //
    // start bit
    //
    clear(*port,pin);
    bit_delay();
    //
    // unrolled loop to write data bits
    //
    if bit_test(txchar,0)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,1)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,2)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,3)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,4)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,5)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,6)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    if bit_test(txchar,7)
        set(*port,pin);
    else
        clear(*port,pin);
    bit_delay();
    //
    // stop bit
    //
    set(*port,pin);
    bit_delay();
    //
    // char delay
    //
    bit_delay();
}


void put_string(volatile unsigned char *port, unsigned char pin, char *str) {
    static int index;
    //
    // print a null-terminated string
    //
    // JWF !! Sending an empty string will fail !!
    index = 0;
    do {
        put_char(port, pin, str[index]);
        ++index;
    } while (str[index] != 0);
}


int main(void) {
    
    char temp[32];
    unsigned char state = 0;
    unsigned char leds = 0;
    
    //
    // main
    //
    static unsigned char count;
    static uint16_t up,down;
    //
    // set clock divider to /1
    //
    CLKPR = (1 << CLKPCE);
    CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
    //
    // initialize output pins
    //
    set(serial_port, serial_pin_out);
    output(serial_direction, serial_pin_out);
    clear(transmit_port, transmit_pin);
    output(transmit_direction, transmit_pin);
    
    output(led_direction, led0_pin);
    set(led_port, led0_pin);
    output(led_direction, led1_pin);
    clear(led_port, led1_pin);
    
    //
    // init A/D
    //
    ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // Vcc ref
    | (0 << ADLAR) // right adjust
    | (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0); // PB3
    ADCSRA = (1 << ADEN) // enable
    | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
    //
    // main loop
    //
    while (1) {
        //
        // accumulate
        //
        up = 0;
        down = 0;
        for (count = 0; count < nloop; ++count) {
            //
            // settle, charge
            //
            settle_delay();
            set(transmit_port, transmit_pin);
            //
            // initiate conversion
            //
            ADCSRA |= (1 << ADSC);
            //
            // wait for completion
            //
            while (ADCSRA & (1 << ADSC))
                ;
            //
            // save result
            //
            up += ADC;
            //
            // settle, discharge
            //
            settle_delay();
            clear(transmit_port, transmit_pin);
            //
            // initiate conversion
            //
            ADCSRA |= (1 << ADSC);
            //
            // wait for completion
            //
            while (ADCSRA & (1 << ADSC))
                ;
            //
            // save result
            //
            down += ADC;
        }
        
        if((abs(up-down) > 5000))
        {
            //if(state == 0)
            {
                leds++;
                state = 1;
            }
        }
        else
            state = 0;
        
        PORTB &= 0xfc;
        PORTB |= (~leds & 0x03);
        
        
#if 0
        sprintf(temp, "up: %d, down: %d\r\n", up, down);
        put_string(&serial_port, serial_pin_out, temp);
#else
        //
        // send framing
        //
        put_char(&serial_port, serial_pin_out, 1);
        char_delay();
        put_char(&serial_port, serial_pin_out, 2);
        char_delay();
        put_char(&serial_port, serial_pin_out, 3);
        char_delay();
        put_char(&serial_port, serial_pin_out, 4);
        
        //
        // send result
        //
        put_char(&serial_port, serial_pin_out, (up & 255));
        char_delay();
        put_char(&serial_port, serial_pin_out, ((up >> 8) & 255));
        char_delay();
        put_char(&serial_port, serial_pin_out, (down & 255));
        char_delay();
        put_char(&serial_port, serial_pin_out, ((down >> 8) & 255));
        char_delay();
#endif
    }
}