From e2e37bea66206adefbb2fc97fcbfb71c1a3cfbe7 Mon Sep 17 00:00:00 2001 From: henryk Date: Fri, 14 Mar 2008 04:55:15 +0000 Subject: Add T/C based receiver code with integrated miller decoder Integrate T/C receiver into iso14443 layer 2a Add state field to iso14443_frame, rename ssc buffer state constants Sniffer seems to work with the new code git-svn-id: https://svn.openpcd.org:2342/trunk@452 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/Makefile | 5 +- openpicc/application/cmd.c | 4 +- openpicc/application/iso14443.h | 9 ++ openpicc/application/iso14443_layer2a.c | 71 ++++++---- openpicc/application/iso14443_layer2a.h | 17 +-- openpicc/application/iso14443_layer3a.c | 24 ++-- openpicc/application/iso14443_sniffer.c | 37 ++--- openpicc/application/iso14443a_diffmiller.c | 37 ++++- openpicc/application/iso14443a_diffmiller.h | 2 + openpicc/application/iso14443a_pretender.c | 4 +- openpicc/application/main.c | 8 +- openpicc/application/openpicc.h | 1 + openpicc/application/performance.c | 5 + openpicc/application/ssc.c | 34 ++--- openpicc/application/ssc.h | 22 +-- openpicc/application/ssc_buffer.h | 10 +- openpicc/application/tc_recv.c | 213 ++++++++++++++++++++++++++++ openpicc/application/tc_recv.h | 21 +++ openpicc/application/tc_sniffer.c | 8 -- 19 files changed, 400 insertions(+), 132 deletions(-) create mode 100644 openpicc/application/tc_recv.c create mode 100644 openpicc/application/tc_recv.h (limited to 'openpicc') diff --git a/openpicc/Makefile b/openpicc/Makefile index e70eab7..b4270ab 100644 --- a/openpicc/Makefile +++ b/openpicc/Makefile @@ -88,6 +88,7 @@ ARM_SRC= \ application/tc_cdiv_sync.c \ application/tc_fdt.c \ application/tc_cdiv.c \ + application/tc_recv.c \ application/usb_print.c \ application/iso14443_layer2a.c \ application/iso14443a_manchester.c \ @@ -109,9 +110,9 @@ ARM_SRC= \ os/core/MemMang/heap_2.c \ os/usb/USB-CDC.c \ os/usb/USBIsr.c \ - application/tc_sniffer.c \ + application/iso14443_sniffer.c \ +# application/tc_sniffer.c \ # application/iso14443a_pretender.c \ -# application/iso14443_sniffer.c \ # application/iso14443_layer3a.c # diff --git a/openpicc/application/cmd.c b/openpicc/application/cmd.c index 4d7d6b2..412a349 100644 --- a/openpicc/application/cmd.c +++ b/openpicc/application/cmd.c @@ -243,9 +243,9 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) { case 'P': print_pio(); break; - case 'R': +/* case 'R': start_stop_sniffing(); - break; + break;*/ case 'C': DumpStringToUSB( " *****************************************************\n\r" diff --git a/openpicc/application/iso14443.h b/openpicc/application/iso14443.h index d3439d1..a2d7458 100644 --- a/openpicc/application/iso14443.h +++ b/openpicc/application/iso14443.h @@ -75,8 +75,17 @@ #define MAXIMUM_FRAME_SIZE 256 #define ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS (MAXIMUM_FRAME_SIZE*9 +2) +typedef enum { + FRAME_FREE=0, /* Frame is free */ + FRAME_PENDING, /* Frame is currently filled by Rx */ + FRAME_FULL, /* Frame has been filled by Rx */ + FRAME_PROCESSING,/* The frame is currently processed by the consumer */ +} iso14443_frame_state_t; + + typedef struct { enum { TYPE_A, TYPE_B } type; + iso14443_frame_state_t state; union { struct { enum { SHORT_FRAME, STANDARD_FRAME, AC_FRAME } format; diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c index 91df6b9..65d5d6a 100644 --- a/openpicc/application/iso14443_layer2a.c +++ b/openpicc/application/iso14443_layer2a.c @@ -44,6 +44,7 @@ #include "tc_fdt.h" #include "tc_cdiv.h" #include "tc_cdiv_sync.h" +#include "tc_recv.h" #include "load_modulation.h" #include "clock_switch.h" #include "pio_irq.h" @@ -58,6 +59,7 @@ static u_int8_t tx_pending=0; static u_int8_t rx_pending=0; static iso14443_receive_callback_t callback=NULL; static ssc_handle_t *ssc; +static tc_recv_handle_t th; #ifdef FOUR_TIMES_OVERSAMPLING #define RX_DIVIDER 32 @@ -65,10 +67,9 @@ static ssc_handle_t *ssc; #define RX_DIVIDER 64 #endif -int iso14443_receive(iso14443_receive_callback_t _callback, ssc_dma_rx_buffer_t **buffer, unsigned int timeout) +int iso14443_receive(iso14443_receive_callback_t _callback, iso14443_frame **frame, unsigned int timeout) { - ssc_dma_rx_buffer_t* _buffer = NULL; - int len; + iso14443_frame* _frame = NULL; if(rx_pending) { return -EALREADY; @@ -76,9 +77,9 @@ int iso14443_receive(iso14443_receive_callback_t _callback, ssc_dma_rx_buffer_t rx_pending=1; callback=_callback; - if(ssc_recv(ssc, &_buffer, timeout) == 0) { + if(tc_recv_receive(th, &_frame, timeout) == 0) { - if(_buffer == NULL) { + if(_frame == NULL) { /* Can this happen? */ rx_pending=0; callback=NULL; @@ -86,25 +87,23 @@ int iso14443_receive(iso14443_receive_callback_t _callback, ssc_dma_rx_buffer_t } portENTER_CRITICAL(); - _buffer->state = PROCESSING; + _frame->state = FRAME_PROCESSING; portEXIT_CRITICAL(); - len = _buffer->len_transfers; - if(callback != NULL && !fast_receive) { - callback(_buffer, 0); + callback(NULL, _frame, 0); } - if(buffer != NULL) *buffer = _buffer; + if(frame != NULL) *frame = _frame; else { portENTER_CRITICAL(); - _buffer->state = FREE; + _frame->state = FRAME_FREE; portEXIT_CRITICAL(); } rx_pending=0; callback=NULL; - return len; + return 0; } /* Note: There is the remote chance of a race condition probability here if @@ -185,7 +184,7 @@ u_int8_t iso14443_get_fast_receive(void) static void iso14443_ssc_callback(ssc_callback_reason reason, void *data) { - if(reason == CALLBACK_RX_FRAME_BEGIN) { + if(reason == SSC_CALLBACK_RX_FRAME_BEGIN) { /* Busy loop for the frame end */ int *end_asserted = data, i=0; for(i=0; i<96000; i++) @@ -197,20 +196,20 @@ static void iso14443_ssc_callback(ssc_callback_reason reason, void *data) return; } - if(reason == CALLBACK_TX_FRAME_ENDED) { + if(reason == SSC_CALLBACK_TX_FRAME_ENDED) { tx_pending = 0; } - if( reason == CALLBACK_RX_FRAME_ENDED && fast_receive ) { + if( reason == SSC_CALLBACK_RX_FRAME_ENDED && fast_receive ) { clock_switch(CLOCK_SELECT_CARRIER); /* A Tx might be coming up */ ssc_dma_rx_buffer_t *buffer = data; if(callback != NULL) - callback(buffer, 1); + callback(buffer, NULL, 1); } - if( (reason == CALLBACK_RX_FRAME_ENDED && !tx_pending) || reason == CALLBACK_RX_STARTING - || reason == CALLBACK_TX_FRAME_ENDED ) { + if( (reason == SSC_CALLBACK_RX_FRAME_ENDED && !tx_pending) || reason == SSC_CALLBACK_RX_STARTING + || reason == SSC_CALLBACK_TX_FRAME_ENDED ) { /* For regular SSC Rx we'd set the clock to // clock_switch(CLOCK_SELECT_PLL); * however, the SSC Rx code is going to go away (at least for 14443-A) @@ -226,16 +225,27 @@ static void iso14443_ssc_callback(ssc_callback_reason reason, void *data) usb_print_set_default_flush(old); #endif } - } -static portBASE_TYPE iso14443_rx_FRAME_cb(u_int32_t pio, portBASE_TYPE xTaskWoken) +static void iso14443_tc_recv_callback(tc_recv_callback_reason reason, void *data) { - (void)pio; - if(PRINT_DEBUG) usb_print_string_f("°", 0); // DEBUG OUTPUT - if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_PIO_FRAME)) - ssc_frame_started(); - return xTaskWoken; + if( reason == TC_RECV_CALLBACK_RX_FRAME_ENDED && fast_receive ) { + clock_switch(CLOCK_SELECT_CARRIER); /* A Tx might be coming up */ + + iso14443_frame *frame = data; + if(callback != NULL) + callback(NULL, frame, 1); + } + + if( (reason == TC_RECV_CALLBACK_RX_FRAME_ENDED && !tx_pending) || + reason == TC_RECV_CALLBACK_SETUP ) { + /* For T/C Rx we set the clock to */ + clock_switch(CLOCK_SELECT_CARRIER); + ssc_set_gate(1); + tc_fdt_set(0xff00); + tc_cdiv_set_divider(RX_DIVIDER); + tc_cdiv_sync_reset(); + } } int iso14443_layer2a_init(u_int8_t enable_fast_receive) @@ -251,14 +261,15 @@ int iso14443_layer2a_init(u_int8_t enable_fast_receive) iso14443_set_fast_receive(enable_fast_receive); pio_irq_init_once(); - if(pio_irq_register(OPENPICC_PIO_FRAME, &iso14443_rx_FRAME_cb) >= 0) { - if(PRINT_DEBUG) usb_print_string("FRAME irq registered\n\r"); // DEBUG OUTPUT - } - - ssc = ssc_open(1, 1, SSC_MODE_14443A, iso14443_ssc_callback); + ssc = ssc_open(0, 1, SSC_MODE_14443A, iso14443_ssc_callback); if(ssc == NULL) return -EIO; + if(tc_recv_init(&th, 0, iso14443_tc_recv_callback) < 0) { + ssc_close(ssc); + return -EIO; + } + load_mod_level(3); return 0; diff --git a/openpicc/application/iso14443_layer2a.h b/openpicc/application/iso14443_layer2a.h index 858af81..a8874d0 100644 --- a/openpicc/application/iso14443_layer2a.h +++ b/openpicc/application/iso14443_layer2a.h @@ -4,36 +4,37 @@ #include "ssc_buffer.h" /* Callback type for iso14443_receive(). - * Parameter buffer is being passed a pointer to an SSC Rx buffer structure that this receive happened - * on. You might want to pass this into iso14443a_decode_miller(). + * Parameter buffer is either being passed a pointer to an SSC Rx buffer structure that this + * receive happened on, or a fully decoded iso14443_frame. + * If it's an SSC buffer you might want to pass this into iso14443a_decode_miller(). * Parameter in_irq is true if the callback has been called while still in IRQ mode. It must then *NOT* * perform any calls that might upset the IRQ processing. Especially it may not call into FreeRTOS or * any parts of the applications that do. */ -typedef void (*iso14443_receive_callback_t)(ssc_dma_rx_buffer_t *buffer, u_int8_t in_irq); +typedef void (*iso14443_receive_callback_t)(ssc_dma_rx_buffer_t *buffer, iso14443_frame *frame, u_int8_t in_irq); /* Wait for and receive a frame. Parameters callback and buffer are optional. If you omit them you'll lose * the received frame, obviously. * Parameter callback is a callback function that will be called for each received frame and might * then trigger a response. - * Parameter buffer is an output pointer to a pointer to an SSC Rx buffer structure containing the + * Parameter frame is an output pointer to a pointer to an ISO14443 frame structure containing the * received frame. * Parameter timeout gives an optional timeout for the receive operation after which the receive will * be aborted. When timeout is 0 the receive will not time out. * This call will block until a frame is received or an exception happens. Obviously it must not be run * from IRQ context. * - * Warning: When you get a buffer from the function then its state is set to PROCESSING and you must - * FREE it yourself. However, you MUST NOT free a buffer from the callback. + * Warning: When you get a frame from the function then its state is set to SSC_PROCESSING and you must + * SSC_FREE it yourself. However, you MUST NOT free a buffer or a frame from the callback. * * Return values: - * >= 0 Frame received, return value is buffer length (yes, 0 is a valid buffer length) + * = 0 Frame received * -ENETDOWN PLL is not locked or PLL lock lost * -ETIMEDOUT Receive timed out without receiving anything (usually not regarded an error condition) * -EBUSY A Tx is currently running or pending; can't receive * -EALREADY There's already an iso14443_receive() invocation running */ -extern int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t **buffer, unsigned int timeout); +extern int iso14443_receive(iso14443_receive_callback_t callback, iso14443_frame **frame, unsigned int timeout); /* * Transmit a frame. Starts transmitting fdt carrier cycles after the end of the received frame. diff --git a/openpicc/application/iso14443_layer3a.c b/openpicc/application/iso14443_layer3a.c index daac8dd..132038e 100644 --- a/openpicc/application/iso14443_layer3a.c +++ b/openpicc/application/iso14443_layer3a.c @@ -158,8 +158,8 @@ void __ramfunc iso14443_layer3a_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode if(send_atqa) { vLedSetGreen(0); - if(ssc_tx_buffer.state == PREFILLED && ssc_tx_buffer.source == &ATQA_FRAME) { - ssc_tx_buffer.state = PROCESSING; + if(ssc_tx_buffer.state == SSC_PREFILLED && ssc_tx_buffer.source == &ATQA_FRAME) { + ssc_tx_buffer.state = SSC_PROCESSING; vLedSetGreen(1); iso14443_transmit(&ssc_tx_buffer, fdt, 8); atqa_sent = 1; @@ -174,8 +174,8 @@ void __ramfunc iso14443_layer3a_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode #define FALSE (0!=0) static int prefill_buffer(ssc_dma_tx_buffer_t *dest, const iso14443_frame *src) { portENTER_CRITICAL(); - if(dest->state == FREE) { - dest->state = PROCESSING; + if(dest->state == SSC_FREE) { + dest->state = SSC_PROCESSING; portEXIT_CRITICAL(); dest->source = (void*)src; dest->len = sizeof(ssc_tx_buffer.data); @@ -185,15 +185,15 @@ static int prefill_buffer(ssc_dma_tx_buffer_t *dest, const iso14443_frame *src) if(ret>0) { dest->len = ret; portENTER_CRITICAL(); - dest->state = PREFILLED; + dest->state = SSC_PREFILLED; portEXIT_CRITICAL(); } else { portENTER_CRITICAL(); - dest->state = FREE; + dest->state = SSC_FREE; portEXIT_CRITICAL(); } return ret > 0; - } else if(dest->state == PREFILLED) { + } else if(dest->state == SSC_PREFILLED) { portEXIT_CRITICAL(); return dest->source == src; } else { @@ -325,7 +325,7 @@ void iso14443_layer3a_state_machine (void *pvParameters) vLedSetGreen(0); vLedBlinkGreen(); portENTER_CRITICAL(); - buffer->state = PROCESSING; + buffer->state = SSC_PROCESSING; portEXIT_CRITICAL(); u_int32_t first_sample = *(u_int32_t*)buffer->data; @@ -392,16 +392,16 @@ void iso14443_layer3a_state_machine (void *pvParameters) ssc_rx_start(); } else { //vTaskDelay(portTICK_RATE_MS); - if(ssc_tx_buffer.source == &ATQA_FRAME) ssc_tx_buffer.state = FREE; + if(ssc_tx_buffer.source == &ATQA_FRAME) ssc_tx_buffer.state = SSC_FREE; if(prefill_buffer(&ssc_tx_buffer, &NULL_FRAME)) { usb_print_string_f("Sending response ...",0); - ssc_tx_buffer.state = PROCESSING; + ssc_tx_buffer.state = SSC_PROCESSING; iso14443_transmit(&ssc_tx_buffer, received_frame.parameters.a.last_bit==ISO14443A_LAST_BIT_0 ? ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0 : ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1, 8); - while( ssc_tx_buffer.state != FREE ) { + while( ssc_tx_buffer.state != SSC_FREE ) { vTaskDelay(portTICK_RATE_MS); } usb_print_string("done\n\r"); @@ -415,7 +415,7 @@ void iso14443_layer3a_state_machine (void *pvParameters) } portENTER_CRITICAL(); - buffer->state = FREE; + buffer->state = SSC_FREE; portEXIT_CRITICAL(); } } else vTaskDelay(portTICK_RATE_MS); diff --git a/openpicc/application/iso14443_sniffer.c b/openpicc/application/iso14443_sniffer.c index bc326b4..6d4a451 100644 --- a/openpicc/application/iso14443_sniffer.c +++ b/openpicc/application/iso14443_sniffer.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "openpicc.h" #include "ssc_buffer.h" @@ -37,12 +38,11 @@ #include "cmd.h" #include "led.h" -static iso14443_frame rx_frame; +static iso14443_frame *rx_frame; void iso14443_sniffer (void *pvParameters) { (void)pvParameters; - (void)rx_frame; int res; /* Delay until USB print etc. are ready */ @@ -56,47 +56,30 @@ void iso14443_sniffer (void *pvParameters) } } while(res < 0); + + //while(1) { static int i=0; vTaskDelay(10*portTICK_RATE_MS); vLedSetBrightness(LED_RED, abs(1000-i)); i=(i+8)%2000; } + usb_print_string("Waiting for carrier. "); while(iso14443_wait_for_carrier(1000 * portTICK_RATE_MS) != 0) { } usb_print_string("Carrier detected.\n\r"); while(true) { - ssc_dma_rx_buffer_t *buffer = 0; - res = iso14443_receive(NULL, &buffer, 20000 * portTICK_RATE_MS); + res = iso14443_receive(NULL, &rx_frame, 20000 * portTICK_RATE_MS); if(res >= 0) { -#if 1 DumpStringToUSB("\n\r"); DumpTimeToUSB(xTaskGetTickCount()); usb_print_string(": Frame received, consists of "); - DumpUIntToUSB(res); - usb_print_string(" transfers ("); - DumpUIntToUSB(buffer->reception_mode->transfersize_ssc); - usb_print_string(" bits from SSC each)\n\r "); - if(buffer->len_transfers < 200) - DumpBufferToUSB((char*)buffer->data, (buffer->len_transfers * buffer->reception_mode->transfersize_pdc)/8); - else { - DumpBufferToUSB((char*)buffer->data, (200 * buffer->reception_mode->transfersize_pdc)/8); - usb_print_string("..."); - } - usb_print_string("\n\r "); - iso14443a_decode_miller(&rx_frame, buffer); - - usb_print_string("Decodes to "); - DumpUIntToUSB(rx_frame.numbytes); + DumpUIntToUSB(rx_frame->numbytes); usb_print_string(" bytes and "); - DumpUIntToUSB(rx_frame.numbits); + DumpUIntToUSB(rx_frame->numbits); usb_print_string(" bits: "); - DumpBufferToUSB((char*)rx_frame.data, rx_frame.numbytes + (rx_frame.numbits+7)/8 ); + DumpBufferToUSB((char*)rx_frame->data, rx_frame->numbytes + (rx_frame->numbits+7)/8 ); usb_print_string("\n\r"); -#else - DumpUIntToUSB(buffer->len_transfers); - DumpStringToUSB("\n\r"); -#endif portENTER_CRITICAL(); - buffer->state = FREE; + rx_frame->state = FRAME_FREE; portEXIT_CRITICAL(); } else { if(res != -ETIMEDOUT) { diff --git a/openpicc/application/iso14443a_diffmiller.c b/openpicc/application/iso14443a_diffmiller.c index a5acfc8..d73bf95 100644 --- a/openpicc/application/iso14443a_diffmiller.c +++ b/openpicc/application/iso14443a_diffmiller.c @@ -124,6 +124,7 @@ inline void start_frame(struct diffmiller_state * const state) //memset(state->frame, 0, sizeof(*state->frame)); memset(state->frame, 0, (u_int32_t)&(((iso14443_frame*)0)->data) ); performance_set_checkpoint("start_frame after memset"); + state->frame->state = FRAME_PENDING; } static inline void append_to_frame(struct diffmiller_state *const state, @@ -171,7 +172,7 @@ static inline void end_frame(struct diffmiller_state * const state, const u_int3 } #define PRINT_BIT(a) if(0){(void)a;} -//#define PRINT_BIT(a) usb_print_string(a) +//#define PRINT_BIT(a) usb_print_string_f(a,0) #define DO_BIT_0 { \ if(++counter==9) { \ @@ -194,10 +195,10 @@ static inline void end_frame(struct diffmiller_state * const state, const u_int3 } #define DO_SYMBOL_X \ + PRINT_BIT("(X)"); \ if(!in_frame) { \ if(last_bit == BIT_0) DO_BIT_0; \ error = 1; \ - end_frame(state, counter); \ PRINT_BIT(" ERROR\n"); \ last_bit = BIT_ERROR; \ in_frame = 0; \ @@ -208,10 +209,10 @@ static inline void end_frame(struct diffmiller_state * const state, const u_int3 } #define DO_SYMBOL_Y \ + PRINT_BIT("(Y)"); \ if(!in_frame) { \ if(last_bit == BIT_0) DO_BIT_0; \ error = 1; \ - end_frame(state, counter); \ PRINT_BIT(" ERROR\n"); \ last_bit = BIT_ERROR; \ in_frame = 0; \ @@ -227,6 +228,7 @@ static inline void end_frame(struct diffmiller_state * const state, const u_int3 } #define DO_SYMBOL_Z \ + PRINT_BIT("(Z)"); \ if(!in_frame) { \ if(last_bit == BIT_0) DO_BIT_0; \ counter = 0; \ @@ -308,11 +310,12 @@ int iso14443a_decode_diffmiller(struct diffmiller_state * const state, iso14443_ if(state->flags.frame_finished) { state->flags.frame_finished = 0; - state->old_state = old_state; + state->old_state = sym_y; state->last_bit = last_bit; state->counter = counter; state->flags.in_frame = in_frame; state->flags.error = error; + state->frame = NULL; performance_set_checkpoint("frame finished"); return 0; } @@ -327,6 +330,31 @@ int iso14443a_decode_diffmiller(struct diffmiller_state * const state, iso14443_ return -EBUSY; } +int iso14443a_diffmiller_assert_frame_ended(struct diffmiller_state * const state, + iso14443_frame * const frame) +{ + if(state == NULL || !state->initialized) return -EINVAL; + if(!state->flags.in_frame) return -EBUSY; + if(state->frame != NULL && state->frame != frame) return -EINVAL; + state->frame = frame; + + end_frame(state, state->counter); + PRINT_BIT(" EOF2\n"); + state->flags.in_frame = 0; + + if(state->flags.frame_finished) { + state->flags.frame_finished = 0; + state->old_state = sym_y; + state->last_bit = BIT_EOF; + state->counter = 0; + state->frame = NULL; + performance_set_checkpoint("frame finished2"); + return 0; + } + + return -EBUSY; +} + struct diffmiller_state *iso14443a_init_diffmiller(int pauses_count) { if(_state.initialized) return NULL; @@ -334,6 +362,7 @@ struct diffmiller_state *iso14443a_init_diffmiller(int pauses_count) state->initialized = 1; state->pauses_count = pauses_count; state->frame = NULL; + state->old_state = sym_y; state->flags.frame_finished = 0; return state; diff --git a/openpicc/application/iso14443a_diffmiller.h b/openpicc/application/iso14443a_diffmiller.h index f5336d6..7dc9c55 100644 --- a/openpicc/application/iso14443a_diffmiller.h +++ b/openpicc/application/iso14443a_diffmiller.h @@ -7,6 +7,8 @@ struct diffmiller_state; extern int iso14443a_decode_diffmiller(struct diffmiller_state *state, iso14443_frame *frame, const u_int32_t buffer[], unsigned int *offset, const unsigned int buflen); +extern int iso14443a_diffmiller_assert_frame_ended(struct diffmiller_state * const state, + iso14443_frame * const frame); extern struct diffmiller_state *iso14443a_init_diffmiller(int pauses_count); #endif /*ISO14443A_DIFFMILLER_H_*/ diff --git a/openpicc/application/iso14443a_pretender.c b/openpicc/application/iso14443a_pretender.c index 64112d1..03fb12d 100644 --- a/openpicc/application/iso14443a_pretender.c +++ b/openpicc/application/iso14443a_pretender.c @@ -118,7 +118,7 @@ static void fast_receive_callback(ssc_dma_rx_buffer_t *buffer, u_int8_t in_irq) if(tx_buffer != NULL) { - tx_buffer->state = FULL; + tx_buffer->state = SSC_FULL; if( iso14443_transmit(tx_buffer, fdt, 1, 0) < 0) { usb_print_string_f("Tx failed ", 0); } @@ -229,7 +229,7 @@ prefill_failed: } portENTER_CRITICAL(); - buffer->state = FREE; + buffer->state = SSC_FREE; portEXIT_CRITICAL(); } else { if(res != -ETIMEDOUT) { diff --git a/openpicc/application/main.c b/openpicc/application/main.c index 8babafe..a082933 100644 --- a/openpicc/application/main.c +++ b/openpicc/application/main.c @@ -211,12 +211,12 @@ int main (void) NULL, TASK_USB_PRIORITY, NULL); /*xTaskCreate (iso14443_layer3a_state_machine, (signed portCHAR *) "ISO14443A-3", TASK_ISO_STACK, NULL, TASK_ISO_PRIORITY, NULL);*/ - /*xTaskCreate (iso14443_sniffer, (signed portCHAR *) "ISO14443-SNIFF", TASK_ISO_STACK, - NULL, TASK_ISO_PRIORITY, NULL);*/ + xTaskCreate (iso14443_sniffer, (signed portCHAR *) "ISO14443-SNIFF", TASK_ISO_STACK, + NULL, TASK_ISO_PRIORITY, NULL); /*xTaskCreate (iso14443a_pretender, (signed portCHAR *) "ISO14443A-PRETEND", TASK_ISO_STACK, NULL, TASK_ISO_PRIORITY, NULL);*/ - xTaskCreate (tc_sniffer, (signed portCHAR *) "RFID-SNIFFER", TASK_ISO_STACK, - NULL, TASK_ISO_PRIORITY, NULL); + /*xTaskCreate (tc_sniffer, (signed portCHAR *) "RFID-SNIFFER", TASK_ISO_STACK, + NULL, TASK_ISO_PRIORITY, NULL);*/ xTaskCreate (vUSBCDCTask, (signed portCHAR *) "USB", TASK_USB_STACK, diff --git a/openpicc/application/openpicc.h b/openpicc/application/openpicc.h index b4d2b7a..17cb4ee 100644 --- a/openpicc/application/openpicc.h +++ b/openpicc/application/openpicc.h @@ -39,5 +39,6 @@ typedef int s_int32_t; #define DA_BASELINE 200 #define DIV_ROUND_UP(a,b) ( (a+(b-1)) / b) +#define MIN(a, b) ((a)>(b)?(b):(a)) #endif/*__OPENPICC_H__*/ diff --git a/openpicc/application/performance.c b/openpicc/application/performance.c index cffd094..4515f18 100644 --- a/openpicc/application/performance.c +++ b/openpicc/application/performance.c @@ -33,6 +33,7 @@ static u_int32_t overruns = 0; #define NUMBER_OF_CHECKPOINTS 20 static struct performance_checkpoint checkpoints[NUMBER_OF_CHECKPOINTS]; static int current_checkpoint; +static int running=0; static void __ramfunc tc_perf_irq(void) __attribute__ ((naked)); static void __ramfunc tc_perf_irq(void) @@ -66,6 +67,7 @@ inline void performance_start(void) memset(checkpoints, 0, sizeof(checkpoints)); current_checkpoint = 0; overruns = 0; + running = 1; tc_perf->TC_CCR = AT91C_TC_SWTRG | AT91C_TC_CLKEN; } @@ -82,6 +84,7 @@ inline perf_time_t performance_get(void) inline perf_time_t performance_stop(void) { perf_time_t result = performance_get(); + running = 0; tc_perf->TC_CCR = AT91C_TC_CLKDIS; return result; } @@ -105,6 +108,7 @@ perf_time_t performance_diff(perf_time_t a, perf_time_t b) void performance_set_checkpoint(const char * const description) { + if(!running) return; if(current_checkpoint < NUMBER_OF_CHECKPOINTS) { perf_time_t time = performance_get(); checkpoints[current_checkpoint++] = (struct performance_checkpoint){ @@ -116,6 +120,7 @@ void performance_set_checkpoint(const char * const description) void performance_stop_report(void) { + if(!running) return; perf_time_t _now = performance_stop(); struct performance_checkpoint now = { .time = _now, diff --git a/openpicc/application/ssc.c b/openpicc/application/ssc.c index e25d982..4da45ae 100644 --- a/openpicc/application/ssc.c +++ b/openpicc/application/ssc.c @@ -125,7 +125,7 @@ static int __ramfunc _ssc_rx_irq(u_int32_t orig_sr, int start_asserted, portBASE sh->ssc->SSC_RCMR = (orig_rcmr & (~AT91C_SSC_START)) | (AT91C_SSC_START_CONTINOUS); /* Receiving has started */ if(sh->callback != NULL) { - sh->callback(CALLBACK_RX_FRAME_BEGIN, &end_asserted); + sh->callback(SSC_CALLBACK_RX_FRAME_BEGIN, &end_asserted); if(end_asserted) sr = orig_sr | _ssc.ssc->SSC_SR; } @@ -147,9 +147,9 @@ static int __ramfunc _ssc_rx_irq(u_int32_t orig_sr, int start_asserted, portBASE ssc_dma_rx_buffer_t *buffer = _unload_rx(sh); if(buffer != NULL) { if(sh->callback != NULL) - sh->callback(CALLBACK_RX_FRAME_ENDED, buffer); + sh->callback(SSC_CALLBACK_RX_FRAME_ENDED, buffer); - if(buffer->state != FREE) { + if(buffer->state != SSC_FREE) { task_woken = xQueueSendFromISR(sh->rx_queue, &buffer, task_woken); } } @@ -174,7 +174,7 @@ static int __ramfunc _ssc_rx_irq(u_int32_t orig_sr, int start_asserted, portBASE } else { sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK; sh->rx_running = 0; - sh->callback(CALLBACK_RX_STOPPED, sh); + sh->callback(SSC_CALLBACK_RX_STOPPED, sh); } } @@ -202,7 +202,7 @@ static void __ramfunc _ssc_tx_end(ssc_handle_t *sh, int is_an_abort) AT91F_PDC_SetNextTx(sh->pdc, 0, 0); if(sh->tx_buffer) { - sh->tx_buffer->state = FREE; + sh->tx_buffer->state = SSC_FREE; sh->tx_running = 0; } @@ -213,9 +213,9 @@ static void __ramfunc _ssc_tx_end(ssc_handle_t *sh, int is_an_abort) if(sh->callback) { if(is_an_abort) - sh->callback(CALLBACK_TX_FRAME_ABORTED, sh->tx_buffer); + sh->callback(SSC_CALLBACK_TX_FRAME_ABORTED, sh->tx_buffer); else - sh->callback(CALLBACK_TX_FRAME_ENDED, sh->tx_buffer); + sh->callback(SSC_CALLBACK_TX_FRAME_ENDED, sh->tx_buffer); } sh->tx_buffer = NULL; @@ -236,7 +236,7 @@ static int __ramfunc _ssc_tx_irq(u_int32_t sr, portBASE_TYPE task_woken) sh->ssc->SSC_TCMR = (sh->ssc->SSC_TCMR & ~AT91C_SSC_START) | AT91C_SSC_START_CONTINOUS; if(sh->callback) - sh->callback(CALLBACK_TX_FRAME_BEGIN, NULL); + sh->callback(SSC_CALLBACK_TX_FRAME_BEGIN, NULL); } if( sr & AT91C_SSC_TXEMPTY ) { @@ -297,7 +297,7 @@ static __ramfunc int _reload_rx(ssc_handle_t *sh) goto out; } - ssc_dma_rx_buffer_t *buffer = _get_buffer(FREE, PENDING); + ssc_dma_rx_buffer_t *buffer = _get_buffer(SSC_FREE, SSC_PENDING); if(buffer == NULL) { ssc_metrics[METRIC_RX_OVERFLOWS].value++; @@ -328,7 +328,7 @@ static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh) rcr = sh->pdc->PDC_RCR; AT91F_PDC_SetRx(sh->pdc, 0, 0); sh->rx_buffer[0] = NULL; - buffer->state = FULL; + buffer->state = SSC_FULL; if(rcr == 0) { buffer->flags.overflow = 1; @@ -357,7 +357,7 @@ static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh) if((buffer->len_transfers - rcr) != (rpr - (unsigned int)buffer->data)*(buffer->reception_mode->transfersize_pdc/8)) { ssc_metrics[METRIC_MANAGEMENT_ERRORS_3].value++; - buffer->state = FREE; + buffer->state = SSC_FREE; return NULL; } @@ -393,7 +393,7 @@ static void _ssc_start_rx(ssc_handle_t *sh) AT91C_SSC_CP1 | AT91C_SSC_ENDRX; sh->rx_running = 1; if(sh->callback != NULL) - sh->callback(CALLBACK_RX_STARTING, sh); + sh->callback(SSC_CALLBACK_RX_STARTING, sh); // Actually enable reception int dummy = sh->ssc->SSC_RHR; (void)dummy; @@ -411,7 +411,7 @@ static void _ssc_stop_rx(ssc_handle_t *sh) sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK; sh->rx_running = 0; if(sh->callback != NULL) - sh->callback(CALLBACK_RX_STOPPED, sh); + sh->callback(SSC_CALLBACK_RX_STOPPED, sh); taskEXIT_CRITICAL(); } @@ -556,7 +556,7 @@ static int _ssc_register_callback(ssc_handle_t *sh, ssc_callback_t _callback) if(sh->callback != NULL) return -EBUSY; sh->callback = _callback; if(sh->callback != NULL) - sh->callback(CALLBACK_SETUP, sh); + sh->callback(SSC_CALLBACK_SETUP, sh); return 0; } @@ -565,7 +565,7 @@ static int _ssc_unregister_callback(ssc_handle_t *sh, ssc_callback_t _callback) if(!sh) return -EINVAL; if(_callback == NULL || sh->callback == _callback) { if(sh->callback != NULL) - sh->callback(CALLBACK_TEARDOWN, sh); + sh->callback(SSC_CALLBACK_TEARDOWN, sh); sh->callback = NULL; } return 0; @@ -686,7 +686,7 @@ int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer) AT91F_PDC_SetTx(sh->pdc, buffer->data, num_data); AT91F_PDC_SetNextTx(sh->pdc, 0, 0); - buffer->state = PENDING; + buffer->state = SSC_PENDING; sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY | AT91C_SSC_TXSYN; /* Enable DMA */ @@ -795,7 +795,7 @@ int ssc_get_metric(ssc_metric metric, char **description, int *value) _value = 0; int i; for(i=0; i < SSC_DMA_BUFFER_COUNT; i++) - if(_rx_buffers[i].state == FREE) _value++; + if(_rx_buffers[i].state == SSC_FREE) _value++; break; case METRIC_MANAGEMENT_ERRORS: _value = ssc_metrics[METRIC_MANAGEMENT_ERRORS_1].value + diff --git a/openpicc/application/ssc.h b/openpicc/application/ssc.h index 9edec64..e99d444 100644 --- a/openpicc/application/ssc.h +++ b/openpicc/application/ssc.h @@ -21,17 +21,17 @@ typedef enum { extern int ssc_get_metric(ssc_metric metric, char **description, int *value); typedef enum { - CALLBACK_RX_STARTING, // *data is ssh_handle_t *sh - CALLBACK_RX_STOPPED, // *data is ssh_handle_t *sh - CALLBACK_RX_FRAME_BEGIN, // *data is int *end_asserted - // may set *end_asserted = 1 to force tell the IRQ handler - // that you have detected the end of reception - CALLBACK_RX_FRAME_ENDED, // *data is ssc_dma_rx_buffer *buffer - CALLBACK_TX_FRAME_BEGIN, - CALLBACK_TX_FRAME_ENDED, - CALLBACK_TX_FRAME_ABORTED, - CALLBACK_SETUP, // *data is ssh_handle_t *sh - CALLBACK_TEARDOWN, // *data is ssh_handle_t *sh + SSC_CALLBACK_RX_STARTING, // *data is ssh_handle_t *sh + SSC_CALLBACK_RX_STOPPED, // *data is ssh_handle_t *sh + SSC_CALLBACK_RX_FRAME_BEGIN, // *data is int *end_asserted + // may set *end_asserted = 1 to force tell the IRQ handler + // that you have detected the end of reception + SSC_CALLBACK_RX_FRAME_ENDED, // *data is ssc_dma_rx_buffer *buffer + SSC_CALLBACK_TX_FRAME_BEGIN, + SSC_CALLBACK_TX_FRAME_ENDED, + SSC_CALLBACK_TX_FRAME_ABORTED, + SSC_CALLBACK_SETUP, // *data is ssh_handle_t *sh + SSC_CALLBACK_TEARDOWN, // *data is ssh_handle_t *sh } ssc_callback_reason; typedef void (*ssc_callback_t)(ssc_callback_reason reason, void *data); diff --git a/openpicc/application/ssc_buffer.h b/openpicc/application/ssc_buffer.h index 5365851..527ae46 100644 --- a/openpicc/application/ssc_buffer.h +++ b/openpicc/application/ssc_buffer.h @@ -15,11 +15,11 @@ #endif typedef enum { - FREE=0, /* Buffer is free */ - PENDING, /* Buffer has been given to the DMA controller and is currently being filled */ - FULL, /* DMA controller signalled that the buffer is full */ - PROCESSING,/* The buffer is currently processed by the consumer (e.g. decoder) */ - PREFILLED, /* The buffer has been prefilled for later usage (only used for TX) */ + SSC_FREE=0, /* Buffer is free */ + SSC_PENDING, /* Buffer has been given to the DMA controller and is currently being filled */ + SSC_FULL, /* DMA controller signalled that the buffer is full */ + SSC_PROCESSING,/* The buffer is currently processed by the consumer (e.g. decoder) */ + SSC_PREFILLED, /* The buffer has been prefilled for later usage (only used for TX) */ } ssc_dma_buffer_state_t; enum ssc_mode { diff --git a/openpicc/application/tc_recv.c b/openpicc/application/tc_recv.c new file mode 100644 index 0000000..fa6b510 --- /dev/null +++ b/openpicc/application/tc_recv.c @@ -0,0 +1,213 @@ +/*************************************************************** + * + * OpenPICC - ISO 14443 Layer 2 Type A T/C based receiver code + * Implements a receiver using FDT Timer/Counter (TC2) and the + * FIQ to measure the number of carrier cycles between modulation + * pauses. + * + * The timing measurements are given to the differential miller + * decoder on the fly to interleave reception and decoding. This + * means two things: a) The CPU will be held in an IRQ handler + * with IRQs disabled for the time of reception and b) The frame + * will already have been fully decoded to a iso14443_frame + * structure when reception ends. + * + * Copyright 2008 Henryk Plötz + * + *************************************************************** + + 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 +#include +#include +#include + +#include +#include + +#include "tc_recv.h" + +#include "iso14443a_diffmiller.h" +#include "usb_print.h" +#include "pio_irq.h" +#include "led.h" +#include "cmd.h" + +struct tc_recv_handle { + u_int8_t initialized; + u_int8_t pauses_count; + struct diffmiller_state *decoder; + int current, next; + tc_recv_callback_t callback; + iso14443_frame *current_frame; + xQueueHandle rx_queue; +}; + +static struct tc_recv_handle _tc; + +#define BUFSIZE 1024 +typedef struct { + u_int32_t count; + u_int32_t data[BUFSIZE]; +} fiq_buffer_t; +fiq_buffer_t fiq_buffers[2]; + +fiq_buffer_t *tc_sniffer_next_buffer_for_fiq = 0; + +iso14443_frame rx_frames[TC_RECV_NUMBER_OF_FRAME_BUFFERS]; + +#define REAL_FRAME_END 333 + +static int tc_recv_buffer_overruns = 0; + +static inline iso14443_frame *get_frame_buffer(tc_recv_handle_t th) +{ + if(th->current_frame) return th->current_frame; + unsigned int i; iso14443_frame *result; + for(i=0; istate = FRAME_PENDING; + th->current_frame = result; + return result; + } + } + tc_recv_buffer_overruns++; + return NULL; +} + +static portBASE_TYPE handle_frame(iso14443_frame *frame, portBASE_TYPE task_woken) +{ + if(_tc.callback) _tc.callback(TC_RECV_CALLBACK_RX_FRAME_ENDED, frame); + if(frame->state != FRAME_FREE) { + task_woken = xQueueSendFromISR(_tc.rx_queue, &frame, task_woken); + } + _tc.current_frame = NULL; + return task_woken; +} + +static portBASE_TYPE handle_buffer(u_int32_t data[], unsigned int count, portBASE_TYPE task_woken) +{ + unsigned int offset = 0; + while(offset < count) { + iso14443_frame *rx_frame = get_frame_buffer(&_tc); + if(rx_frame == NULL) return task_woken; + int ret = iso14443a_decode_diffmiller(_tc.decoder, rx_frame, data, &offset, count); + if(ret == 0) { + task_woken = handle_frame(rx_frame, task_woken); + } + } + return task_woken; +} + +static inline portBASE_TYPE flush_buffer(fiq_buffer_t *buffer, portBASE_TYPE task_woken) +{ + if(buffer->count > 0) { + if(buffer->count >= BUFSIZE) { + usb_print_string_f("Warning: Possible buffer overrun detected\n\r",0); + //overruns++; + } + buffer->count = MIN(buffer->count, BUFSIZE); + task_woken = handle_buffer(buffer->data, buffer->count, task_woken); + buffer->count = 0; + } + return task_woken; +} + +#define NEXT_BUFFER(a) ((a+1)%(sizeof(fiq_buffers)/sizeof(fiq_buffers[0]))) + +static portBASE_TYPE switch_buffers(portBASE_TYPE task_woken) +{ + _tc.next = NEXT_BUFFER(_tc.current); + task_woken = flush_buffer( &fiq_buffers[_tc.next] , task_woken); + + tc_sniffer_next_buffer_for_fiq = &fiq_buffers[_tc.current=_tc.next]; + return task_woken; +} + +static portBASE_TYPE tc_recv_irq(u_int32_t pio, portBASE_TYPE task_woken) +{ + (void)pio; + /* TODO There should be some emergency exit here to prevent the CPU from + * spinning in the IRQ for excessive amounts of time. (Maximum transmission + * time for 256 Byte frame is something like 21ms.) + */ + while(*AT91C_TC2_CV <= REAL_FRAME_END || + fiq_buffers[NEXT_BUFFER(_tc.current)].count > 0 || + fiq_buffers[_tc.current].count > 0) + task_woken = switch_buffers(task_woken); + + if(*AT91C_TC2_CV > REAL_FRAME_END) { + iso14443_frame *rx_frame = get_frame_buffer(&_tc); + if(rx_frame == NULL) return task_woken; + int ret = iso14443a_diffmiller_assert_frame_ended(_tc.decoder, rx_frame); + if(ret == 0) { + task_woken = handle_frame(rx_frame, task_woken); + } + } + return task_woken; +} + + +int tc_recv_init(tc_recv_handle_t *_th, int pauses_count, tc_recv_callback_t callback) +{ + if(_tc.initialized) return -EBUSY; + tc_recv_handle_t th = &_tc; + + memset(fiq_buffers, 0, sizeof(fiq_buffers)); + th->current = th->next = 0; + + memset(rx_frames, 0, sizeof(rx_frames)); + th->current_frame = NULL; + + if(th->rx_queue == NULL) { + th->rx_queue = xQueueCreate(TC_RECV_NUMBER_OF_FRAME_BUFFERS, sizeof(iso14443_frame*)); + if(th->rx_queue == NULL) + return -ENOMEM; + } + + th->pauses_count = pauses_count; + th->decoder = iso14443a_init_diffmiller(th->pauses_count); + if(!th->decoder) return -EBUSY; + + // The change interrupt is going to be handled by the FIQ and our secondary IRQ handler + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_DATA); + if( pio_irq_register(OPENPICC_SSC_DATA, &tc_recv_irq) < 0) + return -EBUSY; + pio_irq_enable(OPENPICC_SSC_DATA); + + th->initialized = 1; + *_th = th; + + th->callback = callback; + if(th->callback) th->callback(TC_RECV_CALLBACK_SETUP, th); + + return 0; +} + +int tc_recv_receive(tc_recv_handle_t th, iso14443_frame* *frame, unsigned int timeout) +{ + if(th == NULL) return -EINVAL; + if(!th->initialized) return -EINVAL; + + if(xQueueReceive(th->rx_queue, frame, timeout)){ + if(*frame != NULL) return 0; + else return -EINTR; + } + + return -ETIMEDOUT; +} diff --git a/openpicc/application/tc_recv.h b/openpicc/application/tc_recv.h new file mode 100644 index 0000000..4f2392b --- /dev/null +++ b/openpicc/application/tc_recv.h @@ -0,0 +1,21 @@ +#ifndef TC_RECV_H_ +#define TC_RECV_H_ + +#include "iso14443.h" + +#define TC_RECV_NUMBER_OF_FRAME_BUFFERS 10 + +struct tc_recv_handle; +typedef struct tc_recv_handle *tc_recv_handle_t; + +typedef enum { + TC_RECV_CALLBACK_RX_FRAME_ENDED, // *data is iso14443_frame *frame + TC_RECV_CALLBACK_SETUP, // *data is tc_recv_handle_t th + TC_RECV_CALLBACK_TEARDOWN, // *data is tc_recv_handle_t th +} tc_recv_callback_reason; +typedef void (*tc_recv_callback_t)(tc_recv_callback_reason reason, void *data); + +extern int tc_recv_init(tc_recv_handle_t *th, int pauses_count, tc_recv_callback_t callback); +extern int tc_recv_receive(tc_recv_handle_t th, iso14443_frame* *frame, unsigned int timeout); + +#endif /*TC_RECV_H_*/ diff --git a/openpicc/application/tc_sniffer.c b/openpicc/application/tc_sniffer.c index 943a2ad..592b5a4 100644 --- a/openpicc/application/tc_sniffer.c +++ b/openpicc/application/tc_sniffer.c @@ -56,15 +56,7 @@ static xSemaphoreHandle data_semaphore; struct diffmiller_state *decoder; iso14443_frame rx_frame; -#define BUFSIZE 1024 #define WAIT_TICKS (20*portTICK_RATE_MS) -typedef struct { - u_int32_t count; - u_int32_t data[BUFSIZE]; -} fiq_buffer_t; -fiq_buffer_t fiq_buffers[2]; - -fiq_buffer_t *tc_sniffer_next_buffer_for_fiq = 0; portBASE_TYPE currently_sniffing = 0; enum { NONE, REQUEST_START, REQUEST_STOP } request_change = REQUEST_START; -- cgit v1.2.3