#include "deca_regs.h"
#include "dw1000_hal.h"
#include "dw1000_util.h"
#include <stdio.h>
#include "Trace.h"

extern volatile uint32_t global_time;

 dw1000_local_data_t dw1000local; // Static local device data
//-----------------------------------------
// map the channel number to the index in the configuration arrays below
// 0th element is chan 1, 1st is chan 2, 2nd is chan 3, 3rd is chan 4, 4th is chan 5, 5th is chan 7
const uint8_t chan_idx[NUM_CH_SUPPORTED] = {0, 0, 1, 2, 3, 4, 0, 5};

//-----------------------------------------
const uint32_t tx_config[NUM_CH] =
{
        RF_TXCTRL_CH1,      /* Tx value match UM */
        RF_TXCTRL_CH2,
        RF_TXCTRL_CH3,
        RF_TXCTRL_CH4,
        RF_TXCTRL_CH5,
        RF_TXCTRL_CH7,
};

//RF -> Channel_Specific_Cfg -> Channel_Cfg -> RF_PLL -> RF PLL2
const uint8_t pll2_config[NUM_CH][5] =
{
    { 0x07, 0x04, 0x00, 0x09, 0x1E}, //3.5Ghz

    { 0x08, 0x05, 0x40, 0x08, 0x26}, //4Ghz

    { 0x09, 0x10, 0x40, 0x08, 0x56}, //4.5Ghz

    { 0x08, 0x05, 0x40, 0x08, 0x26}, //4Ghz WBW

    { 0x1D, 0x04, 0x00, 0x08, 0xA6}, //6.5Ghz

    { 0x1D, 0x04, 0x00, 0x08, 0xA6} //6.5Ghz WBW
};

const uint8_t pll2calcfg = (0x60 | 0x10) ;    /* Bits 7:5 must always be set to binary “011”. Failure to maintain this value will result in DW1000 malfunction. */


//bandwidth configuration
const uint8_t rx_config[NUM_BW] =
{
    0xD8,   //NBW
    0xBC    //WBW
};

//FIXME
//const agc_cfg_struct agc_config =
//{
//    AGC_TUNE2_VAL,
//
//    { AGC_TUNE1_16M , AGC_TUNE1_64M }  //adc target
//}
const uint8_t dwnsSFDlen[NUM_BR] = { 0x40, 0x10, 0x08 }; //DW non-standard SFD length for 110k, 850k and 6.81M

// SFD Threshold
const uint16_t sftsh[NUM_BR][NUM_SFD] =
{
    //110k
    {
        (0x0a), //RX_SFTSH_LONG - standard
        (0x16)  //RX_SFTSH_USR_LONG - non-standard (DW - length specified above dwnsSFDlen)
    },
    //850k
    {
        (0x01), //RX_SFTSH_SHORT
        (0x06), //RX_SFTSH_USR_SHORT - non-standard (DW - length specified above dwnsSFDlen)
    },
    //6.81Mb
    {
        (0x01), //RX_SFTSH_SHORT
        (0x02), //RX_SFTSH_USR_SHORT - non-standard (DW - length specified above dwnsSFDlen)
    }
};

const uint16_t dtune1[NUM_PRF] =
{
    0x0087, // 16 MHz PRF
    0x008D //  64 MHz PRF
};

const uint32_t digital_bb_config[NUM_PRF][NUM_PACS] =
    {
        //16 PRF
        {
            //PAC 8
            0x311A002D,
            //PAC 16
            0x331A0052,
            //PAC 32
            0x351A009A,
            //PAC 64
            0x371A011D
        },
        //64 PRF
        {
            //PAC 8
            0x313B006B,
            //PAC 16
            0x333B00BE,
            //PAC 32
            0x353B015E,
            //PAC 64
            0x373B0296
        }
};

