/******************************************************************************!
 * \file main.c
 * \author Sebastien Beaugrand
 * \sa http://beaugrand.chez.com/
 * \copyright CeCILL 2.1 Free Software license
 * \note Source: https://github.com/jpiat/arduino
 ******************************************************************************/
#include <util/atomic.h>
#include "tinyX5.h"
#define F_CPU 1000000UL
#include "timer1.h"
#include "lifi.h"

#ifdef MESSAGE
const char* gMessage = MESSAGE;
#endif

unsigned char frame_buffer[DATA_SIZE_MAX + 6];  // Buffer for frame
volatile int8_t frame_index = -1;  // Index in frame
int8_t frame_size = -1;  // Size of the frame to be sent

// State variables of the manchester encoder
unsigned char bit_counter = WORD_LENGTH << 1;
unsigned long int manchester_data = 0xFFFFFFFF;

/******************************************************************************!
 * \fn toManchester
 ******************************************************************************/
void toManchester(unsigned char data, unsigned long int* data_manchester)
{
    unsigned int i;
    *data_manchester = 0x02;  // STOP symbol
    *data_manchester <<= 2;
    for (i = 0; i < 8; i++) {
        if (data & 0x80) {
            *data_manchester |= 0x02;  // Data LSB first
        } else {
            *data_manchester |= 0x01;
        }
        *data_manchester <<= 2;
        data = data << 1;  // To next bit
    }
    *data_manchester |= 0x01;  // START symbol
}

/******************************************************************************!
 * \fn TIMER1_COMPA_vect
 ******************************************************************************/
ISR(TIMER1_COMPA_vect)
{
    if (manchester_data & 0x01) {
        digitalWrite(A_PINB0, 1);
    } else {
        digitalWrite(A_PINB0, 0);
    }
    bit_counter--;
    manchester_data >>= 1;
    if (bit_counter == 0) {
        if (frame_index >= 0) {
            if (frame_index < frame_size) {
                toManchester(frame_buffer[frame_index], &manchester_data);
                frame_index++;
            } else {
                frame_index = -1;
                frame_size = -1;
            }
        }
        bit_counter = WORD_LENGTH << 1;
    }
}

/******************************************************************************!
 * \fn write
 ******************************************************************************/
int write(const char* data, int data_size)
{
    if (frame_index >= 0) {
        return -1;
    }
    if (data_size > DATA_SIZE_MAX) {
        return -1;
    }
    memcpy(&(frame_buffer[5]), data, data_size);
    frame_buffer[5 + data_size] = ETX;
    cli();
    frame_index = 0;
    frame_size = data_size + 6;
    sei();
    return 0;
}

/******************************************************************************!
 * \fn setup
 ******************************************************************************/
void setup()
{
    pinMode(A_PINB0, OUTPUT);

    // Init frame
    memset(frame_buffer, 0xAA, 3);
    frame_buffer[3] = SYNC_SYMBOL;
    frame_buffer[4] = STX;

    // Timer
    timer1SetPeriod(SYMBOL_PERIOD);

#   ifdef MESSAGE
    int len = strlen(gMessage);
    int pos = 0;
    while (len > 0) {
        if (write(gMessage + pos,
                  (len < DATA_SIZE_MAX) ? len : DATA_SIZE_MAX) < 0) {
        } else {
            len -= DATA_SIZE_MAX;
            pos += DATA_SIZE_MAX;
        }
    }
#   endif
}

/******************************************************************************!
 * \fn loop
 ******************************************************************************/
void loop()
{
#   ifndef MESSAGE
    static char* msg = "Hello World";

    if (write(msg, 11) < 0) {
    }
#   endif
}

/******************************************************************************!
 * \fn main
 ******************************************************************************/
int main()
{
    setup();
    for (;;) {
        loop();
    }
}