/**********************************************************************
* nrf24l01 lib                                                        *
*                                                                     *
* Copyright (c) Davide Gironi, 2012                                   *
* http://davidegironi.blogspot.com/                                   *
*                                                                     *
* References:                                                         *
*    This library is based upon nRF24L01 avr lib by Stefan Engelke    *
*    http://www.tinkerer.eu/AVRLib/nRF24L01                           *
**********************************************************************/

/**********************************************************************
* This library is free software; you can redistribute it and/or       *
* modify it under the terms of the GNU Lesser General Public          *
* License as published by the Free Software Foundation.               *
*                                                                     *
* This library is distributed in the hope that it will be useful,     *
* but WITHOUT ANY WARRANTY; without even the implied warranty of      *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   *
* Lesser General Public License for more details.                     *
*                                                                     *
* You should have received a copy of the GNU Lesser General Public    *
* License along with this library; if not, write to the               *
* Free Software Foundation, Inc.,                                     *
* 59 Temple Place, Suite 330,                                         *
* Boston, MA                                                          *
* 02111-1307                                                          *
* USA                                                                 *
*                                                                     *
* For further information, visit www.gnu.org
* http://www.tinkerer.eu/AVRLib/nRF24L01/                       *
**********************************************************************/

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

#include "mirf.h"
#include "nRF24L01.h"

uint8_t self_addr[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0x23};
uint8_t remote_addr[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0x22};