const uint16_t lde_replicaCoeff[PCODES] = {

    // 0
    (int)(0.0 * 65536),
    // 1
    (int)(0.35 * 65536),
    // 2
    (int)(0.35 * 65536),
    // 3
    (int)(0.32 * 65536),
    // 4
    (int)(0.26 * 65536),
    // 5
    (int)(0.27 * 65536),
    // 6
    (int)(0.18 * 65536),
    // 7
    (int)(0.50 * 65536),
    // 8
    (int)(0.32 * 65536),
    // 9
    (int)(0.16 * 65536),
    // 10
    (int)(0.20 * 65536),
    // 11
    (int)(0.23 * 65536),
    // 12
    (int)(0.24 * 65536),
    // 13
    (int)(0.23 * 65536),
    // 14
    (int)(0.21 * 65536),
    // 15
    (int)(0.17 * 65536),
    // 16
    (int)(0.21 * 65536),
    // 17
    (int)(0.20 * 65536),
    // 18
    (int)(0.21 * 65536),
    // 19
    (int)(0.21 * 65536),
    // 20
    (int)(0.28 * 65536),
    // 21
    (int)(0.23 * 65536),
    // 22
    (int)(0.22 * 65536),
    // 23
    (int)(0.19 * 65536),
    // 24
    (int)(0.22 * 65536)
};
void dw1000Util_enableclocks(int clocks)
{
    uint8_t reg[2];
    dw1000Hal_readSubRegister(PMSC_ID,PMSC_CTRL0_OFFSET, reg, 2);
    switch(clocks)
    {
        case ENABLE_ALL_SEQ:
        {
            reg[0] = 0x00 ;
            reg[1] = reg[1] & 0xfe;
        }
        break;
        case FORCE_SYS_XTI:
        {
            //system and rx
            reg[0] = 0x01 | (reg[0] & 0xfc);
        }
        break;
        case FORCE_SYS_PLL:
        {
            //system
            reg[0] = 0x02 | (reg[0] & 0xfc);
        }
        break;
        case READ_ACC_ON:
        {
            reg[0] = 0x48 | (reg[0] & 0xb3);
            reg[1] = 0x80 | reg[1];
        }
        break;
        case READ_ACC_OFF:
        {
            reg[0] = reg[0] & 0xb3;
            reg[1] = 0x7f & reg[1];

        }
        break;
        case FORCE_OTP_ON:
        {
            reg[1] = 0x02 | reg[1];
        }
        break;
        case FORCE_OTP_OFF:
        {
            reg[1] = reg[1] & 0xfd;
        }
        break;
        case FORCE_TX_PLL:
        {
            reg[0] = 0x20| (reg[0] & 0xcf);
        }
        break;
        default:
        break;
    }

    //DECA: Need to write lower byte separately before setting the higher byte(s)
    dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, &reg[0], 1);
    dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET + 1, &reg[0], 1);
}


void dw1000Util_enableRX(){
#ifdef DOUBLE_BUFFER
	//Align HSRBP and ICRBP if needed (see page 37 in the Usermanual)
	uint64_t event = 0;
	dw1000Hal_readRegisterFromIsr(SYS_STATUS_ID, (uint8_t*) &event,
	SYS_STATUS_LEN);
	if((event & SYS_STATUS_HSRBP) != (event & SYS_STATUS_ICRBP)){
		uint32_t reg;
		dw1000Hal_readRegisterFromIsr(SYS_CTRL_ID, (uint8_t *)&reg, SYS_CTRL_LEN);
		reg |= SYS_CTRL_HSRBTOGGLE;
		dw1000Hal_writeRegisterFromIsr(SYS_CTRL_ID, (uint8_t *)&reg, SYS_CTRL_LEN);
	}
#endif

	uint32_t sys_ctrl = 0;
	dw1000Hal_readRegisterFromIsr(SYS_CTRL_ID, (uint8_t*) &sys_ctrl,
	SYS_CTRL_LEN); // switch to rx mode
	sys_ctrl |= SYS_CTRL_RXENAB;
	dw1000Hal_writeRegisterFromIsr(SYS_CTRL_ID, (uint8_t*) &sys_ctrl,
	SYS_CTRL_LEN);
}

uint32_t dw1000Util_otpread(uint32_t address)
{
    uint8_t buf[4];
    uint32_t ret_data;

    //TODO Wieso buf? Und nicht gleich von address?
    buf[1] = (address>>8) & 0xff;
    buf[0] = address & 0xff;

    // Write the address
    dw1000Hal_writeSubRegister(OTP_IF_ID, OTP_ADDR, buf, OTP_ADDR_LEN);


    // Assert OTP Read (self clearing)
    buf[0] = 0x03; // 0x03 for manual drive of OTP_READ and OTP_READ
    dw1000Hal_writeSubRegister(OTP_IF_ID, OTP_CTRL, buf, 1);
    buf[0] = 0x00; // Bit0 is not autoclearing, so clear it (Bit 1 is but we clear it anyway).
    dw1000Hal_writeSubRegister(OTP_IF_ID, OTP_CTRL, buf, 1);

    // Read read data, available 40ns after rising edge of OTP_READ
    dw1000Hal_readSubRegister(OTP_IF_ID,OTP_RDAT, &ret_data, OTP_RDAT_LEN);

    // Return the 32bit of read data
    return (ret_data);
}

void dw1000Util_getRxTimestamp(dw1000_global_time_t *time_buffer){
		uint8_t buf[5] = {0};
		uint64_t radio_rx_time = 0;

		// Read rx timestamp from radio
		dw1000Hal_readSubRegisterFromIsr(RX_TIME_ID, RX_TIME_RX_STAMP_OFFSET, buf, RX_TIME_RX_STAMP_LEN);
		radio_rx_time = ((uint64_t) buf[4]) << 32 |
						((uint64_t) buf[3]) << 24 |
						((uint64_t) buf[2]) << 16 |
						((uint64_t) buf[1]) << 8 |
						((uint64_t) buf[0]) << 0;

		// multiply by 16 to get picoseconds (actually ~15.65 is right)
		radio_rx_time <<= 4;

		// Calculate timestamp in milliseconds and sub-milliseconds parts separately
		uint64_t ms_buf = global_time * GLOBAL_TIME_TICK_MS + radio_rx_time / 1000000000llu;
		uint64_t subms_buf = radio_rx_time - (global_time * 1000000000llu);

		if(ms_buf < dw1000local.last_rx_time.ms) {
			// The radio timer had an overflow, but the global timer didn't, yet
			ms_buf += GLOBAL_TIME_TICK_MS;
		}

		// Write calculated timestamp to provided structure
		time_buffer->ms = ms_buf;
		time_buffer->subms = subms_buf;

		// Store new timestamp to be able to detect asynchronous overflows
		dw1000local.last_rx_time.ms = ms_buf;
}

