/*
 * nfc.c
 *
 *  Created on: Jul 22, 2018
 *      Author: conor
 */

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

#include "em_chip.h"
#include "em_gpio.h"
#include "em_i2c.h"

#include "log.h"
#include "util.h"
#include "nfc.h"
#include "app.h"

#define NFC_DEV_ADDR		(0xa0|(0x0<<1))
#define NFC_DEV_USART		USART1
#ifndef IS_BOOTLOADER
I2C_TransferReturn_TypeDef I2CSPM_Transfer(I2C_TypeDef *i2c, I2C_TransferSeq_TypeDef *seq)
{
  I2C_TransferReturn_TypeDef ret;
  uint32_t timeout = 10000;
  /* Do a polled transfer */
  ret = I2C_TransferInit(i2c, seq);

  while (ret == i2cTransferInProgress && timeout--)
  {
    ret = I2C_Transfer(i2c);
  }
  return ret;
}

// data must be 16 bytes
void read_block(uint8_t block, uint8_t * data)
{
	uint8_t addr = NFC_DEV_ADDR;
	I2C_TransferSeq_TypeDef    seq;
	I2C_TransferReturn_TypeDef ret;
	uint8_t i2c_read_data[16];
	uint8_t i2c_write_data[1];

	seq.addr  = addr;
	seq.flags = I2C_FLAG_WRITE_READ;
	/* Select command to issue */
	i2c_write_data[0] = block;
	seq.buf[0].data   = i2c_write_data;
	seq.buf[0].len    = 1;
	/* Select location/length of data to be read */
	seq.buf[1].data = i2c_read_data;
	seq.buf[1].len  = 16;

	ret = I2CSPM_Transfer(I2C0, &seq);

	if (ret != i2cTransferDone) {
		printf("I2C fail %04x\r\n",ret);
		exit(1);
	}
	memmove(data, i2c_read_data, 16);
}

// data must be 16 bytes
void write_block(uint8_t block, uint8_t * data)
{
	uint8_t addr = NFC_DEV_ADDR;
	I2C_TransferSeq_TypeDef    seq;
	I2C_TransferReturn_TypeDef ret;
	uint8_t i2c_write_data[1 + 16];

	seq.addr  = addr;
	seq.flags = I2C_FLAG_WRITE;
	/* Select command to issue */
	i2c_write_data[0] = block;
	memmove(i2c_write_data + 1, data, 16);
	seq.buf[0].data   = i2c_write_data;
	seq.buf[0].len    = 17;
	/* Select location/length of data to be read */
	seq.buf[1].data = NULL;
	seq.buf[1].len  = 0;

	ret = I2CSPM_Transfer(I2C0, &seq);

	if (ret != i2cTransferDone) {
		printf("I2C fail %04x\r\n",ret);
		exit(1);
	}
}

void write_reg_flash(uint8_t reg_addr, uint8_t mask,uint8_t data)
{
	uint8_t addr = NFC_DEV_ADDR;
	I2C_TransferSeq_TypeDef    seq;
	I2C_TransferReturn_TypeDef ret;
	uint8_t i2c_write_data[4];

	seq.addr  = addr;
	seq.flags = I2C_FLAG_WRITE;
	i2c_write_data[0] = 0x3a;
	i2c_write_data[1] = reg_addr;
	i2c_write_data[2] = mask;
	i2c_write_data[3] = data;

	seq.buf[0].data   = i2c_write_data;
	seq.buf[0].len    = 4;
	seq.buf[1].data = NULL;
	seq.buf[1].len  = 0;

	ret = I2CSPM_Transfer(I2C0, &seq);

	if (ret != i2cTransferDone) {
		printf("I2C fail %04x\r\n",ret);
		exit(1);
	}
}

void write_reg(uint8_t reg_addr, uint8_t data)
{

	uint8_t mode = 0x00 | (reg_addr & 0x1f);
//	delay(10);

//	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	mode = USART_SpiTransfer(NFC_DEV_USART, data);
	GPIO_PinOutSet(NFC_DEV_SS);
}

void write_command(uint8_t cmd)
{

	uint8_t mode = cmd;
//	delay(10);

//	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	GPIO_PinOutSet(NFC_DEV_SS);
	GPIO_PinOutClear(NFC_DEV_SS);

}

void write_eeprom(uint8_t block, uint8_t * data)
{

	uint8_t mode = 0x40;
//	delay(10);

//	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	mode = block << 1;
	USART_SpiTransfer(NFC_DEV_USART, mode);
	USART_SpiTransfer(NFC_DEV_USART, *data++);
	USART_SpiTransfer(NFC_DEV_USART, *data++);
	USART_SpiTransfer(NFC_DEV_USART, *data++);
	USART_SpiTransfer(NFC_DEV_USART, *data++);

	GPIO_PinOutSet(NFC_DEV_SS);
	GPIO_PinOutClear(NFC_DEV_SS);

}

