From 6549d8861a943b7c341a03901127d84f1fa41131 Mon Sep 17 00:00:00 2001 From: henryk Date: Mon, 26 Nov 2007 21:28:19 +0000 Subject: Restructure irq handling for setting tc_fdt (works now) and to get most iso specific stuff out of ssc_picc Add ssc tx code (doesn't work yet) git-svn-id: https://svn.openpcd.org:2342/trunk@355 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/application/iso14443_layer3a.c | 92 ++++++++++++++++++++++++++-- openpicc/application/ssc_picc.c | 102 +++++++++++--------------------- openpicc/application/ssc_picc.h | 13 ++++ openpicc/application/tc_fdt.c | 5 ++ openpicc/config/FreeRTOSConfig.h | 2 +- 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 -- cgit v1.2.3