#ifdef SX1276_INSTALLED
#include "iface_sx1276.h"

bool SX1276_Mode_LoRa=false;

void SX1276_WriteReg(uint8_t address, uint8_t data)
{
	SPI_CSN_off;
	SPI_Write(address | 0x80); // MSB 1 = write
	NOP();
	SPI_Write(data);
	SPI_CSN_on;
}

uint8_t SX1276_ReadReg(uint8_t address)
{ 
	SPI_CSN_off;
	SPI_Write(address & 0x7F);
	uint8_t result = SPI_Read();
	SPI_CSN_on;
	return result;
}

void SX1276_WriteRegisterMulti(uint8_t address, const uint8_t* data, uint8_t length)
{
	SPI_CSN_off;
	SPI_Write(address | 0x80); // MSB 1 = write

	for(uint8_t i = 0; i < length; i++)
		SPI_Write(data[i]);

	SPI_CSN_on;
}

void SX1276_ReadRegisterMulti(uint8_t address, uint8_t* data, uint8_t length)
{ 
	SPI_CSN_off;
	SPI_Write(address & 0x7F);

	for(uint8_t i = 0; i < length; i++)
		data[i]=SPI_Read();

	SPI_CSN_on;
}

uint8_t SX1276_Reset()
{
	//TODO when pin is not wired
	#ifdef SX1276_RST_pin
		SX1276_RST_off;
		delayMicroseconds(200);
		SX1276_RST_on;
	#endif
    return 0;
}

bool SX1276_DetectChip() //to be called after reset, verfies the chip has been detected
{
	#define SX1276_Detect_MaxAttempts 5
	uint8_t i = 0;
	bool chipFound = false;
	while ((i < SX1276_Detect_MaxAttempts) && !chipFound)
	{
		uint8_t ChipVersion = SX1276_ReadReg(SX1276_42_VERSION);
		if (ChipVersion == 0x12)
		{
			debugln("SX1276 reg version=%d", ChipVersion);
			chipFound = true;
		}
		else
		{
			debug("SX1276 not found! attempts: %d", i);
			debug(" of ");
			debugln("%d SX1276 reg version=%d", SX1276_Detect_MaxAttempts, ChipVersion);
			i++;
		}
	}
	if (!chipFound)
	{
		debugln("SX1276 not detected!!!");
		return false;
	}
	else
	{
		debugln("Found SX1276 Device!");
		return true;
	}
}

void SX1276_SetTxRxMode(uint8_t mode)
{
	#ifdef SX1276_TXEN_pin
		if(mode == TX_EN)
			SX1276_TXEN_on;
		else
			SX1276_RXEN_on;
	#endif
}

void SX1276_SetFrequency(uint32_t frequency)
{
	uint32_t f = frequency / 61;
	uint8_t data[3];
	data[0] = f >> 16;
	data[1] = f >> 8;
	data[2] = f;
	
	SX1276_WriteRegisterMulti(SX1276_06_FRFMSB, data, 3);
}

void SX1276_SetMode(bool lora, bool low_freq_mode, uint8_t mode)
{
	uint8_t data = 0x00;

	SX1276_Mode_LoRa=lora;

	if(lora)
	{
		data = data | (1 << 7);
		data = data & ~(1 << 6);
	}
	else
	{
		data = data & ~(1 << 7);
		data = data | (1 << 6);
	}

	if(low_freq_mode)
		data = data | (1 << 3);
	
	data = data | mode;

	SX1276_WriteReg(SX1276_01_OPMODE, data);
}

void SX1276_SetDetectOptimize(bool auto_if, uint8_t detect_optimize)
{
	uint8_t data = SX1276_ReadReg(SX1276_31_DETECTOPTIMIZE);
	data = (data & 0b01111000) | detect_optimize;
	data = data | (auto_if << 7);

	SX1276_WriteReg(SX1276_31_DETECTOPTIMIZE, data);
}