void read_eeprom(uint8_t block, uint8_t * data)
{

	uint8_t mode = 0x7f;
//	delay(10);

//	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	mode = block << 1;
	USART_SpiTransfer(NFC_DEV_USART, mode);
	*data++ = USART_SpiTransfer(NFC_DEV_USART, 0);
	*data++ = USART_SpiTransfer(NFC_DEV_USART, 0);
	*data++ = USART_SpiTransfer(NFC_DEV_USART, 0);
	*data++ = USART_SpiTransfer(NFC_DEV_USART, 0);


	GPIO_PinOutSet(NFC_DEV_SS);
	GPIO_PinOutClear(NFC_DEV_SS);

}

uint8_t read_reg(uint8_t reg_addr)
{

	uint8_t mode = 0x20 | (reg_addr & 0x1f);
//	delay(10);

//	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	mode = USART_SpiTransfer(NFC_DEV_USART, 0);
	GPIO_PinOutSet(NFC_DEV_SS);

	GPIO_PinOutClear(NFC_DEV_SS);

//	printf("%02x: %x\n",(reg_addr),(int)mode);
	return mode;
}

void read_buffer(uint8_t * data, int len)
{

	uint8_t mode = 0xC0;
	int i;
	if (len > 32)
	{
		printf("warning, max len is 32\n");
		len = 32;
	}

	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	for(i = 0; i < len; i++)
	{
		*data++ = USART_SpiTransfer(NFC_DEV_USART, 0);
	}
	GPIO_PinOutSet(NFC_DEV_SS);

	GPIO_PinOutClear(NFC_DEV_SS);

}

// data must be 14 bytes long
void read_reg_block(uint8_t * data)
{
	int i;
	uint8_t mode = 0x20 | (0 & 0x1f);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(1);
	USART_SpiTransfer(NFC_DEV_USART, mode);
	for (i = 0; i < 0x20; i++)
	{
		mode = USART_SpiTransfer(NFC_DEV_USART, 0);
		if (i < 6 || (i >=8 && i < 0x0f) || (i >= 0x1e))
		{
			*data = mode;
			data++;
		}
	}

	GPIO_PinOutSet(NFC_DEV_SS);
	GPIO_PinOutClear(NFC_DEV_SS);
}



typedef struct {
	uint8_t header;
	uint8_t tlen;
	uint8_t plen;
	uint8_t ilen;
	uint8_t rtype;
} NDEF;

typedef struct {
	uint8_t io;
	uint8_t conf0;
	uint8_t conf1;
	uint8_t conf2;
	uint8_t rfid_status;
	uint8_t ic_status;
	uint8_t mask0;
	uint8_t mask1;
	uint8_t int0;
	uint8_t int1;
	uint8_t buf_status2;
	uint8_t buf_status1;
	uint8_t last_nfc_address;
	uint8_t maj;
	uint8_t minor;
} __attribute__((packed)) AMS_REGS;

void nfc_test()
{
	uint8_t data[32];
	uint8_t ns_reg;
	uint8_t last_ns_reg;
	// magic-number,
	uint8_t cc[] = {0xE1,0x10,0x08, 0x00};

	uint8_t ndef[32] = "\x03\x11\xD1\x01\x0D\x55\x01adafruit.com";

	AMS_REGS  * regs;

	return ;



	delay(10);
	GPIO_PinOutSet(NFC_DEV_SS);
	delay(10);
	GPIO_PinOutClear(NFC_DEV_SS);
	delay(10);

//	uint8_t reg = read_reg(0);
	write_command(0xC2);				// Set to default state
	write_command(0xC4);				// Clear buffer

	write_reg(0x3, 0x80 | 0x40);		// enable tunneling mode and RF configuration



	read_reg_block(data);

	printf("regs: "); dump_hex(data,15);

	delay(100);


	read_reg_block(data);

	printf("regs: "); dump_hex(data,15);



	if (0)
	{
		read_eeprom(0x7F, data);
		printf("initial config: "); dump_hex(data,4);

		data[0] = (1<<2) | 0x03;	// save cfg1 setting for energy harvesting
		data[1] = 0x80 | 0x40;	// save cfg2 setting for tunneling
		write_eeprom(0x7F, data);

		printf("updated config: "); dump_hex(data,4);
	}

	while (1)
	{
//		delay(100);
//		read_reg_block(data);
//		regs = (AMS_REGS *)data;
//
//		if ((regs->buf_status2 & 0x3f) && !(regs->buf_status2 & 0x80))
//		{
//			read_buffer(data, regs->buf_status2 & 0x3f);
//			printf("data: ");
//
//			dump_hex(data, regs->buf_status2 & 0x3f);
//		}

//		dump_hex(data,15);
	}

}

#endif
