diff options
Diffstat (limited to 'openpicc/application/iso14443_layer2a.c')
-rw-r--r-- | openpicc/application/iso14443_layer2a.c | 92 |
1 files changed, 84 insertions, 8 deletions
diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c index 57754f8..d5e89cf 100644 --- a/openpicc/application/iso14443_layer2a.c +++ b/openpicc/application/iso14443_layer2a.c @@ -39,6 +39,7 @@ #include "openpicc.h" #include "iso14443_layer2a.h" #include "ssc.h" +#include "ssc_buffer.h" #include "pll.h" #include "tc_fdt.h" #include "tc_cdiv.h" @@ -51,6 +52,9 @@ #define PRINT_DEBUG 0 static u_int8_t fast_receive; +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; #ifdef FOUR_TIMES_OVERSAMPLING @@ -59,16 +63,23 @@ 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, ssc_dma_rx_buffer_t **buffer, unsigned int timeout) { - (void)callback; (void)timeout; ssc_dma_rx_buffer_t* _buffer = NULL; int len; + if(rx_pending) { + return -EALREADY; + } + rx_pending=1; + callback=_callback; + if(ssc_recv(ssc, &_buffer, timeout) == 0) { if(_buffer == NULL) { /* Can this happen? */ + rx_pending=0; + callback=NULL; return -ETIMEDOUT; } @@ -78,6 +89,10 @@ int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t * len = _buffer->len_transfers; + if(callback != NULL && !fast_receive) { + callback(_buffer, 0); + } + if(buffer != NULL) *buffer = _buffer; else { portENTER_CRITICAL(); @@ -85,13 +100,59 @@ int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t * portEXIT_CRITICAL(); } + rx_pending=0; + callback=NULL; return len; } - if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_PIO_FRAME)) tc_cdiv_sync_reset(); + /* Note: There is the remote chance of a race condition probability here if + * a frame start was received right before the timeout for this function + * expired. In the future one might want to replace this with some safer code + * (hmm, maybe check TC2_CV?) but for now it's an essential safeguard to prevent + * a hung receiver when no proper frame end is signalled to iso14443_ssc_callback + * and therefore the callback never resets the flipflop */ + if(!tx_pending) { + if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_PIO_FRAME)) tc_cdiv_sync_reset(); + } + + rx_pending=0; + callback=NULL; return -ETIMEDOUT; } +int iso14443_transmit(ssc_dma_tx_buffer_t *buffer, unsigned int fdt, u_int8_t async, unsigned int timeout) +{ + if(tx_pending) + return -EBUSY; + + tx_pending = 1; + + /* Immediately set up FDT and clock */ + ssc_select_clock(CLOCK_SELECT_CARRIER); + ssc_set_gate(0); + tc_fdt_set(fdt); + tc_cdiv_set_divider(8); // FIXME Magic hardcoded number + + if(!async) { + /* FIXME Implement */ + (void)timeout; + tx_pending = 0; + return -EINVAL; + } + + int ret = ssc_send(ssc, buffer); + if(ret < 0) { + tx_pending = 0; + return ret; + } + + if(!async) { + /* FIXME Wait for completion, timeout or abort */ + } + + return 0; +} + int iso14443_wait_for_carrier(unsigned int timeout) { (void)timeout; @@ -112,7 +173,6 @@ u_int8_t iso14443_get_fast_receive(void) static void iso14443_ssc_callback(ssc_callback_reason reason, void *data) { - (void) data; if(reason == CALLBACK_RX_FRAME_BEGIN) { /* Busy loop for the frame end */ int *end_asserted = data, i=0; @@ -124,11 +184,28 @@ static void iso14443_ssc_callback(ssc_callback_reason reason, void *data) } return; } - if( reason == CALLBACK_RX_FRAME_ENDED || reason == CALLBACK_RX_STARTED ) { + + if(reason == CALLBACK_TX_FRAME_ENDED) { + tx_pending = 0; + } + + if( reason == CALLBACK_RX_FRAME_ENDED && fast_receive ) { + ssc_select_clock(CLOCK_SELECT_CARRIER); /* A Tx might be coming up */ + + ssc_dma_rx_buffer_t *buffer = data; + if(callback != NULL) + callback(buffer, 1); + } + + if( (reason == CALLBACK_RX_FRAME_ENDED && !tx_pending) || reason == CALLBACK_RX_STARTING + || reason == CALLBACK_TX_FRAME_ENDED ) { + ssc_select_clock(CLOCK_SELECT_PLL); + ssc_set_gate(1); tc_fdt_set(0xff00); tc_cdiv_set_divider(RX_DIVIDER); tc_cdiv_sync_reset(); } + } static void iso14443_rx_FRAME_cb(u_int32_t pio) @@ -155,12 +232,11 @@ int iso14443_layer2a_init(u_int8_t enable_fast_receive) if(PRINT_DEBUG) usb_print_string("FRAME irq registered\n\r"); // DEBUG OUTPUT } - ssc = ssc_open(1, 0, SSC_MODE_14443A, iso14443_ssc_callback); + ssc = ssc_open(1, 1, SSC_MODE_14443A, iso14443_ssc_callback); if(ssc == NULL) return -EIO; - // FIXME should be 3 for production, when tx code is implemented - load_mod_level(0); + load_mod_level(3); return 0; } |