void SX1276_ConfigModem1(uint8_t bandwidth, uint8_t coding_rate, bool implicit_header_mode)
{
	uint8_t data = 0x00;
	data = data | (bandwidth << 4);
	data = data | (coding_rate << 1);
	data = data | implicit_header_mode;

	SX1276_WriteReg(SX1276_1D_MODEMCONFIG1, data);

	if (bandwidth == SX1276_MODEM_CONFIG1_BW_500KHZ) //datasheet errata reconmendation http://caxapa.ru/thumbs/972894/SX1276_77_8_ErrataNote_1.1_STD.pdf
	{
		SX1276_WriteReg(SX1276_36_LORA_REGHIGHBWOPTIMIZE1, 0x02);
		SX1276_WriteReg(SX1276_3A_LORA_REGHIGHBWOPTIMIZE2, 0x64);
	}
	else
		SX1276_WriteReg(SX1276_36_LORA_REGHIGHBWOPTIMIZE1, 0x03);
}

void SX1276_ConfigModem2(uint8_t spreading_factor, bool tx_continuous_mode, bool rx_payload_crc_on)
{
	uint8_t data = SX1276_ReadReg(SX1276_1E_MODEMCONFIG2);
	data = data & 0b11; // preserve the last 2 bits
	data = data | (spreading_factor << 4);
	data = data | (tx_continuous_mode << 3);
	data = data | (rx_payload_crc_on << 2);

	SX1276_WriteReg(SX1276_1E_MODEMCONFIG2, data);
}

void SX1276_ConfigModem3(bool low_data_rate_optimize, bool agc_auto_on)
{
	uint8_t data = SX1276_ReadReg(SX1276_26_MODEMCONFIG3);
	data = data & 0b11; // preserve the last 2 bits
	data = data | (low_data_rate_optimize << 3);
	data = data | (agc_auto_on << 2);
	
	SX1276_WriteReg(SX1276_26_MODEMCONFIG3, data);
}

void SX1276_SetPreambleLength(uint16_t length)
{
	uint8_t data[2];
	data[0] = (length >> 8) & 0xFF; // high byte
	data[1] = length & 0xFF; // low byte
	
	SX1276_WriteRegisterMulti(SX1276_20_PREAMBLEMSB, data, 2);
}

void SX1276_SetDetectionThreshold(uint8_t threshold)
{
	SX1276_WriteReg(SX1276_37_DETECTIONTHRESHOLD, threshold);
}

void SX1276_SetLna(uint8_t gain, bool high_freq_lna_boost)
{
	uint8_t data = SX1276_ReadReg(SX1276_0C_LNA);
	data = data & 0b100; // preserve the third bit
	data = data | (gain << 5);
	
	if(high_freq_lna_boost)
		data = data | 0b11;
	
	SX1276_WriteReg(SX1276_0C_LNA, data);
}

void SX1276_SetHopPeriod(uint8_t freq_hop_period)
{
	SX1276_WriteReg(SX1276_24_HOPPERIOD, freq_hop_period);
}

void SX1276_SetPaDac(bool on)
{
	uint8_t data = SX1276_ReadReg(SX1276_4D_PADAC);
	data = data & 0b11111000; // preserve the upper 5 bits

	if(on)
		data = data | 0x07;
	else
		data = data | 0x04;
	
	SX1276_WriteReg(SX1276_4D_PADAC, data);
}

void SX1276_SetPaConfig(bool pa_boost_pin, uint8_t max_power, uint8_t output_power)
{
	uint8_t data = 0x00;
	data = data | (pa_boost_pin << 7);
	data = data | (max_power << 4);
	data = data | (output_power & 0x0F);

	SX1276_WriteReg(SX1276_09_PACONFIG, data);
}

void SX1276_SetOcp(bool OcpOn, uint8_t OcpTrim)
{
	SX1276_WriteReg(SX1276_0B_OCP, (OcpOn << 5) | OcpTrim);
}

void SX1276_WritePayloadToFifo(uint8_t* payload, uint8_t length)
{
	SX1276_WriteReg(SX1276_22_PAYLOAD_LENGTH, length);
	SX1276_WriteReg(SX1276_0E_FIFOTXBASEADDR, 0x00);
	SX1276_WriteReg(SX1276_0D_FIFOADDRPTR, 0x00);
	SX1276_WriteRegisterMulti(SX1276_00_FIFO, payload, length);
}

#endif