//initialize spi
void spi_init()
{
    DDR_SPI &= ~( (1<<SPI_MOSI) | (1<<SPI_MISO) | (1<<SPI_SS) | (1<<SPI_SCK) );
    DDR_SPI |= ( (1<<SPI_MOSI) | (1<<SPI_SS) | (1<<SPI_SCK) );

    SPCR = ((1<<SPE)|               // SPI Enable
            (0<<SPIE)|              // SPI Interupt Enable
            (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
            (1<<MSTR)|              // Master/Slave select
            (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate foc/8
			//(1<<SPR1)|(1<<SPR0)|    // SPI Clock Rate foc/128
            (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
            (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)

    SPSR = (1<<SPI2X); // double spi speed bit
}

//spi write one byte and read it back
uint8_t spi_writeread(uint8_t data)
{
    SPDR = data;
    while((SPSR & (1<<SPIF)) == 0);
    return SPDR;
}

//initialize mirf
void mirf_init() 
{
    DDRB |= ( (1<<CSN) | (1<<CE) );

    mirf_CE_lo;
    mirf_CSN_hi;

    spi_init();
}


//config mirf
uint8_t mirf_config()
{

	mirf_write_register(EN_AA,(1<<ENAA_P0));													// включение автоподтверждения только по каналу 0
	mirf_write_register(EN_RXADDR, (1 << ERX_P0) | (1 << ERX_P1)); 								// включение каналов 0 и 1
	mirf_write_register(SETUP_AW, SETUP_AW_5BYTES_ADDRESS); 									// выбор длины адреса 5 байт
	mirf_write_register(SETUP_RETR, SETUP_RETR_DELAY_1500MKS | SETUP_RETR_UP_TO_5_RETRANSMIT);	// задаем ждать подтверждение от принимающего 1,500мс и пять попыткот нас до него достучаться
	mirf_write_register(RF_SETUP, RF_SETUP_250KBPS | RF_SETUP_0DBM); 							// выбор скорости 250 кбит/с и мощности 0dBm
    mirf_write_register(RF_CH, mirf_CH);														// задаем канал преима/передачи

/*
    // адресация для приемника
	mirf_write_registers(TX_ADDR, remote_addr, 5);												// передаем для преимника с конкретным адресом, Значение регистра по умолчанию: 0xE7E7E7E7E7
	mirf_write_registers(RX_ADDR_P0, remote_addr, 5);											// ждем подтверждения от приемника по этому адресу, Значение регистра по умолчанию: 0xE7E7E7E7E7
	mirf_write_registers(RX_ADDR_P1, self_addr, 5);												// ждем приема (не подтверждения) на первый пайп, Значение регистра по умолчанию: 0xC2C2C2C2C2
*/

/*
	// адресация для передатчика
	mirf_write_registers(TX_ADDR, self_addr, 5);											// передаем для преимника с конкретным адресо, Значение регистра по умолчанию: 0xE7E7E7E7E7
	mirf_write_registers(RX_ADDR_P0, self_addr, 5);											// ждем подтверждения от приемника по этому адресу, Значение регистра по умолчанию: 0xE7E7E7E7E7
	mirf_write_registers(RX_ADDR_P1, remote_addr, 5);										// ждем приема (не подтверждения) на первый пайп, Значение регистра по умолчанию: 0xC2C2C2C2C2
*/

    if (mirf_PAYLOAD!=0){
    	// настраиваем отправку данных фиксированной длинны
    	mirf_write_register(RX_PW_P0, mirf_PAYLOAD); 											//length of incoming payload
    	mirf_write_register(FEATURE,(0 << EN_DPL) | (1<<EN_ACK_PAY) | (1<<EN_DYN_ACK));			// запрещаем произвольную длинну пакета и включаем возможность  отправки с подтверждение и без
    }else{
	// настраиваем отправку данных произвольной длинны с автоподтверждением
    	mirf_write_register(FEATURE,(1 << EN_DPL) | (1<<EN_ACK_PAY) | (1<<EN_DYN_ACK));			// разрешаем произвольную длинну пакета и включаем возможность  отправки с подтверждение и без
    	mirf_write_register(DYNPD, (1 << DPL_P0)); 												// включение произвольной длины для канала 0
	}
    mirf_write_register(CONFIG, (1 << EN_CRC) | (1 << CRCO) | (1 << PWR_UP) | (1 << PRIM_RX)); 	// Включение CRC, питания и переход на прием

    mirf_setRX; // rx mode
    _delay_ms(20);
    mirf_CE_hi;
    return 1;
}


//set tx address
void mirf_set_txaddr(uint8_t *addr)
{
    mirf_write_registers(TX_ADDR, addr, 5);
}

//get status
uint8_t mirf_get_status()
{
	uint8_t status = 0;
	mirf_CSN_lo;
	status = spi_writeread(NOP);
	mirf_CSN_hi;
	return status;
}

//read one register
uint8_t mirf_read_register(uint8_t reg)
{
	mirf_CSN_lo;
	spi_writeread(R_REGISTER | (REGISTER_MASK & reg));
    uint8_t result = spi_writeread(NOP);
    mirf_CSN_hi;
    return result;
}

//read many registers
void mirf_read_registers(uint8_t reg, uint8_t *value, uint8_t len)
{
    mirf_CSN_lo;
    spi_writeread(R_REGISTER | (REGISTER_MASK & reg));
	for (uint8_t i = 0; i < len; i++)
		value[i] = spi_writeread(NOP);
    mirf_CSN_hi;
}

//write one register
void mirf_write_register(uint8_t reg, uint8_t value)
{
	mirf_CSN_lo;
	spi_writeread(W_REGISTER | (REGISTER_MASK & reg));
	spi_writeread(value);
	mirf_CSN_hi;
}

//write many registers
void mirf_write_registers(uint8_t reg, uint8_t *value, uint8_t len)
{
    mirf_CSN_lo;
    spi_writeread(W_REGISTER | (REGISTER_MASK & reg));
	for (uint8_t i = 0; i < len; i++)
		 spi_writeread(value[i]);
    mirf_CSN_hi;
}

//check if there is rx data
uint8_t mirf_read_ready()
{
    uint8_t status = mirf_get_status();
    return status & (1<<RX_DR);
}

//read data
void mirf_read(uint8_t *data)
{
	//read rx register
    mirf_CSN_lo;
    spi_writeread( R_RX_PAYLOAD );
    for (uint8_t i = 0; i < mirf_PAYLOAD; i++)
    	data[i] = spi_writeread(NOP);
    mirf_CSN_hi;
    //reset register
    mirf_write_register(STATUS,(1<<RX_DR));
}

uint8_t nrf24_retransmissionCount()
{
    
    
    return (mirf_read_register(OBSERVE_TX)&0x0F);
}

uint8_t nrf24_isSending()
{

    /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */
    if((mirf_get_status()&((1 << TX_DS)|(1 << MAX_RT))))
    {        
        return 0; /* false */
    }

    return 1; /* true */

}

uint8_t nrf24_lastMessageStatus()
{
    uint8_t rv;

    rv = mirf_get_status();

    /* Transmission went OK */
    if((rv & ((1 << TX_DS))))
    {
        return 1;
    }
    /* Maximum retransmission count is reached */
    /* Last message probably went missing ... */
    else if((rv & ((1 << MAX_RT))))
    {
        return 2;
    }  
    /* Probably still sending ... */
    else
    {
        return 0xFF;
    }
}

/**
 *
return 1 - Transmission went OK
return 2 - Maximum retransmission count is reached
return 0xFF - Probably still sending
return 3 - powerdown
 */
//write data
uint8_t mirf_write(char *data, uint8_t data_lenght)
{
	uint8_t ACK_OK = 0;
	uint8_t conf = mirf_read_register(CONFIG);
	  if (!(conf & (1 << PWR_UP))){ // Если питание по какой-то причине отключено, возвращаемся с ошибкой
		  printf_P(PSTR("CONFIG1\t\t = %02d MASK_RX_DR=%x MASK_TX_DS=%x MASK_MAX_RT=%x EN_CRC=%x CRCO=%x PWR_UP=%x PRIM_RX=%x\r"),
				  conf,
		        	(conf & _BV(MASK_RX_DR))?1:0,
		        	(conf & _BV(MASK_TX_DS))?1:0,
		            (conf & _BV(MASK_MAX_RT))?1:0,
		            (conf & _BV(EN_CRC))?1:0,
		            (conf & _BV(CRCO))?1:0,
		            (conf & _BV(PWR_UP))?1:0,
		            (conf & _BV(PRIM_RX))?1:0
		  );
		  return 3;
	  }
	//set tx mode
	mirf_CE_lo;
	mirf_setTX;
	_delay_us(210);

	//flush tx fifo
	//mirf_send_cmd(FLUSH_TX);

	//write data
	mirf_CSN_lo;
	spi_writeread( W_TX_PAYLOAD );
	for (uint8_t i = 0; i < data_lenght; i++)
		spi_writeread(data[i]);
	mirf_CSN_hi;

	//start transmission
	mirf_CE_hi;
	_delay_us(20);
	mirf_CE_lo;

	//wait for the transmission to stop
//	ACK_OK = 1;

	while(nrf24_isSending());	//крутимся, пока не дождемся успешной передачи либо всех попыток передачи
	ACK_OK=nrf24_lastMessageStatus();
	nrf_print_observe_tx();

	mirf_write_register(STATUS,((1<<TX_DS)|(1<<MAX_RT)));	//обнуляем флаги прерываний

	if (ACK_OK==2){
		// Достигнуто максиумум попыток доставки, но пакет еще в очереди, нужо его сбросить из очереди
		//flush tx fifo
		mirf_send_cmd(FLUSH_TX);
	}
	//set rx mode
	mirf_setRX;
	_delay_us(135);
	mirf_CE_hi;
	return ACK_OK;
}

// читает разу строку указанной длинны из NRF (испольуется для динамического payload)
void mirf_read_buf(uint8_t *data, uint8_t lenght)
{
	//read rx register
    mirf_CSN_lo;
    spi_writeread( R_RX_PAYLOAD );
    for (uint8_t i = 0; i < lenght; i++)
    	data[i] = spi_writeread(NOP);
    mirf_CSN_hi;
    //reset register
    //mirf_write_register(STATUS,(1<<RX_DR));
}

// Возвращает размер данных в начале FIFO очереди приёмника
uint8_t radio_read_rx_payload_width() {
  mirf_CSN_lo;
  spi_writeread(R_RX_PL_WID);
  uint8_t answ = spi_writeread(NOP);
  mirf_CSN_hi;
  return answ;
}

// переводим nrf в режим Standby
void mirf_power_up(void)
{
  uint8_t _config = spi_writeread(CONFIG);
  _config|=(1<<PWR_UP);						// ставим PWR_UP
  mirf_write_register(CONFIG, _config);
  _delay_ms(4);								// ждем устаканивания переходных процессов
  // ждем пока PWR_UP не установится в единицу
  while(!(mirf_read_register(CONFIG) & _BV(PWR_UP)));
  mirf_CE_hi;
}

// вгоняем nrf в power down
void mirf_power_down(void)
{
	  uint8_t _config = mirf_read_register(CONFIG);
	  _config &= ~(1<<PWR_UP);					// снимаем PWR_UP и вгоняем nrf в сон
	  mirf_write_register(CONFIG, _config);

	  // ждем пока PWR_UP не установится в ноль
	  while(mirf_read_register(CONFIG) & _BV(PWR_UP));
	  mirf_CE_lo;
}

void nrf_print_status(void)
{
uint8_t status=0;
status=mirf_get_status();
  printf_P(PSTR("STATUS\t\t = 0x%02X RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r"),
           status,
           (status & _BV(RX_DR))?1:0,
           (status & _BV(TX_DS))?1:0,
           (status & _BV(MAX_RT))?1:0,
           ((status >> RX_P_NO) & 0b111),
           (status & _BV(TX_FULL))?1:0
          );
}

void nrf_print_config(void)
{
uint8_t status=0;
status=mirf_read_register(CONFIG);
  printf_P(PSTR("CONFIG\t\t = 0x%02X MASK_RX_DR=%x MASK_TX_DS=%x MASK_MAX_RT=%x EN_CRC=%x CRCO=%x PWR_UP=%x PRIM_RX=%x\r"),
           status,
        	(status & _BV(MASK_RX_DR))?1:0,
        	(status & _BV(MASK_TX_DS))?1:0,
            (status & _BV(MASK_MAX_RT))?1:0,
            (status & _BV(EN_CRC))?1:0,
            (status & _BV(CRCO))?1:0,
            (status & _BV(PWR_UP))?1:0,
            (status & _BV(PRIM_RX))?1:0
  );
}

void nrf_print_setup(void)
{
uint8_t status=0;
status=mirf_read_register(RF_SETUP);
  printf_P(PSTR("RF_SETUP\t\t = 0x%02X CONT_WAVE=%x  RF_DR_LOW=%x PLL_LOCK=%x RF_DR_HIGH=%x RF_PWR=%x LNA_HCURR=%x\r"),
           status,
           (status & _BV(CONT_WAVE))?1:0,
           (status & _BV(RF_DR_LOW))?1:0,
           (status & _BV(PLL_LOCK))?1:0,
           (status & _BV(RF_DR_HIGH))?1:0,
 		   ((status >> RF_PWR) & 0b11),
           (status & _BV(LNA_HCURR))?1:0
        	  );
}
void nrf_print_future(void)
{
uint8_t status=0;
status=mirf_read_register(FEATURE);
  printf_P(PSTR("FEATURE\t\t = 0x%02X EN_DPL=%x  EN_ACK_PAY=%x EN_DYN_ACK=%x\r"),
           status,
           (status & _BV(EN_DPL))?1:0,
           (status & _BV(EN_ACK_PAY))?1:0,
           (status & _BV(EN_DYN_ACK))?1:0
        	  );
}

void print_sprintf(const char* name,uint8_t reg){
	printf(name, reg);

}
// отправляем комманду в NRF
void mirf_send_cmd(uint8_t reg) {
	mirf_CSN_lo;
	spi_writeread(reg);
	mirf_CSN_hi;
}
void nrf_print_fifostatus(void) {
	uint8_t status = 0;
	status = mirf_read_register(FIFO_STATUS);
	printf_P(PSTR("FIFO_STATUS\t\t = 0x%02X\r"), status);
}
void nrf_print_cd(void) {
	printf_P(PSTR("CD=0x%02X\r"), mirf_read_register(CD));
}

void nrf_print_chanel(void) {
	printf_P(PSTR("CHANEL=0x%02X\r"), mirf_read_register(RF_CH));
}

void nrf_print_payload(void) {
	printf_P(PSTR("L_PAYLOAD=0x%02X\r"), mirf_read_register(RX_PW_P0));
}

void nrf_print_observe_tx(void)
{
uint8_t status=0;
status=mirf_read_register(OBSERVE_TX);
printf_P(PSTR("OBSERVE_TX=0x%02X POLS_CNT=%X ARC_CNT=%X\r"),
		status,
           (status >> PLOS_CNT) & 0b1111,
           (status >> ARC_CNT) & 0b1111
);
}

void nrf_print_tx_addr(void) {
	uint8_t addr[5] = { 0, 0, 0, 0, 0 };
	mirf_read_registers(TX_ADDR, addr, 5);
	printf_P(PSTR("TX_ADDR="));

	// выводим в терминал  байты
	for (uint8_t i = 0; i < sizeof(addr); i++) {
		printf_P(PSTR("0x%02X "), addr[i]);
	}
	printf_P(PSTR("\r"));

}

void nrf_print_rx_addr_p0(void) {
	uint8_t addr[5] = { 0, 0, 0, 0, 0 };
	mirf_read_registers(RX_ADDR_P0, addr, 5);
	printf_P(PSTR("RX_ADDR_P0="));

	// выводим в терминал  байты
	for (uint8_t i = 0; i < sizeof(addr); i++) {
		printf_P(PSTR("0x%02X "), addr[i]);
	}
	printf_P(PSTR("\r"));

}


void nrf_print_rx_addr_p1(void) {
	uint8_t addr[5] = { 0, 0, 0, 0, 0 };
	mirf_read_registers(RX_ADDR_P1, addr, 5);
	printf_P(PSTR("RX_ADDR_P1="));

	// выводим в терминал  байты
	for (uint8_t i = 0; i < sizeof(addr); i++) {
		printf_P(PSTR("0x%02X "), addr[i]);
	}
	printf_P(PSTR("\r"));

}

/**
 * Функция очищает буфер приемника от всех пакетов
 */
void nrf_clear_tx_buffer(void) {
while ((mirf_read_register(STATUS)& (7 << RX_P_NO)) != (7 << RX_P_NO)) {
			printf_P(PSTR("FLUSH_RX\r"));
			mirf_send_cmd(FLUSH_RX);	// очищаем буфер на прием
		}
	}
