//
//  comunication.c
//  nrf24
//
//  Created by Richard Kuckovsky on 29.4.17.
//  Copyright © 2017 Richard Kuckovsky. All rights reserved.
//

#include "comunication.h"

#include <stdio.h>
#include <string.h>

#ifndef _TIMESTAMP
#define _TIMESTAMP 0
#endif

volatile bool end_timer = false;

int last_message_id = 0;



nRF24L01 *comunication_init() {
    
    nRF24L01 *rf = nRF24L01_init();
    
    rf->ss.port = &PORTB;
    rf->ss.pin = PB1;
    rf->ce.port = &PORTB;
    rf->ce.pin = PB0;
    rf->sck.port = &PORTB;
    rf->sck.pin = PB5;
    rf->mosi.port = &PORTB;
    rf->mosi.pin = PB3;
    rf->miso.port = &PORTB;
    rf->miso.pin = PB4;
    
    nRF24L01_begin(rf);

    
    return rf;
}


bool send_data(nRF24L01 *rf, char *buff, uint8_t rpi, uint8_t address, char data[28], int max_round) {
    
    payload_data send, recieved;
    
    int round = 0;
    bool again = true;
    
    int id = rand() % 50000+1; // id poziadavky
    
    nRF24L01_stop_listen(rf);
    
    while(again) {
        
        send.rpi = rpi; // adresa RPI
        send.modul = address; // adresa modulu
        send.type = 0x02; // odosielanie z modulu
        send.id = id;
        
        memcpy(send.mes, data, 28);
        
        nRF24L01_transmit(rf, &send);
        _delay_us(400);
        nRF24L01_flush_transmit_message(rf);
        nRF24L01_start_listen(rf);
        
        start_timer();
        bool timeout = false;
        while (!(nRF24L01_data_received(rf) || end_timer)) {
            //_delay_us(10);
        }
        nRF24L01_stop_listen(rf);
        
        if (end_timer) {
            timeout = true;
        }
        stop_timer();
        
        if (timeout) {
            round++;
            if(round > max_round) {
                again = false;
            }
        } else {
            
            while(nRF24L01_data_received(rf)){
                nRF24L01_read_received_data(rf, &recieved);
            }
            
            if(recieved.id == send.id && recieved.type == 0x01) {
                again = false;
                strncpy(buff,recieved.mes, 28);
                return true;
            }
        }
    }
    
    return false;
}


void recieve_data(nRF24L01 *rf, char *buff) {
    payload_data recieved, response;
    
    while(nRF24L01_data_received(rf)){
        nRF24L01_read_received_data(rf, &recieved);
    }
    
    if(recieved.modul == module.address && recieved.type == 0x00 && recieved.rpi == module.rpi) {
        
        response.rpi = recieved.rpi; // adresa RPI
        response.modul = module.address; // adresa cieloveho modulu
        response.type = 0x03; // odpoved
        response.id = recieved.id; // id poziadavky
        
        memcpy(response.mes, status, 28);
        
        nRF24L01_stop_listen(rf);
        nRF24L01_flush_transmit_message(rf);
        
        nRF24L01_transmit(rf, &response);
        _delay_us(400);
        
        if(recieved.id == last_message_id) {
            strncpy(buff,"0", 28);
        } else {
            strncpy(buff,recieved.mes, 28);
            last_message_id = recieved.id;
        }
        
    } else if (recieved.modul == module.address && recieved.type == 0x05 && recieved.rpi == module.rpi) {
        
        response.rpi = recieved.rpi; // adresa RPI
        response.modul = module.address; // adresa modulu
        response.type = 0x03; // odosielanie z modulu
        response.id = recieved.id; // id poziadavky
        
        memcpy(response.mes, recieved.mes, 28);
        
        nRF24L01_transmit(rf, &response);
        _delay_us(400);
        
        strncpy(buff,"0", 28);
    } else {
        strncpy(buff,"0", 28);
    }
    
    nRF24L01_flush_recieve_message(rf);
    nRF24L01_flush_transmit_message(rf);
    
    nRF24L01_start_listen(rf);
    
    return;
    
}


