summaryrefslogtreecommitdiff
path: root/openpicc
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc')
-rw-r--r--openpicc/application/iso14443_layer3a.c92
-rw-r--r--openpicc/application/ssc_picc.c102
-rw-r--r--openpicc/application/ssc_picc.h13
-rw-r--r--openpicc/application/tc_fdt.c5
-rw-r--r--openpicc/config/FreeRTOSConfig.h2
5 files changed, 141 insertions, 73 deletions
diff --git a/openpicc/application/iso14443_layer3a.c b/openpicc/application/iso14443_layer3a.c
index 2239655..f2fe16e 100644
--- a/openpicc/application/iso14443_layer3a.c
+++ b/openpicc/application/iso14443_layer3a.c
@@ -49,11 +49,65 @@ const iso14443_frame ATQA_FRAME = {
{}
};
+const iso14443_frame NULL_FRAME = {
+ TYPE_A,
+ {{STANDARD_FRAME, PARITY}},
+ 4,
+ 0, 0,
+ {0, 0, 0, 0},
+ {}
+};
+
#define PLL_LOCK_HYSTERESIS portTICK_RATE_MS*5
#define LAYER3_DEBUG usb_print_string
+#define INITIAL_STATE IDLE
+//#define INITIAL_STATE ACTIVE
+
+/* Running in ISR mode */
+void __ramfunc iso14443_layer3a_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode, u_int8_t* samples)
+{
+ (void)ssc_sr;
+ if(ssc_mode == SSC_MODE_14443A_SHORT && samples) {
+ ISO14443A_SHORT_TYPE sample = *(ISO14443A_SHORT_TYPE*)samples;
+ portBASE_TYPE send_atqa = 0;
+ if(sample == REQA) {
+ tc_fdt_set(ISO14443A_FDT_SHORT_0);
+ if(state == IDLE)
+ send_atqa = 1;
+ /* FIXME: prepare and configure ATQA response */
+ } else if(sample == WUPA) {
+ tc_fdt_set(ISO14443A_FDT_SHORT_1);
+ if(state == IDLE || state == HALT)
+ send_atqa = 1;
+ /* FIXME: prepare and configure ATQA response */
+ }
+
+ if(send_atqa) {
+ vLedSetGreen(0);
+ if(ssc_tx_buffer.state == FREE) {
+ ssc_tx_buffer.state = PROCESSING;
+ ssc_tx_buffer.len = sizeof(ssc_tx_buffer.data);
+ int ret = manchester_encode(ssc_tx_buffer.data,
+ ssc_tx_buffer.len,
+ &ATQA_FRAME);
+ if(ret>0) {
+ vLedSetGreen(1);
+ ssc_tx_buffer.len = ret;
+ ssc_tx_start(&ssc_tx_buffer);
+ vLedSetGreen(0);
+
+ } else {
+ ssc_tx_buffer.state = FREE;
+ }
+ }
+ vLedSetGreen(1);
+ }
+ }
+}
+
extern void main_help_print_buffer(ssc_dma_rx_buffer_t *buffer, int *pktcount);
void iso14443_layer3a_state_machine (void *pvParameters)
{
@@ -64,6 +118,11 @@ void iso14443_layer3a_state_machine (void *pvParameters)
ssc_dma_rx_buffer_t* buffer = NULL;
portBASE_TYPE need_receive = 0, switch_on = 0;
+ if(ssc_get_overflows() > 0 && state != ERROR) {
+ LAYER3_DEBUG("SSC overflow error, please debug\n\r");
+ state = ERROR;
+ }
+
/* First let's see whether there is a reader */
switch(state) {
case STARTING_UP: /* Fall through */
@@ -111,6 +170,7 @@ void iso14443_layer3a_state_machine (void *pvParameters)
tc_cdiv_set_divider(64);
#endif
tc_fdt_init();
+ ssc_set_irq_extension((ssc_irq_ext_t)iso14443_layer3a_irq_ext);
#if 1
ssc_tx_init();
#else
@@ -129,8 +189,12 @@ void iso14443_layer3a_state_machine (void *pvParameters)
break;
case POWERED_OFF:
if(switch_on == 1) {
- state=IDLE;
- ssc_rx_mode_set(SSC_MODE_14443A_SHORT);
+ state=INITIAL_STATE;
+ if(INITIAL_STATE == IDLE)
+ ssc_rx_mode_set(SSC_MODE_14443A_SHORT);
+ else if(INITIAL_STATE == ACTIVE)
+ ssc_rx_mode_set(SSC_MODE_14443A_STANDARD);
+ else ssc_rx_mode_set(SSC_MODE_NONE);
ssc_rx_start();
continue;
}
@@ -139,6 +203,9 @@ void iso14443_layer3a_state_machine (void *pvParameters)
case HALT:
/* Wait for REQA or WUPA (HALT: only WUPA) */
need_receive = 1;
+ case ACTIVE:
+ case ACTIVE_STAR:
+ need_receive = 1;
default:
break;
}
@@ -164,10 +231,17 @@ void iso14443_layer3a_state_machine (void *pvParameters)
LAYER3_DEBUG("Received ");
LAYER3_DEBUG(first_sample == WUPA ? "WUPA" : "REQA");
LAYER3_DEBUG(" waking up to send ATQA\n\r");
- portENTER_CRITICAL();
+ if(ssc_tx_buffer.state == PROCESSING) {
+ LAYER3_DEBUG("Buffer ");
+ DumpUIntToUSB(ssc_tx_buffer.len);
+ LAYER3_DEBUG(" ");
+ DumpBufferToUSB((char*)ssc_tx_buffer.data, ssc_tx_buffer.len);
+ LAYER3_DEBUG("\n\r");
+ }
+ /*portENTER_CRITICAL();
if(ssc_tx_buffer.state != FREE) {
portEXIT_CRITICAL();
- /* Wait for another frame */
+ * Wait for another frame */ /*
ssc_rx_mode_set(SSC_MODE_14443A_SHORT);
ssc_rx_start();
} else {
@@ -180,6 +254,7 @@ void iso14443_layer3a_state_machine (void *pvParameters)
&ATQA_FRAME);
if(ret>0) {
ssc_tx_buffer.len = ret;
+ ssc_tx_start(&ssc_tx_buffer);
LAYER3_DEBUG("Buffer ");
DumpUIntToUSB(ret);
LAYER3_DEBUG(" ");
@@ -189,17 +264,22 @@ void iso14443_layer3a_state_machine (void *pvParameters)
portENTER_CRITICAL();
ssc_tx_buffer.state = FREE;
portEXIT_CRITICAL();
- /* Wait for another frame */
+ * Wait for another frame */ /*
ssc_rx_mode_set(SSC_MODE_14443A_SHORT);
ssc_rx_start();
}
- }
+ }*/
} else {
/* Wait for another frame */
ssc_rx_mode_set(SSC_MODE_14443A_SHORT);
ssc_rx_start();
}
break;
+ case ACTIVE:
+ case ACTIVE_STAR:
+ /* Wait for another frame */
+ ssc_rx_mode_set(SSC_MODE_14443A_STANDARD);
+ ssc_rx_start();
default:
break;
}
diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c
index 50470c5..df0f3f9 100644
--- a/openpicc/application/ssc_picc.c
+++ b/openpicc/application/ssc_picc.c
@@ -51,6 +51,7 @@
static const AT91PS_SSC ssc = AT91C_BASE_SSC;
static AT91PS_PDC rx_pdc;
+static AT91PS_PDC tx_pdc;
static ssc_dma_rx_buffer_t dma_buffers[SSC_DMA_BUFFER_COUNT];
xQueueHandle ssc_rx_queue = NULL;
@@ -84,7 +85,7 @@ static struct ssc_state ssc_state;
static const struct {u_int16_t bytes; u_int16_t transfers;} ssc_dmasize[] = {
[SSC_MODE_NONE] = {0, 0},
[SSC_MODE_14443A_SHORT] = {ISO14443A_SHORT_TRANSFER_SIZE/8, 1}, /* 1 transfer of ISO14443A_SHORT_LEN bits */
- [SSC_MODE_14443A_STANDARD] = {16*4, 16}, /* 64 bytes */
+ [SSC_MODE_14443A_STANDARD] = {16*4, 16}, /* 16 transfers of 32 bits (maximum number), resulting in 512 samples */
[SSC_MODE_14443B] = {16*4, 16}, /* 64 bytes */
[SSC_MODE_EDGE_ONE_SHOT] = {16*4, 16}, /* 64 bytes */
[SSC_MODE_CONTINUOUS] = {511*4, 511}, /* 2044 bytes */
@@ -169,7 +170,7 @@ out_set_mode:
ssc_state.mode = ssc_mode;
}
-static void ssc_tx_mode_set(enum ssc_mode ssc_mode)
+void ssc_tx_start(ssc_dma_tx_buffer_t *buf)
{
u_int8_t data_len, num_data, sync_len;
u_int32_t start_cond;
@@ -180,40 +181,26 @@ static void ssc_tx_mode_set(enum ssc_mode ssc_mode)
/* disable all Tx related interrupt sources */
AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK);
- switch (ssc_mode) {
- case SSC_MODE_14443A_SHORT:
- start_cond = AT91C_SSC_START_RISE_RF;
- sync_len = 0;
- data_len = 32;
- num_data = 1;
- break;
- case SSC_MODE_14443A_STANDARD:
- start_cond = AT91C_SSC_START_0;
- sync_len = ISO14443A_SOF_LEN;
- ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE;
- data_len = 32;
- num_data = 1; /* FIXME */
- break;
- default:
- break;
- }
+ start_cond = AT91C_SSC_START_RISE_RF;
+ sync_len = 0;
+ ssc->SSC_RC0R = 0;
+ data_len = 16;
+ num_data = buf->len/2;
+
ssc->SSC_TFMR = ((data_len-1) & 0x1f) |
(((num_data-1) & 0x0f) << 8) |
(((sync_len-1) & 0x0f) << 16);
ssc->SSC_TCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | start_cond;
+
+ AT91F_PDC_SetTx(tx_pdc, buf->data, num_data);
#ifdef TEST_WHETHER_NOT_ENABLING_IT_HELPS
- AT91F_SSC_EnableIt(ssc, AT91C_SSC_TXSYN);
+ AT91F_SSC_EnableIt(ssc, AT91C_SSC_TXSYN | AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE);
#endif
- AT91F_SSC_EnableTx(AT91C_BASE_SSC);
-#if 0
- /* Enable RX interrupts */
- AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN |
- AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE);
+ /* Enable DMA */
AT91F_PDC_EnableTx(tx_pdc);
-
- ssc_state.mode = ssc_mode;
-#endif
+ /* Start Transmission */
+ AT91F_SSC_EnableTx(AT91C_BASE_SSC);
}
@@ -249,6 +236,13 @@ int ssc_count_free(void) {
return free;
}
+static ssc_irq_ext_t irq_extension = NULL;
+ssc_irq_ext_t ssc_set_irq_extension(ssc_irq_ext_t ext_handler) {
+ ssc_irq_ext_t old = irq_extension;
+ irq_extension = ext_handler;
+ return old;
+}
+
static int __ramfunc __ssc_rx_refill(int secondary)
{
ssc_dma_rx_buffer_t *buffer;
@@ -289,6 +283,7 @@ static void __ramfunc ssc_irq(void)
u_int32_t ssc_sr = ssc->SSC_SR;
int i, emptyframe = 0;
u_int32_t *tmp;
+ ssc_dma_rx_buffer_t *inbuf=NULL;
DEBUGP("ssc_sr=0x%08x, mode=%u: ", ssc_sr, ssc_state.mode);
if (ssc_sr & AT91C_SSC_ENDRX) {
@@ -296,7 +291,8 @@ static void __ramfunc ssc_irq(void)
/* in a one-shot sample, we don't want to keep
* sampling further after having received the first
* packet. */
- if (ssc_state.mode == SSC_MODE_EDGE_ONE_SHOT || ssc_state.mode == SSC_MODE_14443A_SHORT) {
+ if (ssc_state.mode == SSC_MODE_EDGE_ONE_SHOT || ssc_state.mode == SSC_MODE_14443A_SHORT
+ || ssc_state.mode == SSC_MODE_14443A_STANDARD) {
DEBUGP("DISABLE_RX ");
ssc_rx_stop();
vLedSetGreen(1);
@@ -334,9 +330,13 @@ static void __ramfunc ssc_irq(void)
}
/* second buffer gets propagated to primary */
+ inbuf = ssc_state.buffer[0];
ssc_state.buffer[0] = ssc_state.buffer[1];
ssc_state.buffer[1] = NULL;
- if(ssc_state.mode != SSC_MODE_14443A_SHORT) {
+ if(ssc_state.mode == SSC_MODE_14443A_SHORT) {
+ // Stop sampling here
+ ssc_rx_stop();
+ } else {
if (ssc_sr & AT91C_SSC_RXBUFF) {
// FIXME
DEBUGP("RXBUFF! ");
@@ -357,9 +357,6 @@ static void __ramfunc ssc_irq(void)
AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX |
AT91C_SSC_RXBUFF |
AT91C_SSC_OVRUN);
- } else {
- // Stop sampling here
- ssc_rx_stop();
}
}
@@ -370,39 +367,11 @@ static void __ramfunc ssc_irq(void)
DEBUGP("CP0 ");
if (ssc_sr & AT91C_SSC_TXSYN)
- DEBUGP("TXSYN ");
-
- switch (ssc_state.mode) {
- case SSC_MODE_14443A_SHORT:
- if (ssc_sr & AT91C_SSC_RXSYN)
- DEBUGP("RXSYN ");
- if (ssc_sr & AT91C_SSC_RXRDY) {
- u_int32_t sample = ssc->SSC_RHR;
- int i = usb_print_set_default_flush(0);
- DumpUIntToUSB(sample);
- DumpStringToUSB("\n\r");
- usb_print_set_default_flush(i);
- DEBUGP("RXRDY=0x%08x ", sample);
- /* Try to set FDT compare register ASAP */
- if (sample == REQA) {
- tc_fdt_set(ISO14443A_FDT_SHORT_0);
- /* FIXME: prepare and configure ATQA response */
- } else if (sample == WUPA) {
- tc_fdt_set(ISO14443A_FDT_SHORT_1);
- /* FIXME: prepare and configure ATQA response */
- } else
- DEBUGP("<== unknown ");
- }
- break;
+ usb_print_string_f("TXSYN ", 0);
+
+ if(irq_extension != NULL)
+ irq_extension(ssc_sr, ssc_state.mode, inbuf?inbuf->data:NULL);
- case SSC_MODE_14443A_STANDARD:
- case SSC_MODE_EDGE_ONE_SHOT:
- DEBUGP("ONE_SHOT ");
- break;
- default:
- DEBUGP("UNKNOWN_MODE ");
- break;
- }
#endif
DEBUGPCR("I");
@@ -463,7 +432,7 @@ void ssc_tx_init(void)
OPENPICC_SSC_DATA | OPENPICC_SSC_DATA |
AT91C_PIO_PA15, 0);
- ssc_tx_mode_set(SSC_MODE_14443A_SHORT);
+ tx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR);
}
//static int ssc_usb_in(struct req_ctx *rctx)
@@ -550,6 +519,7 @@ void ssc_fini(void)
{
// usb_hdlr_unregister(OPENPCD_CMD_CLS_SSC);
AT91F_PDC_DisableRx(rx_pdc);
+ AT91F_PDC_DisableTx(tx_pdc);
AT91F_SSC_DisableTx(ssc);
AT91F_SSC_DisableRx(ssc);
AT91F_SSC_DisableIt(ssc, 0xfff);
diff --git a/openpicc/application/ssc_picc.h b/openpicc/application/ssc_picc.h
index db3cc00..9ba7ec8 100644
--- a/openpicc/application/ssc_picc.h
+++ b/openpicc/application/ssc_picc.h
@@ -15,6 +15,7 @@ extern void ssc_fini(void);
extern void ssc_rx_stop(void);
extern void ssc_rx_unthrottle(void);
+
enum ssc_mode {
SSC_MODE_NONE,
SSC_MODE_14443A_SHORT,
@@ -26,6 +27,16 @@ enum ssc_mode {
extern void ssc_rx_mode_set(enum ssc_mode ssc_mode);
+typedef void (*ssc_irq_ext_t)(u_int32_t ssc_sr, enum ssc_mode ssc_mode, u_int8_t* samples);
+
+/* A fast method to extend the IRQ handler from the higher level code, e.g. to prepare
+ * an ATQA answer to REQA or WUPA in iso14443_layer3a. Normally I'd use the FreeRTOS
+ * primitives to wake the task and then do everything in task context, but the delay
+ * from SSC IRQ to the task returning from xQueueReceive is around 165us. Additionally to the
+ * delay from end of communication to SSC IRQ which is around 50us. This results in way more delay
+ * than acceptable for the synchronous responses (around 87us).*/
+extern ssc_irq_ext_t ssc_set_irq_extension(ssc_irq_ext_t ext_handler);
+
extern portBASE_TYPE ssc_get_overflows(void);
extern int ssc_count_free(void);
@@ -62,4 +73,6 @@ typedef struct {
* rate is approx 4k bytes). */
extern ssc_dma_tx_buffer_t ssc_tx_buffer;
+extern void ssc_tx_start(ssc_dma_tx_buffer_t *buf);
+
#endif
diff --git a/openpicc/application/tc_fdt.c b/openpicc/application/tc_fdt.c
index d8dbfd5..57036e5 100644
--- a/openpicc/application/tc_fdt.c
+++ b/openpicc/application/tc_fdt.c
@@ -39,6 +39,7 @@
#include "led.h"
#include "tc_cdiv.h"
#include "tc_fdt.h"
+#include "usb_print.h"
static AT91PS_TC tcfdt = AT91C_BASE_TC2;
@@ -65,21 +66,25 @@ static void tc_fdt_irq(void)
sr, tcfdt->TC_CV);
if (sr & AT91C_TC_ETRGS) {
+ usb_print_string_f("tc_etrgs ", 0);
DEBUGP("Ext_trigger ");
}
if (sr & AT91C_TC_CPAS) {
+ usb_print_string_f("tc_cpas ", 0);
DEBUGP("FDT_expired ");
/* FIXME: if we are in anticol / sync mode,
* we could do software triggering of SSC TX,
* but IIRC the hardware does this by TF */
}
if (sr & AT91C_TC_CPBS) {
+ usb_print_string_f("tc_cpbs ", 0);
DEBUGP("Frame_end ");
/* FIXME: stop ssc (in continuous mode),
* take care of preparing synchronous response if
* we operate in anticol mode.*/
}
if (sr & AT91C_TC_CPCS) {
+ usb_print_string_f("tc_cpcs ", 0);
DEBUGP("Compare_C ");
}
DEBUGPCR("");
diff --git a/openpicc/config/FreeRTOSConfig.h b/openpicc/config/FreeRTOSConfig.h
index e4de597..1c3c0a6 100644
--- a/openpicc/config/FreeRTOSConfig.h
+++ b/openpicc/config/FreeRTOSConfig.h
@@ -59,7 +59,7 @@
#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 110 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) 1024*16 )
#define configMAX_TASK_NAME_LEN ( 16 )
-#define configUSE_TRACE_FACILITY 0
+#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
personal git repositories of Harald Welte. Your mileage may vary