crashtest-r0ket/misc/openbeacon/lpc13xx/openpcd2/src/rfid.c

360 lines
7.5 KiB
C

/***************************************************************
*
* OpenBeacon.org - PN532 routines for LPC13xx based OpenPCD2
*
* Copyright 2010 Milosch Meriac <meriac@openbeacon.de>
*
***************************************************************
This program 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; version 2.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <openbeacon.h>
#include "pn532.h"
#include "rfid.h"
#define BIT_REVERSE(x) ((unsigned char)(__RBIT(x)>>24))
static void rfid_reset(unsigned char reset)
{
GPIOSetValue(PN532_RESET_PORT, PN532_RESET_PIN, reset ? 1 : 0);
}
static void rfid_cs(unsigned char cs)
{
GPIOSetValue(PN532_CS_PORT, PN532_CS_PIN, cs ? 1 : 0);
}
static unsigned char rfid_tx(unsigned char data)
{
while ((LPC_SSP->SR & 0x02) == 0);
LPC_SSP->DR = BIT_REVERSE (data);
while ((LPC_SSP->SR & 0x04) == 0);
data = BIT_REVERSE (LPC_SSP->DR);
return data;
}
static unsigned char rfid_rx(void)
{
return rfid_tx(0x00);
}
static unsigned char rfid_status(void)
{
unsigned char res;
/* enable chip select */
rfid_cs(0);
/* transmit status request */
rfid_tx(0x02);
res = rfid_rx();
/* release chip select */
rfid_cs(1);
return res;
}
int rfid_read(void *data, unsigned char size)
{
int res;
unsigned char *p, c, pkt_size, crc, prev, t;
/* wait 100ms max till PN532 response is ready */
t=0;
while ((rfid_status() & 1) == 0)
{
if(t++>10)
return -8;
vTaskDelay( 10 / portTICK_RATE_MS);
}
/* enable chip select */
rfid_cs(0);
/* read from FIFO command */
rfid_tx(0x03);
/* default result */
res = -1;
/* find preamble */
t = 0;
prev = rfid_rx();
while ((!(((c = rfid_rx()) == 0xFF) && (prev == 0x00))) && (t
< PN532_FIFO_SIZE))
{
prev = c;
t++;
}
if (t >= PN532_FIFO_SIZE)
res = -3;
else
{
/* read packet size */
pkt_size = rfid_rx();
/* special treatment for NACK and ACK */
if ((pkt_size == 0x00) || (pkt_size == 0xFF))
{
/* verify if second length byte is inverted */
if (rfid_rx() != (unsigned char) (~pkt_size))
res = -2;
else
{
/* eat Postamble */
rfid_rx();
/* -1 for NACK, 0 for ACK */
res = pkt_size ? 0 : -1;
}
}
else
{
/* verify packet size against LCS */
if (((pkt_size + rfid_rx()) & 0xFF) != 0)
res = -4;
else
{
/* remove TFI from packet size */
pkt_size--;
/* verify if packet fits into buffer */
if (pkt_size > size)
res = -5;
else
{
/* remember actual packet size */
size = pkt_size;
/* verify TFI */
if ((crc = rfid_rx()) != 0xD5)
res = -6;
else
{
/* read packet */
p = (unsigned char *) data;
while (pkt_size--)
{
/* read data */
c = rfid_rx();
/* maintain crc */
crc += c;
/* save payload */
if (p)
*p++ = c;
}
/* add DCS to CRC */
crc += rfid_rx();
/* verify CRC */
if (crc)
res = -7;
else
{
/* eat Postamble */
rfid_rx();
/* return actual size as result */
res = size;
}
}
}
}
}
}
rfid_cs(1);
/* everything fine */
return res;
}
int rfid_write(const void *data, int len)
{
int i;
static const unsigned char preamble[] =
{ 0x01, 0x00, 0x00, 0xFF };
const unsigned char *p = preamble;
unsigned char tfi = 0xD4, c;
if (!data)
len = 0xFF;
/* enable chip select */
rfid_cs(0);
p = preamble; /* Praeamble */
for (i = 0; i < (int) sizeof(preamble); i++)
rfid_tx(*p++);
rfid_tx(len + 1); /* LEN */
rfid_tx(0x100 - (len + 1)); /* LCS */
rfid_tx(tfi); /* TFI */
/* PDn */
p = (const unsigned char *) data;
while (len--)
{
c = *p++;
rfid_tx(c);
tfi += c;
}
rfid_tx(0x100 - tfi); /* DCS */
rfid_rx(); /* Postamble */
/* release chip select */
rfid_cs(1);
/* check for ack */
return rfid_read(NULL, 0);
}
static void rfid_hexdump(const void *buffer, int size)
{
int i;
const unsigned char *p = (unsigned char *) buffer;
for (i = 0; i < size; i++)
{
if (i && ((i & 3) == 0))
debug_printf(" ");
debug_printf(" %02X", *p++);
}
debug_printf(" [size=%02i]\n", size);
}
static int rfid_execute(void *data, unsigned int isize, unsigned int osize)
{
int res;
if (rfid_write(data, isize))
{
debug_printf("getting result\n");
res = rfid_read(data, osize);
if (res > 0)
rfid_hexdump(data, res);
else
debug_printf("error: res=%i\n", res);
}
else
{
debug_printf("->NACK!\n");
res = -1;
}
return res;
}
void WriteRegister(unsigned short address, unsigned char data)
{
unsigned char cmd[4];
/* write register */
cmd[0] = 0x08;
/* high byte of address */
cmd[1] = address >> 8;
/* low byte of address */
cmd[2] = address & 0xFF;
/* data value */
cmd[3] = data;
rfid_execute(&cmd, sizeof(cmd), sizeof(data));
}
static
void rfid_task(void *pvParameters)
{
int i;
static unsigned char data[80];
/* touch unused Parameter */
(void) pvParameters;
/* release reset line after 400ms */
vTaskDelay( 400 / portTICK_RATE_MS);
rfid_reset(1);
/* wait for PN532 to boot */
vTaskDelay( 100 / portTICK_RATE_MS);
/* read firmware revision */
debug_printf("\nreading firmware version...\n");
data[0] = PN532_CMD_GetFirmwareVersion;
rfid_execute(&data, 1, sizeof(data));
/* enable debug output */
debug_printf("\nenabling debug output...\n");
WriteRegister(0x6328, 0xFC);
// select test bus signal
WriteRegister(0x6321, 6);
// select test bus type
WriteRegister(0x6322, 0x07);
while (1)
{
/* wait 500ms */
vTaskDelay( 500 / portTICK_RATE_MS);
/* detect cards in field */
GPIOSetValue(LED_PORT, LED_BIT, LED_ON);
debug_printf("\nchecking for cards...\n");
data[0] = PN532_CMD_InListPassiveTarget;
data[1] = 0x01; /* MaxTg - maximum cards */
data[2] = 0x00; /* BrTy - 106 kbps type A */
if (((i = rfid_execute(&data, 3, sizeof(data))) >= 11) && (data[1]
== 0x01) && (data[2] == 0x01))
{
debug_printf("card id: ");
rfid_hexdump(&data[7], data[6]);
}
else
debug_printf("unknown response of %i bytes\n", i);
GPIOSetValue(LED_PORT, LED_BIT, LED_OFF);
/* turning field off */
debug_printf("\nturning field off again...\n");
data[0] = PN532_CMD_RFConfiguration;
data[1] = 0x01; /* CfgItem = 0x01 */
data[2] = 0x00; /* RF Field = off */
rfid_execute(&data, 3, sizeof(data));
}
}
void rfid_init(void)
{
/* reset SSP peripheral */
LPC_SYSCON->PRESETCTRL = 0x01;
/* Enable SSP clock */
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11);
// Enable SSP peripheral
LPC_IOCON->PIO0_8 = 0x01 | (0x01 << 3); /* MISO, Pulldown */
LPC_IOCON->PIO0_9 = 0x01; /* MOSI */
LPC_IOCON->SCKLOC = 0x00; /* route to PIO0_10 */
LPC_IOCON->JTAG_TCK_PIO0_10 = 0x02; /* SCK */
/* Set SSP clock to 4.5MHz */
LPC_SYSCON->SSPCLKDIV = 0x01;
LPC_SSP->CR0 = 0x0707;
LPC_SSP->CR1 = 0x0002;
LPC_SSP->CPSR = 0x02;
/* Initialize chip select line */
rfid_cs(1);
GPIOSetDir(PN532_CS_PORT, PN532_CS_PIN, 1);
/* Initialize RESET line */
rfid_reset(0);
GPIOSetDir(PN532_RESET_PORT, PN532_RESET_PIN, 1);
/* Create PN532 task */
xTaskCreate(rfid_task, (const signed char*) "RFID", TASK_RFID_STACK_SIZE,
NULL, TASK_RFID_PRIORITY, NULL);
}