bool module_init(nRF24L01 *rf) {
    eeprom data = get_eeprom();
    
    nRF24L01_set_recieve_address(rf, data.rx_pipe);
    nRF24L01_set_recieve2_address(rf, data.rx2_pipe);
    nRF24L01_set_transmit_address(rf, data.tx_pipe);
    
    if(!data.is_init) {
        int hash;
        if(!data.is_hash) {
            srand(_TIMESTAMP);
            hash = rand();
            data.is_hash = true;
            data.hash  = hash;
            
            set_eeprom(data);
        } else {
            hash = data.hash;
        }
        
        bool again = true;
        
        while(again) {
            
            
            payload_data send, recieved;
            
            send.rpi = 0x00; // adresa RPI
            send.modul = 0x00; // adresa modulu
            send.type = 0x04; // odosielanie z modulu
            send.id = rand() % 50000+1; // id poziadavky
            
            char temp[28];
            sprintf(temp, "b %08X", hash);
            memcpy(send.mes, temp, 28);
            
            nRF24L01_flush_transmit_message(rf);
            nRF24L01_transmit(rf, &send);
            
            _delay_us(400);
            
            nRF24L01_start_listen(rf);
            
            int i = 0;
            while (!(nRF24L01_data_received(rf) || i > 30000)) {
                i++;
                _delay_us(100);
            }
            
            nRF24L01_stop_listen(rf);
            if (i < 30000) {
                nRF24L01_read_received_data(rf, &recieved);
                
                if(recieved.type == 0x05) {

                    unsigned long recieved_hash  = (long)strtol(recieved.mes, NULL, 16);
                    if(recieved_hash == hash) {
                        
                        send.rpi = recieved.rpi; // adresa RPI
                        send.modul = recieved.modul; // adresa modulu
                        send.type = 0x03; // odosielanie z modulu
                        send.id = recieved.id; // id poziadavky
                        memcpy(send.mes, recieved.mes, 28);
                        
                        nRF24L01_flush_transmit_message(rf);
                        nRF24L01_transmit(rf, &send);
                        _delay_us(400);
                        char pipe[2];
                        
                        pipe[0] = recieved.mes[9];
                        pipe[1] = recieved.mes[10];
                        uint8_t rx_pipe = strtol(pipe, NULL, 16);
                        
                        pipe[0] = recieved.mes[11];
                        pipe[1] = recieved.mes[12];
                        uint8_t tx_pipe = strtol(pipe, NULL, 16);
                        
                        data.is_init = true;
                        data.rpi = recieved.rpi;
                        data.address = recieved.modul;
                        data.rx_pipe[0] = rx_pipe;
                        data.tx_pipe[0] = tx_pipe;
                        
                        set_eeprom(data);
                        
                        module.rpi = data.rpi;
                        module.address = data.address;
                        
                        nRF24L01_set_recieve_address(rf, data.rx_pipe);
                        nRF24L01_set_recieve2_address(rf, data.rx2_pipe);
                        nRF24L01_set_transmit_address(rf, data.tx_pipe);
                        again = false;
                    }
                }
            } else {
                again = true;
            }
            
        }
    } else {
        srand(data.srand);
        data.srand = rand() % 60000;
        set_eeprom(data);
        
        module.rpi = data.rpi;
        module.address = data.address;
    }
    
    return true;
}

eeprom get_eeprom(void) {
    eeprom temp;
    eeprom_read_block((void*)&temp, (void*)0, sizeof(eeprom));
    return temp;
}

void set_eeprom(eeprom data) {
    eeprom_update_block((void*)&data, (void*)0, sizeof(eeprom));
}

void erase_eeprom() {
    eeprom data;
    data.is_init = false;
    data.is_hash = false;
    data.hash = 0;
    data.rpi = 0;
    data.address = 0;
    uint8_t rx[5] = {0xAA, 0x96, 0x67, 0x89, 0x67};
    memcpy(data.rx_pipe, rx, 5);
    memcpy(data.rx2_pipe, rx, 5);
    uint8_t tx[5] = {0xAB, 0x96, 0x67, 0x89, 0x67};
    memcpy(data.tx_pipe, tx, 5);

    eeprom_write_block((void*)&data, (void*)0, sizeof(eeprom));
    
    char empty[28] = "                            ";
    eeprom_write_block((void*)&empty, (void*)sizeof(eeprom), sizeof(empty));
}

void save_status(void) {
    eeprom_write_block((void*)&status, (void*)sizeof(eeprom), sizeof(status));
}
void load_status(void) {
    char temp[28];
    eeprom_read_block((void*)&temp, (void*)sizeof(eeprom), sizeof(status));
    memcpy(status, temp, sizeof(status));
}

void start_timer(void) {
    OCR1A = 32000;
    TCCR1B |= (1 << WGM12);
    // Mode 4, CTC on OCR1A
    
    TIMSK1 |= (1 << OCIE1A);
    //Set interrupt on compare match
    
    TCCR1B |= (1 << CS10);

}

void stop_timer(void) {
    TCCR1B &= ~_BV(CS10);
    end_timer = false;
}

ISR(TIMER1_COMPA_vect) {
    OCR1A = 0;
    end_timer = true;
}


