/*
* Copyright (C) 2018 SoloKeys, Inc.
*
* This file is part of Solo.
*
* Solo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Solo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Solo. If not, see
*
* This code is available under licenses for commercial use.
* Please contact SoloKeys for more information.
*/
/*
* nfc.c
*
* Created on: Jul 22, 2018
* Author: conor
*/
#include
#include
#include
#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