void lltoa(uint64_t val, char *dest_buf, uint8_t base) {
	char buf[64] = {0};
	uint32_t i = 62;

	for(; val && i ; --i, val /= base) {
		buf[i] = "0123456789abcdef"[val % base];
	}

	memcpy(dest_buf, &buf[i + 1], 64);
}

void dw1000Util_printGlobalTimestamp(dw1000_global_time_t *time) {
	char ms_buf[64] = {0};
	char subms_buf[64] = {0};

	// Convert uint64_t timestamp to strings, because printf can't handle 64-bit integers
	lltoa(time->ms, ms_buf, 10);
	lltoa(time->subms, subms_buf, 10);

	printf("RX time = %s.%sms\n", ms_buf, subms_buf);
}

void dw1000Util_forceTrxOff(void) {
	uint32_t sys_ctrl = 0;
	//DECA: decaIrqStatus_t stat ; ???
	uint32_t  sys_mask;
	dw1000Hal_readRegisterFromIsr(SYS_MASK_ID, (uint8_t *) &sys_mask, SYS_MASK_LEN);


	// need to beware of interrupts occurring in the middle of following read modify write cycle
	// we can disable the radio, but before the status is cleared an interrupt can be set (e.g. the
	// event has just happened before the radio was disabled)
	// thus we need to disable interrupt during this operation
   /// stat = decamutexon() ; DECA: ???:" -->
	portDISABLE_INTERRUPTS(); //FIXME Eigentlich eher EXTI

	uint32_t tmp_mask = 0;
	// No interrupts
	dw1000Hal_writeRegisterFromIsr(SYS_MASK_ID, (uint8_t *) &tmp_mask, SYS_MASK_LEN);

	//Disable radio
	dw1000Hal_readRegisterFromIsr(SYS_CTRL_ID, (uint8_t *) &sys_ctrl, 4);
	sys_ctrl |= SYS_CTRL_TRXOFF;//  Immediately cancel all RX and TX operations, bring radio to IDLE state
	dw1000Hal_writeRegisterFromIsr(SYS_CTRL_ID, (uint8_t *) &sys_ctrl, 4);


	uint32_t tmp = (CLEAR_ALLTX_EVENTS | CLEAR_ALLRXERROR_EVENTS | CLEAR_ALLRXGOOD_EVENTS);

	dw1000Hal_writeRegisterFromIsr(SYS_STATUS_ID,(uint8_t *)  &tmp, 4) ;
	//TODO     dwt_syncrxbufptrs();

	dw1000Hal_writeRegisterFromIsr(SYS_MASK_ID, (uint8_t *) &sys_mask, SYS_MASK_LEN);

	portENABLE_INTERRUPTS();




}

void dw1000Util_reset(void) {
	uint32_t subreg;
	dw1000Hal_readSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);
	subreg |= (1 << 0); 	// SOFTRESET - Set SYSCLKS to 01
	subreg &= ~(1 << 1); 	// SOFTRESET - Zero everything else
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);

	dw1000Hal_readSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);
	subreg &= ~(15 << 28); // SOFTRESET - Set all to ZERO
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);

	dw1000Hal_readSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);
	subreg |= (15 << 28); 	// SOFTRESET - Set all to ONE
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &subreg,
	PMSC_CTRL0_LEN);
}

void dw1000Util_resetRxOnly(void) {
	uint32_t subreg;

	dw1000Hal_readSubRegisterFromIsr(PMSC_ID, PMSC_CTRL0_OFFSET,
			(uint8_t*) &subreg, PMSC_CTRL0_LEN);
	subreg &= ~(1 << 28); // SOFTRESET - Set all to ZERO
	subreg |= (0xe << 28);
	dw1000Hal_writeSubRegisterFromIsr(PMSC_ID, PMSC_CTRL0_OFFSET,
			(uint8_t*) &subreg, PMSC_CTRL0_LEN);

//	dw1000Hal_readSubRegisterFromIsr(PMSC_ID, PMSC_CTRL0_OFFSET,
//			(uint8_t*) &subreg, PMSC_CTRL0_LEN);
	subreg |= (0xf << 28);
	dw1000Hal_writeSubRegisterFromIsr(PMSC_ID, PMSC_CTRL0_OFFSET,
			(uint8_t*) &subreg, PMSC_CTRL0_LEN);
}

#ifdef DEBUG

void hexdump(uint8_t * buffer, uint8_t len){
	char string [2*len +1];
	char * string_ptr = string;
	for (uint8_t i = 0; i < len; i++)
	{
		string_ptr += sprintf(string_ptr, "%02X", (unsigned int)*(buffer+i));
	}
	string[2*len] = '\0';
	trace_printf("Ev: %s\n", string);
}
#endif