diff options
Diffstat (limited to 'openpicc/application')
| -rw-r--r-- | openpicc/application/cmd.c | 98 | ||||
| -rw-r--r-- | openpicc/application/iso14443_layer2a.c | 96 | ||||
| -rw-r--r-- | openpicc/application/iso14443_layer2a.h | 5 | ||||
| -rw-r--r-- | openpicc/application/iso14443_layer3a.h | 88 | ||||
| -rw-r--r-- | openpicc/application/iso14443_sniffer.c | 10 | ||||
| -rw-r--r-- | openpicc/application/iso14443a_miller.c | 2 | ||||
| -rw-r--r-- | openpicc/application/main.c | 153 | ||||
| -rw-r--r-- | openpicc/application/openpicc.h | 1 | ||||
| -rw-r--r-- | openpicc/application/ssc.c | 599 | ||||
| -rw-r--r-- | openpicc/application/ssc.h | 53 | ||||
| -rw-r--r-- | openpicc/application/ssc_buffer.h | 46 | ||||
| -rw-r--r-- | openpicc/application/ssc_picc.c | 731 | ||||
| -rw-r--r-- | openpicc/application/ssc_picc.h | 105 | ||||
| -rw-r--r-- | openpicc/application/tc_fdt.c | 39 | ||||
| -rw-r--r-- | openpicc/application/usb_print.c | 2 | 
15 files changed, 933 insertions, 1095 deletions
| diff --git a/openpicc/application/cmd.c b/openpicc/application/cmd.c index a96a68d..3b777b3 100644 --- a/openpicc/application/cmd.c +++ b/openpicc/application/cmd.c @@ -18,7 +18,7 @@  #include "tc_cdiv.h"  #include "tc_cdiv_sync.h"  #include "pio_irq.h" -#include "ssc_picc.h" +#include "ssc.h"  #include "usb_print.h"  #include "load_modulation.h" @@ -45,7 +45,7 @@ static const portBASE_TYPE USE_COLON_FOR_LONG_COMMANDS = 0;  /* When not USE_COLON_FOR_LONG_COMMANDS then short commands will be recognized by including   * their character in the string SHORT_COMMANDS   * */ -static const char *SHORT_COMMANDS = "!pc+-l?hq9fjkai"; +static const char *SHORT_COMMANDS = "!pc+-l?hq9fjka#i";  /* Note that the long/short command distinction only applies to the USB serial console   * */ @@ -132,16 +132,10 @@ int atoiEx(const char * nptr, char * * eptr)  	return sign * curval;  } -static const struct {ssc_metric metric; char *description;} SSC_METRICS[] = { -	{OVERFLOWS,     "overflows"}, -	{BUFFER_ERRORS, "internal buffer management errors"}, -	{FREE_BUFFERS,  "free rx buffers"}, -	{LATE_FRAMES,   "late frames"}, -}; -#define DYNAMIC_PIN_PLL_LOCK -1 -static struct { int pin; char * description; } PIO_PINS[] = { -	{DYNAMIC_PIN_PLL_LOCK,  "pll lock   "}, -	{OPENPICC_PIO_FRAME,    "frame start"}, +#define DYNAMIC_PIN_PLL_LOCK 1 +static struct { int pin; int dynpin; char * description; } PIO_PINS[] = { +	{0,DYNAMIC_PIN_PLL_LOCK,      "pll lock   "}, +	{OPENPICC_PIO_FRAME,0,        "frame start"},  };  void print_pio(void)  { @@ -153,7 +147,7 @@ void print_pio(void)          	" *****************************************************\n\r"          	" *\n\r");  	for(i=0; i<sizeof(PIO_PINS)/sizeof(PIO_PINS[0]); i++) { -			if(PIO_PINS[i].pin < 0) continue; +			if(PIO_PINS[i].dynpin != 0) continue;          	DumpStringToUSB(" * ");          	DumpStringToUSB(PIO_PINS[i].description);          	DumpStringToUSB(": "); @@ -167,6 +161,7 @@ void print_pio(void)  static const AT91PS_SPI spi = AT91C_BASE_SPI;  #define SPI_MAX_XFER_LEN 33 +static int clock_select=0;  void startstop_field_meter(void);  extern volatile unsigned portLONG ulCriticalNesting;  void prvExecCommand(u_int32_t cmd, portCHAR *args) { @@ -205,6 +200,14 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    DumpUIntToUSB(j);  		    DumpStringToUSB("\n\r");  		    break; +		case 'THRU': { +				/*char buffer[64]; +				memset(buffer, 'A', sizeof(buffer)); +				usb_print_flush(); +				while(1) usb_print_buffer(buffer, 0, sizeof(buffer));*/ +				while(1) vUSBSendBuffer((unsigned char*)"AAAAAABCDEBBBBB", 0, 15); +			} +			break;  		case 'Z':  		    i=atoiEx(args, &args);  		    if(i==0) { @@ -221,7 +224,8 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  				break;  			}  		    i=atoiEx(args, &args); -		    ssc_set_data_gate(i); +		    //BROKEN new ssc code +		    //ssc_set_data_gate(i);  		    if(i==0) {  		    	DumpStringToUSB("SSC_DATA disabled \n\r");  		    } else { @@ -252,15 +256,6 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    ms=xTaskGetTickCount();  		    DumpTimeToUSB(ms);  		    DumpStringToUSB("\n\r"); -		    DumpStringToUSB(" * The reader id is "); -		    DumpUIntToUSB(env.e.reader_id); -		    DumpStringToUSB("\n\r"); -		    DumpStringToUSB(" * The mode is "); -		    DumpUIntToUSB(env.e.mode); -		    DumpStringToUSB("\n\r"); -		    DumpStringToUSB(" * The transmit interval is "); -		    DumpUIntToUSB(env.e.speed); -		    DumpStringToUSB("00ms\n\r");  		    DumpStringToUSB(" * The comparator threshold is ");  		    DumpUIntToUSB(da_get_value());  		    DumpStringToUSB("\n\r"); @@ -281,12 +276,16 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    DumpUIntToUSB(load_mod_level_set);  		    DumpStringToUSB("\n\r");  		    DumpStringToUSB(" * SSC performance metrics:\n\r"); -		    for(i=0; i<(int)(sizeof(SSC_METRICS)/sizeof(SSC_METRICS[0])); i++) { -		    	DumpStringToUSB(" * \t"); -		    	DumpStringToUSB(SSC_METRICS[i].description); -		    	DumpStringToUSB(": "); -		    	DumpUIntToUSB(ssc_get_metric(SSC_METRICS[i].metric)); -		    	DumpStringToUSB("\n\r"); +		    for(i=0; i<_MAX_METRICS; i++) { +		    	char *name;  +		    	int value; +		    	if(ssc_get_metric(i, &name, &value)) { +		    		DumpStringToUSB(" * \t"); +		    		DumpStringToUSB(name); +		    		DumpStringToUSB(": "); +		    		DumpUIntToUSB(value); +		    		DumpStringToUSB("\n\r"); +		    	}  		    }  		    DumpStringToUSB(" * SSC status: ");  		    DumpUIntToUSB(AT91C_BASE_SSC->SSC_SR); @@ -294,6 +293,21 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    DumpStringToUSB(" * TC0_CV value: ");  		    DumpUIntToUSB(*AT91C_TC0_CV);  		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * TC2_CV value: "); +		    DumpUIntToUSB(*AT91C_TC2_CV); +		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * TC2_IMR value: "); +		    DumpUIntToUSB(*AT91C_TC2_IMR); +		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * TC2_SR value: "); +		    DumpUIntToUSB(*AT91C_TC2_SR); +		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * TC2_RB value: "); +		    DumpUIntToUSB(*AT91C_TC2_RB); +		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * TC2_RC value: "); +		    DumpUIntToUSB(*AT91C_TC2_RC); +		    DumpStringToUSB("\n\r");  		    DumpStringToUSB(" * SSC_SR value: ");  		    DumpUIntToUSB(*AT91C_SSC_SR);  		    DumpStringToUSB("\n\r"); @@ -312,6 +326,12 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    DumpStringToUSB(" * SSC_TCR value: ");  		    DumpUIntToUSB(*AT91C_SSC_TCR);  		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * SSC_RPR value: "); +		    DumpUIntToUSB(*AT91C_SSC_RPR); +		    DumpStringToUSB("\n\r"); +		    DumpStringToUSB(" * SSC_RCR value: "); +		    DumpUIntToUSB(*AT91C_SSC_RCR); +		    DumpStringToUSB("\n\r");  		    DumpStringToUSB(" * SSC_IMR value: ");  		    DumpUIntToUSB(*AT91C_SSC_IMR);  		    DumpStringToUSB("\n\r"); @@ -346,6 +366,17 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		case '!':  		    tc_cdiv_sync_reset();  		    break; +		case '#': +			if(!OPENPICC->features.clock_switching) { +				DumpStringToUSB("* This hardware is not clock switching capable\n\r"); +				break; +			} +			clock_select = (clock_select+1) % _MAX_CLOCK_SOURCES; +			ssc_select_clock(clock_select); +			DumpStringToUSB("Active clock is now "); +			DumpUIntToUSB(clock_select); +			DumpStringToUSB("\n\r"); +			break;  		case 'J':  		    fdt_offset++;  		    DumpStringToUSB("fdt_offset is now "); @@ -375,7 +406,8 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    break;  #endif  		case 'Q': -		    ssc_rx_start(); +		    //BROKEN new ssc code +			//ssc_rx_start();  		    while(0) {  		    	DumpUIntToUSB(AT91C_BASE_SSC->SSC_SR);  		    	DumpStringToUSB("\n\r"); @@ -402,11 +434,13 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {  		    DumpStringToUSB(OPENPICC->release_name);  		    DumpStringToUSB("\n\r *\n\r"  			" * test - test critical sections\n\r" +		    " * thru - test throughput\n\r"  #if ( configUSE_TRACE_FACILITY == 1 )  			" * t    - print task list and stack usage\n\r"  #endif  			" * c    - print configuration\n\r"  			" * +,-  - decrease/increase comparator threshold\n\r" +		    " * #    - switch clock\n\r"  			" * l    - cycle LEDs\n\r"  			" * p    - print PIO pins\n\r"  			" * z 0/1- enable or disable tc_cdiv_sync\n\r" @@ -551,8 +585,9 @@ void startstop_field_meter(void) {  portBASE_TYPE vCmdInit() {  	unsigned int i;  	for(i=0; i<sizeof(PIO_PINS)/sizeof(PIO_PINS[0]); i++) { -		if(PIO_PINS[i].pin == DYNAMIC_PIN_PLL_LOCK) { +		if(PIO_PINS[i].dynpin == DYNAMIC_PIN_PLL_LOCK) {  			PIO_PINS[i].pin = OPENPICC->PLL_LOCK; +			PIO_PINS[i].dynpin = 0;  		}  	} @@ -567,7 +602,6 @@ portBASE_TYPE vCmdInit() {  	}  	xSemaphoreTake(xFieldMeterMutex, portMAX_DELAY); -	  	if(xTaskCreate(vCmdCode, (signed portCHAR *)"CMD", TASK_CMD_STACK, NULL,   		TASK_CMD_PRIORITY, &xCmdTask) != pdPASS) {  		return 0; diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c index b91b67c..57754f8 100644 --- a/openpicc/application/iso14443_layer2a.c +++ b/openpicc/application/iso14443_layer2a.c @@ -38,15 +38,20 @@  #include "openpicc.h"  #include "iso14443_layer2a.h" -#include "ssc_picc.h" +#include "ssc.h"  #include "pll.h"  #include "tc_fdt.h"  #include "tc_cdiv.h"  #include "tc_cdiv_sync.h"  #include "load_modulation.h" +#include "pio_irq.h" + +#include "usb_print.h" + +#define PRINT_DEBUG 0  static u_int8_t fast_receive; -static volatile u_int8_t receiving = 0; +static ssc_handle_t *ssc;  #ifdef FOUR_TIMES_OVERSAMPLING  #define RX_DIVIDER 32 @@ -56,28 +61,11 @@ static volatile u_int8_t receiving = 0;  int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t **buffer, unsigned int timeout)  { -	int was_receiving = receiving; -	(void)callback; +	(void)callback; (void)timeout;  	ssc_dma_rx_buffer_t* _buffer = NULL;  	int len; -	 -	if(!was_receiving) { -		iso14443_l2a_rx_start(); -	} else { -		/* -		 * handled by _iso14443_ssc_irq_ext below -		tc_fdt_set(0xff00); -		tc_cdiv_set_divider(RX_DIVIDER); -		tc_cdiv_sync_reset(); -		*/ -	} -	 -	 -	if(xQueueReceive(ssc_rx_queue, &_buffer, timeout)) { -		if(!was_receiving) { -			iso14443_l2a_rx_stop(); -		} +	if(ssc_recv(ssc, &_buffer, timeout) == 0) {  		if(_buffer == NULL) {  			/* Can this happen? */ @@ -100,9 +88,7 @@ int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t *  		return len;  	} -	if(!was_receiving) -		iso14443_l2a_rx_stop(); -	 +	if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_PIO_FRAME)) tc_cdiv_sync_reset();  	return -ETIMEDOUT;  } @@ -112,23 +98,6 @@ int iso14443_wait_for_carrier(unsigned int timeout)  	return 0;  } -int iso14443_l2a_rx_start(void) -{ -	receiving = 1; -	tc_fdt_set(0xff00); -	tc_cdiv_set_divider(RX_DIVIDER); -	ssc_rx_start(); -	return 0; -} - -int iso14443_l2a_rx_stop(void) -{ -	ssc_rx_stop(); -	receiving = 0; -	return 0; -} - -  u_int8_t iso14443_set_fast_receive(u_int8_t enable_fast_receive)  {  	u_int8_t old_value = fast_receive; @@ -141,32 +110,57 @@ u_int8_t iso14443_get_fast_receive(void)  	return fast_receive;  } -void _iso14443_ssc_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode, u_int8_t* samples) +static void iso14443_ssc_callback(ssc_callback_reason reason, void *data)  { -	(void) ssc_mode; (void) samples; -	if( (ssc_sr & AT91C_SSC_CP1) && receiving) { +	(void) data; +	if(reason == CALLBACK_RX_FRAME_BEGIN) { +		/* Busy loop for the frame end */ +		int *end_asserted = data, i=0; +		for(i=0; i<96000; i++)  +			if(*AT91C_TC2_CV > 2*128) { // FIXME magic number +				*end_asserted = 1; +				if(PRINT_DEBUG) usb_print_string_f("^", 0); // DEBUG OUTPUT +				break; +			} +		return; +	} +	if( reason == CALLBACK_RX_FRAME_ENDED || reason == CALLBACK_RX_STARTED ) {  		tc_fdt_set(0xff00);  		tc_cdiv_set_divider(RX_DIVIDER);  		tc_cdiv_sync_reset();  	}  } +static void iso14443_rx_FRAME_cb(u_int32_t pio) +{ +	(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(); +} +  int iso14443_layer2a_init(u_int8_t enable_fast_receive)  {  	pll_init();  	tc_cdiv_init();  	tc_fdt_init(); -	//ssc_set_irq_extension((ssc_irq_ext_t)iso14443_layer3a_irq_ext); -	ssc_rx_init(); -	ssc_tx_init();  	load_mod_init(); -	load_mod_level(3); -	 -	ssc_rx_mode_set(SSC_MODE_14443A); -	ssc_set_irq_extension(_iso14443_ssc_irq_ext);  	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, 0, 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); +	  	return 0;  } diff --git a/openpicc/application/iso14443_layer2a.h b/openpicc/application/iso14443_layer2a.h index abe019a..cf31ec4 100644 --- a/openpicc/application/iso14443_layer2a.h +++ b/openpicc/application/iso14443_layer2a.h @@ -1,7 +1,7 @@  #ifndef ISO14443_LAYER2A_H_  #define ISO14443_LAYER2A_H_ -#include "ssc_picc.h" +#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 @@ -55,9 +55,6 @@ extern int iso14443_transmit(ssc_dma_tx_buffer_t *buffer, unsigned int fdt, u_in  extern int iso14443_tx_abort(void);  extern int iso14443_tx_busy(void); -extern int iso14443_l2a_rx_start(void); -extern int iso14443_l2a_rx_stop(void); -  /*   * Wait for the presence of a reader to be detected.   * Returns 0 when the PLL is locked. diff --git a/openpicc/application/iso14443_layer3a.h b/openpicc/application/iso14443_layer3a.h index 1eb94b4..ff4b1c0 100644 --- a/openpicc/application/iso14443_layer3a.h +++ b/openpicc/application/iso14443_layer3a.h @@ -15,76 +15,11 @@ enum ISO14443_STATES {  	ERROR,       /* Some unrecoverable error has occured */  }; -/******************** RX ************************************/ -#ifdef FOUR_TIMES_OVERSAMPLING -/* definitions for four-times oversampling */ -#define ISO14443A_SAMPLE_LEN    4 -/* Sample values for the REQA and WUPA short frames */ -#define REQA	0x10410441 -#define WUPA	0x04041041 - -/* Start of frame sample for SSC compare 0 */ -#define ISO14443A_SOF_SAMPLE	0x01 -#define ISO14443A_SOF_LEN	4 -/* Length in samples of a short frame */ -#define ISO14443A_SHORT_LEN     32 -/* This is wrong: a short frame is 1 start bit, 7 data bits, 1 stop bit  - * followed by no modulation for one bit period. The start bit is 'eaten' in  - * SSC Compare 0, but the remaining 7+1+1 bit durations must be sampled and - * compared. At four times oversampling this would be 9*4=36 samples, which is  - * more than one SSC transfer. You'd have to use two transfers of 18 samples - * each and modify the comparison code accordingly.  - * Since four times oversampling doesn't work reliably anyway (every second - * sample is near an edge and might sample 0 or 1) this doesn't matter for now.*/ -#error Four times oversampling is broken, see comments in code  - -#else -/* definitions for two-times oversampling */ -#define ISO14443A_SAMPLE_LEN    2 - -/* For SSC_MODE_ISO14443A_SHORT */ -#define ISO14443A_SHORT_LEN     18 -#define REQA	0x4929 -#define WUPA	0x2249 - -#define ISO14443A_SOF_SAMPLE	0x01 -#define ISO14443A_SOF_LEN	2 - -#define ISO14443A_EOF_SAMPLE    0x00 -#define ISO14443A_EOF_LEN       5 - -/* For SSC_MODE_ISO14443A */ -#define ISO14443A_SHORT_FRAME_COMPARE_LENGTH 2 -#define _ISO14443A_SHORT_FRAME_REQA { 0x29, 0x49 } -#define _ISO14443A_SHORT_FRAME_WUPA { 0x49, 0x22 } -// FIXME not correct. This should be compare_length == 3 (which is 9 at 4 per compare), but this -// needs enhanced ssc irq code to transfer the last read (incomplete) data from the ssc holding  -// register to the buffer  - -#endif +#include "iso14443.h"  extern const u_int8_t ISO14443A_SHORT_FRAME_REQA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH];  extern const u_int8_t ISO14443A_SHORT_FRAME_WUPA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH]; -/* A short frame should be received in one single SSC transfer */ -#if (ISO14443A_SHORT_LEN <= 8) -/* SSC transfer size in bits */ -#define ISO14443A_SHORT_TRANSFER_SIZE 8 -#define ISO14443A_SHORT_TYPE u_int8_t - -#elif (ISO14443A_SHORT_LEN <= 16) -#define ISO14443A_SHORT_TRANSFER_SIZE 16 -#define ISO14443A_SHORT_TYPE u_int16_t - -#elif (ISO14443A_SHORT_LEN <= 32) -#define ISO14443A_SHORT_TRANSFER_SIZE 32 -#define ISO14443A_SHORT_TYPE u_int32_t - -#else -#error ISO14443A_SHORT_LEN defined too big -#endif - -#define ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS (256*9 +2)  /******************** TX ************************************/  /* Magic delay, don't know where it comes from */  //#define MAGIC_OFFSET -32 @@ -102,27 +37,6 @@ extern volatile int fdt_offset;  #define ISO14443A_FDT_SHORT_1	(ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_1 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY)  #define ISO14443A_FDT_SHORT_0	(ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_0 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY) -/* in bytes, not counting parity */ -#define MAXIMUM_FRAME_SIZE 256 - -typedef struct { -  enum { TYPE_A, TYPE_B } type; -  union { -  	struct { -  		enum { SHORT_FRAME, STANDARD_FRAME, AC_FRAME } format; -  		enum { PARITY, /* Calculate parity on the fly, ignore the parity field below */  -  		       GIVEN_PARITY, /* Use the parity bits from the parity field below */   -  		       NO_PARITY, /* Don't send any parity */ -  		} parity; -  		enum { ISO14443A_LAST_BIT_0 = 0, ISO14443A_LAST_BIT_1 = 1, ISO14443A_LAST_BIT_NONE } last_bit; -  	} a; -  } parameters; -  u_int32_t numbytes; -  u_int8_t numbits, bit_offset; -  u_int8_t data[MAXIMUM_FRAME_SIZE]; -  u_int8_t parity[MAXIMUM_FRAME_SIZE/8+1]; /* parity bit for data[x] is in parity[x/8] & (1<<(x%8)) */ -} iso14443_frame; -  extern const iso14443_frame ATQA_FRAME;  #endif /*ISO14443_LAYER3A_H_*/ diff --git a/openpicc/application/iso14443_sniffer.c b/openpicc/application/iso14443_sniffer.c index d5cf9c2..bc326b4 100644 --- a/openpicc/application/iso14443_sniffer.c +++ b/openpicc/application/iso14443_sniffer.c @@ -28,17 +28,21 @@  #include <errno.h>  #include "openpicc.h" +#include "ssc_buffer.h" +#include "iso14443.h"  #include "iso14443_sniffer.h"  #include "iso14443_layer2a.h"  #include "iso14443a_miller.h"  #include "usb_print.h"  #include "cmd.h" +#include "led.h"  static iso14443_frame rx_frame;  void iso14443_sniffer (void *pvParameters)  {  	(void)pvParameters; +	(void)rx_frame;  	int res;  	/* Delay until USB print etc. are ready */ @@ -57,11 +61,11 @@ void iso14443_sniffer (void *pvParameters)  	}  	usb_print_string("Carrier detected.\n\r"); -	iso14443_l2a_rx_start();  	while(true) {  		ssc_dma_rx_buffer_t *buffer = 0;  		res = iso14443_receive(NULL, &buffer, 20000 * portTICK_RATE_MS);  		if(res >= 0) { +#if 1  			DumpStringToUSB("\n\r");  			DumpTimeToUSB(xTaskGetTickCount());  			usb_print_string(": Frame received, consists of "); @@ -86,6 +90,10 @@ void iso14443_sniffer (void *pvParameters)  			usb_print_string(" bits:  ");  			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; diff --git a/openpicc/application/iso14443a_miller.c b/openpicc/application/iso14443a_miller.c index 27a0977..c902bb7 100644 --- a/openpicc/application/iso14443a_miller.c +++ b/openpicc/application/iso14443a_miller.c @@ -24,7 +24,7 @@  #include "iso14443_layer3a.h"  #include "usb_print.h" -#include "ssc_picc.h" +#include "ssc_buffer.h"  #include "cmd.h"  #if 0 diff --git a/openpicc/application/main.c b/openpicc/application/main.c index e1749de..d9b35f1 100644 --- a/openpicc/application/main.c +++ b/openpicc/application/main.c @@ -30,6 +30,7 @@  #include <FreeRTOS.h>  #include <AT91SAM7.h> +#include <lib_AT91SAM7.h>  #include <USB-CDC.h>  #include <task.h> @@ -50,14 +51,89 @@  #include "iso14443_sniffer.h"  #include "decoder.h" +static inline int detect_board(void) +{ +	/* OpenPICC board detection logic. +	 * Interesting board differences: PA31 is open on OPENPICC_v0_4 and connected +	 * to PA18 on OPENPICC_v0_4_p1. PA18 is connected to U7 on both and might read +	 * differently depending on the state of U7 (primarily depending on U5 and the +	 * receive circuitry). +	 * Strategy: Enable Pullups, read PA31 and PA18, if both read low then U7 is +	 * switched through and this is an v0.4p1. If PA18 reads low and PA31 reads high +	 * then U7 is switched through and this is an v0.4. If both read high, then U7 is +	 * not switched through and it might be either board. In this case drive PA31 down +	 * and see whether PA18 follows down, then it's a v0.4p1 otherwise a v0.4. +	 */ +	int result = -1; +	 +	AT91PS_PIO pio = AT91C_BASE_PIOA; +	u_int32_t old_OSR = pio->PIO_OSR,  +		old_ODSR = pio->PIO_ODSR, +		old_PUSR = pio->PIO_PPUSR, +		old_PSR = pio->PIO_PSR; +	 +	pio->PIO_ODR   = AT91C_PIO_PA18 | AT91C_PIO_PA31; +	pio->PIO_PER   = AT91C_PIO_PA18 | AT91C_PIO_PA31; +	pio->PIO_PPUER = AT91C_PIO_PA18 | AT91C_PIO_PA31; +	 +	unsigned int pa18 = AT91F_PIO_IsInputSet(pio, AT91C_PIO_PA18), +		pa31 = AT91F_PIO_IsInputSet(pio, AT91C_PIO_PA31); +	if(!pa18 && !pa31) { +	    //vLedInit(); +		//vLedHaltBlinking(1); +		result = OPENPICC_v0_4_p2; +	} else if(!pa18 && pa31) { +	    vLedInit(); +		vLedHaltBlinking(2); +		// Needs to be tested, should be v0.4 +	} else if(pa18 && pa31) { +		// Can be either board +		pio->PIO_OER = AT91C_PIO_PA31; +		pio->PIO_CODR = AT91C_PIO_PA31; +		pa18 = AT91F_PIO_IsInputSet(pio, AT91C_PIO_PA18); +		if(!pa18) { +			result = OPENPICC_v0_4_p2; +		} else { +		    vLedInit(); +			vLedHaltBlinking(3); +			// Needs to be tested, should be v0.4 +		} +		 +		// Restore state +		if( old_OSR & AT91C_PIO_PA31 ) { +			pio->PIO_OER = AT91C_PIO_PA31; +			if(old_ODSR & AT91C_PIO_PA31) { +				pio->PIO_SODR = AT91C_PIO_PA31; +			} else { +				pio->PIO_CODR = AT91C_PIO_PA31; +			} +		} else { +			pio->PIO_ODR = AT91C_PIO_PA31; +		} +	} +	 +	// Restore state +	if(old_PSR & AT91C_PIO_PA18) pio->PIO_PER = AT91C_PIO_PA18; else pio->PIO_PDR = AT91C_PIO_PA18; +	if(old_PSR & AT91C_PIO_PA31) pio->PIO_PER = AT91C_PIO_PA31; else pio->PIO_PDR = AT91C_PIO_PA31; +	 +	if(old_PUSR & AT91C_PIO_PA18) pio->PIO_PPUDR = AT91C_PIO_PA18; else pio->PIO_PPUER = AT91C_PIO_PA18; +	if(old_PUSR & AT91C_PIO_PA31) pio->PIO_PPUDR = AT91C_PIO_PA31; else pio->PIO_PPUER = AT91C_PIO_PA31; +	 +	return result; +} +  /**********************************************************************/  static inline void prvSetupHardware (void)  {  	/* The very, very first thing we do is setup the global OPENPICC variable to point to  	 * the correct hardware information. -	 * FIXME: Detect dynamically in the future  	 */ -	OPENPICC = &OPENPICC_HARDWARE[OPENPICC_v0_4_p1]; +	int release = detect_board(); +	if(release < 0) { +		vLedInit(); +		vLedHaltBlinking(0); +	} +	OPENPICC = &OPENPICC_HARDWARE[release];      /*	When using the JTAG debugger the hardware is not always initialised to @@ -89,68 +165,8 @@ void vApplicationIdleHook(void)      	//vLedSetGreen(0);      	disabled_green = 1;      } -    usb_print_flush();  } -#if 0 -// Bitrotten -void main_help_print_buffer(ssc_dma_rx_buffer_t *buffer, int *pktcount) -{ -	ISO14443A_SHORT_TYPE *tmp = (ISO14443A_SHORT_TYPE*)buffer->data; -	int i, dumped = 0; -	unsigned int j; -	for(i = buffer->len / (sizeof(*tmp)*8); i >= 0 ; i--) { -		if( *tmp != 0x00000000 ) { -			if(dumped == 0) { -				DumpUIntToUSB(buffer->len); -				DumpStringToUSB(", "); -				DumpUIntToUSB((*pktcount)++); -				DumpStringToUSB(": "); -			} else { -				DumpStringToUSB(" "); -			} -			dumped = 1; -			DumpUIntToUSB(buffer->len / (sizeof(*tmp)*8) - i); -			DumpStringToUSB(": "); -			for(j=0; j<sizeof(*tmp)*8; j++) { -				usb_print_char_f( (((*tmp) >> j) & 0x1) ? '1' : '_' , 0); -			} -			usb_print_flush(); -			//DumpBufferToUSB((char*)(tmp), sizeof(*tmp)); -		} -		tmp++; -	} -	if(dumped) DumpStringToUSB("\n\r"); -} - -void vMainTestSSCRXConsumer (void *pvParameters) -{ -	static int pktcount=0; -	(void)pvParameters; -	while(1) { -		ssc_dma_rx_buffer_t* buffer; -		if(xQueueReceive(ssc_rx_queue, &buffer, portMAX_DELAY)) { -			portENTER_CRITICAL(); -			buffer->state = PROCESSING; -			portEXIT_CRITICAL(); -			/*vLedBlinkGreen(); -			for(i=0; i<buffer->len*8; i++) { -				vLedSetGreen( buffer->data[i/8] & (1<<(i%8)) ); -			} -			vLedBlinkGreen();*/ -			//i = usb_print_set_default_flush(0); -			 -			main_help_print_buffer(buffer, &pktcount); -			 -			//usb_print_set_default_flush(i); -			portENTER_CRITICAL(); -			buffer->state = FREE; -			portEXIT_CRITICAL(); -		} -	} -} -#endif -  /* This task pings the watchdog even when the idle task is not running   * It should be started with a very high priority and will delay most of the time */  void vMainWatchdogPinger (void *pvParameters) @@ -164,6 +180,15 @@ void vMainWatchdogPinger (void *pvParameters)  	}  } +void usb_print_flusher (void *pvParameters) +{ +	(void)pvParameters; +	while(1) { +		usb_print_flush(); +		vTaskDelay(100*portTICK_RATE_MS); +	} +} +  /**********************************************************************/  int main (void)  { @@ -178,8 +203,8 @@ int main (void)      da_init();      adc_init(); -    /*xTaskCreate (vMainTestSSCRXConsumer, (signed portCHAR *) "SSC_CONSUMER", TASK_USB_STACK, -	NULL, TASK_USB_PRIORITY, NULL);*/ +    xTaskCreate (usb_print_flusher, (signed portCHAR *) "PRINT-FLUSH", TASK_USB_STACK, +	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, diff --git a/openpicc/application/openpicc.h b/openpicc/application/openpicc.h index fc2c4d8..b4d2b7a 100644 --- a/openpicc/application/openpicc.h +++ b/openpicc/application/openpicc.h @@ -38,5 +38,6 @@ typedef int s_int32_t;  #define DA_BASELINE 200 +#define DIV_ROUND_UP(a,b) ( (a+(b-1)) / b)  #endif/*__OPENPICC_H__*/ diff --git a/openpicc/application/ssc.c b/openpicc/application/ssc.c new file mode 100644 index 0000000..f15b25d --- /dev/null +++ b/openpicc/application/ssc.c @@ -0,0 +1,599 @@ +/* AT91SAM7 SSC controller routines for OpenPICC + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2007-2008 Henryk Plötz <henryk@ploetzli.ch> + * + *  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; either version 2 of the License, or + *  (at your option) any later version. + * + *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + * We use SSC for both TX and RX side. + * + * RX side is interconnected with demodulated carrier  + * + * TX side is interconnected with load modulation circuitry + */ + +#include <FreeRTOS.h> +#include <queue.h> +#include <task.h> +#include <openpicc.h> + +#include <string.h> +#include <errno.h> + +#include "ssc.h" +#include "iso14443.h" + +#include "tc_cdiv_sync.h" +#include "tc_fdt.h" +#include "led.h" + +#include "usb_print.h" +#include "cmd.h" + +#define PRINT_DEBUG 0 + +// BROKEN Old FIQ code +int ssc_tx_pending=0, ssc_tx_fiq_fdt_cdiv=0, ssc_tx_fiq_fdt_ssc=0; + +struct _ssc_handle { +	enum ssc_mode mode; +	const struct openpicc_hardware *openpicc; +	ssc_dma_rx_buffer_t* rx_buffer[2]; +	ssc_callback_t callback; +	xQueueHandle rx_queue; +	AT91PS_PDC pdc; +	AT91PS_SSC ssc; +	u_int8_t rx_enabled, tx_enabled; +	u_int8_t rx_running, tx_running; +}; + +static ssc_handle_t _ssc; +static const ssc_mode_def ssc_modes[] = { +	/* Undefined, no size set */ +	[SSC_MODE_NONE]		   = {SSC_MODE_NONE, 0, 0, 0}, +	/* 14443A Frame */ +	[SSC_MODE_14443A]      = {SSC_MODE_14443A,  +		ISO14443_BITS_PER_SSC_TRANSFER * ISO14443A_SAMPLE_LEN,               // transfersize_ssc  +		ISO14443_BITS_PER_SSC_TRANSFER * ISO14443A_SAMPLE_LEN <= 8 ? 8 : 16, // transfersize_pdc  +		DIV_ROUND_UP(ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS, ISO14443_BITS_PER_SSC_TRANSFER) }, +}; +static struct { +	ssc_metric metric; +	char *name; +	int value; +} ssc_metrics[] = { +		[METRIC_RX_OVERFLOWS]      = {METRIC_RX_OVERFLOWS, "Rx overflows", 0}, +		[METRIC_FREE_RX_BUFFERS]   = {METRIC_FREE_RX_BUFFERS, "Free Rx buffers", 0}, +		[METRIC_MANAGEMENT_ERRORS] = {METRIC_MANAGEMENT_ERRORS, "Internal buffer management error", 0}, +		[METRIC_MANAGEMENT_ERRORS_1] = {METRIC_MANAGEMENT_ERRORS_1, "Internal buffer management error type 1", 0}, +		[METRIC_MANAGEMENT_ERRORS_2] = {METRIC_MANAGEMENT_ERRORS_2, "Internal buffer management error type 2", 0}, +		[METRIC_MANAGEMENT_ERRORS_3] = {METRIC_MANAGEMENT_ERRORS_3, "Internal buffer management error type 3", 0}, +}; + +static ssc_dma_rx_buffer_t _rx_buffers[SSC_DMA_BUFFER_COUNT]; +ssc_dma_tx_buffer_t        _tx_buffer; + +/******* PRIVATE "meat" code *************************************************/ + +#define SSC_RX_IRQ_MASK	(AT91C_SSC_RXRDY | 	\ +			 AT91C_SSC_OVRUN | 	\ +			 AT91C_SSC_ENDRX |	\ +			 AT91C_SSC_RXBUFF |	\ +			 AT91C_SSC_RXSYN |	\ +			 AT91C_SSC_CP0 |	\ +			 AT91C_SSC_CP1) + +#define SSC_TX_IRQ_MASK (AT91C_SSC_TXRDY |	\ +			 AT91C_SSC_TXEMPTY | 	\ +			 AT91C_SSC_ENDTX |	\ +			 AT91C_SSC_TXBUFE |	\ +			 AT91C_SSC_TXSYN) + +static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh); +static __ramfunc int _reload_rx(ssc_handle_t *sh); + + +static int __ramfunc _ssc_rx_irq(u_int32_t orig_sr, int start_asserted, portBASE_TYPE task_woken) +{ +	int end_asserted = 0; +	ssc_handle_t *sh = &_ssc; +	u_int32_t orig_rcmr = sh->ssc->SSC_RCMR; +	 +#if PRINT_DEBUG +	int old = usb_print_set_default_flush(0);  // DEBUG OUTPUT +	DumpStringToUSB("orig:");  // DEBUG OUTPUT +	DumpUIntToUSB(orig_sr);  // DEBUG OUTPUT +	DumpStringToUSB("\n\r");  // DEBUG OUTPUT +#endif +	u_int32_t sr = orig_sr | _ssc.ssc->SSC_SR; +	 +	if( (sr & AT91C_SSC_RXSYN) || start_asserted) { +		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); +			if(end_asserted) +				sr = orig_sr | _ssc.ssc->SSC_SR; +		} +	} +	 +#if PRINT_DEBUG	 +	DumpStringToUSB("sr:");  // DEBUG OUTPUT +	DumpUIntToUSB(sr);  // DEBUG OUTPUT +	DumpStringToUSB("\n\r");  // DEBUG OUTPUT +	usb_print_set_default_flush(old);  // DEBUG OUTPUT +#endif +	 +	if(((sr & (AT91C_SSC_CP1 | AT91C_SSC_ENDRX)) || end_asserted) && (sh->rx_buffer[0] != NULL)) { +		/* Receiving has ended */ +		AT91F_PDC_DisableRx(sh->pdc); +		AT91F_SSC_DisableRx(sh->ssc); +		sh->ssc->SSC_RCMR = ((sh->ssc->SSC_RCMR) & (~AT91C_SSC_START)) | (AT91C_SSC_START_0); + +		ssc_dma_rx_buffer_t *buffer = _unload_rx(sh); +		if(buffer != NULL) { +			if(sh->callback != NULL) +				sh->callback(CALLBACK_RX_FRAME_ENDED, buffer); + +			if(buffer->state != FREE) { +				task_woken = xQueueSendFromISR(sh->rx_queue, &buffer, task_woken); +			} +		} +		 +		if(_reload_rx(sh)) { +			int dummy = sh->ssc->SSC_RHR; (void)dummy; +			AT91F_PDC_EnableRx(sh->pdc); +			AT91F_SSC_EnableRx(sh->ssc); +		} else { +			sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK; +			sh->rx_running = 0; +			sh->callback(CALLBACK_RX_STOPPED, sh); +		} +		 +	} + +	sh->ssc->SSC_RCMR = orig_rcmr; +	return task_woken; +} + +/* Exported callback for the case when the frame start has been detected externally */ +void ssc_frame_started(void) +{ +	_ssc_rx_irq(_ssc.ssc->SSC_SR, 1, pdFALSE); +} + +static void __ramfunc ssc_irq(void) __attribute__ ((naked)); +static void __ramfunc ssc_irq(void) +{ +	portENTER_SWITCHING_ISR(); +	vLedSetRed(1); +	portBASE_TYPE task_woken = pdFALSE; +	 +	u_int32_t sr = _ssc.ssc->SSC_SR; +	if(sr & AT91C_SSC_RXSYN) { +		task_woken = _ssc_rx_irq(sr, 1, task_woken); +	} else if(sr & SSC_RX_IRQ_MASK) { +		task_woken = _ssc_rx_irq(sr, 0, task_woken); +	} +	 +	AT91F_AIC_ClearIt(AT91C_ID_SSC); +	AT91F_AIC_AcknowledgeIt(); + +	vLedSetRed(0); +	portEXIT_SWITCHING_ISR(task_woken); +} + +static __ramfunc ssc_dma_rx_buffer_t *_get_buffer(ssc_dma_buffer_state_t old, ssc_dma_buffer_state_t new) +{ +	ssc_dma_rx_buffer_t *buffer = NULL; +	int i; +	for(i=0; i < SSC_DMA_BUFFER_COUNT; i++) { +		if(_rx_buffers[i].state == old) { +			buffer = &_rx_buffers[i]; +			buffer->state = new; +			break; +		} +	} +	return buffer; +} + +/* Doesn't check sh, must be called with interrupts disabled */ +static __ramfunc int _reload_rx(ssc_handle_t *sh) +{ +	int result = 0; +	if(sh->rx_buffer[0] != NULL) { +		ssc_metrics[METRIC_MANAGEMENT_ERRORS_1].value++; +		result = 1; +		goto out; +	} +	 +	ssc_dma_rx_buffer_t *buffer = _get_buffer(FREE, PENDING); +	 +	if(buffer == NULL) { +		ssc_metrics[METRIC_RX_OVERFLOWS].value++; +		goto out; +	} + +	buffer->reception_mode = &ssc_modes[sh->mode]; +	buffer->len_transfers = ssc_modes[sh->mode].transfers; +	 +	AT91F_PDC_SetRx(sh->pdc, buffer->data, buffer->len_transfers); +	sh->rx_buffer[0] = buffer; +	 +	result = 1; +out: +	return result; +} + +// Doesn't check sh, call with interrupts disabled, SSC/PDC stopped +static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh) +{ +	if(sh->rx_buffer[0] == NULL) { +		ssc_metrics[METRIC_MANAGEMENT_ERRORS_2].value++; +		return NULL; +	} +	 +	ssc_dma_rx_buffer_t *buffer = sh->rx_buffer[0]; +	u_int32_t rpr = sh->pdc->PDC_RPR,  +		rcr = sh->pdc->PDC_RCR; +	AT91F_PDC_SetRx(sh->pdc, 0, 0); +	sh->rx_buffer[0] = NULL; +	buffer->state = FULL; +	 +	if(rcr == 0) { +		buffer->flags.overflow = 1; +	} else { +		buffer->flags.overflow = 0; +	} +	 +	if(rcr > 0) { +		/* Append a zero to make sure the buffer decoder finds the stop bit */ +		switch(buffer->reception_mode->transfersize_pdc) { +		case 8: +			//*((u_int8_t*)rpr++) = sh->ssc->SSC_RSHR; +			*((u_int8_t*)rpr++) = 0; +			--rcr; +			break; +		case 16: +			*((u_int16_t*)rpr++) = 0; +			--rcr; +			break; +		case 32: +			*((u_int32_t*)rpr++) = 0; +			--rcr; +			break; +		} +	} +	 +	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; +		return NULL; +	} +	 +	buffer->len_transfers = buffer->len_transfers - rcr; +	 +	return buffer; +} + +void ssc_select_clock(enum ssc_clock_source clock) +{ +	if(!OPENPICC->features.clock_switching) return; +	switch(clock) { +	case CLOCK_SELECT_PLL: +		AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH); +		break; +	case CLOCK_SELECT_CARRIER: +		AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH); +		break; +	default: break; +	} +} + +static void _ssc_start_rx(ssc_handle_t *sh) +{ +	taskENTER_CRITICAL(); +	if(sh != &_ssc) goto out; +	if(sh->rx_running) goto out; +	if(!sh->rx_enabled) goto out; + +	// Load buffer +	if(!_reload_rx(sh)) +		goto out; +	 +	sh->ssc->SSC_IER = AT91C_SSC_RXSYN | \ +		 AT91C_SSC_CP1 | AT91C_SSC_ENDRX; +	sh->rx_running = 1; +	if(sh->callback != NULL) +		sh->callback(CALLBACK_RX_STARTED, sh); + +	// Actually enable reception +	int dummy = sh->ssc->SSC_RHR; (void)dummy; +	AT91F_PDC_EnableRx(sh->pdc); +	AT91F_SSC_EnableRx(sh->ssc); + +out: +	taskEXIT_CRITICAL(); +	usb_print_string_f(sh->rx_running ? "SSC now running\n\r":"SSC not running\n\r", 0); +} + +static void _ssc_stop_rx(ssc_handle_t *sh) +{ +	taskENTER_CRITICAL(); +	sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK; +	sh->rx_running = 0; +	if(sh->callback != NULL) +		sh->callback(CALLBACK_RX_STOPPED, sh); +	taskEXIT_CRITICAL(); +} + +/******* PRIVATE Initialization Code *****************************************/ +static void _ssc_rx_mode_set(ssc_handle_t *sh, enum ssc_mode ssc_mode) +{ +	taskENTER_CRITICAL(); +	int was_running = sh->rx_running; +	if(was_running) _ssc_stop_rx(sh); + +	u_int8_t data_len=0, num_data=0, sync_len=0; +	u_int32_t start_cond=0; +	u_int32_t clock_gating=0; +	u_int8_t stop = 0, invert=0; + +	switch(ssc_mode) { +		case SSC_MODE_14443A: +			/* Start on Compare 0. The funky calculations down there are designed to allow a different +			 * (longer) compare length for Compare 1 than for Compare 0. Both lengths are set by the +			 * same register. */ +			start_cond = AT91C_SSC_START_0; +			sync_len = ISO14443A_EOF_LEN; +			sh->ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE << (ISO14443A_EOF_LEN-ISO14443A_SOF_LEN); +			sh->ssc->SSC_RC1R = ISO14443A_EOF_SAMPLE; +			 +			data_len = ssc_modes[SSC_MODE_14443A].transfersize_ssc; +			 +			/* We are using stop on Compare 1. The docs are ambiguous but my interpretation is that +			 * this means that num_data is basically ignored and reception is continuous until stop +			 * event. Set num_data to the maximum anyways. */ +			num_data = 16; +			stop = 1; +			 +			stop = 0; +			start_cond = AT91C_SSC_START_CONTINOUS; +			sync_len = 0; +			 +			/* We can't use receive clock gating with RF because RF will only go up with the first +			 * edge, this doesn't cooperate with the longer sync len above.  +			 * FIXME: What's the interaction between clock BURST on v0.4p1, RF and Compare 0?  +			 * In theory this shouldn't work even without SSC clock_gating because BURST gates the +			 * clock before the SSC and so it shouldn't get sync_len samples before Compare 0.  +			 * I believe there's a bug waiting to happen somewhere here. */ +			clock_gating = (0x0 << 6); +			//invert = AT91C_SSC_CKI; +			break; +		case SSC_MODE_NONE: +			goto out; +			break; +	} +	 +	/* Receive frame mode register */ +	sh->ssc->SSC_RFMR = ((data_len-1) & 0x1f) | +			(((num_data-1) & 0x0f) << 8) |  +			(((sync_len-1) & 0x0f) << 16); +	 +	/* Receive clock mode register, Clock selection: RK, Clock output: None */ +	sh->ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE |  +			clock_gating | invert | start_cond | (stop << 12); + +out: +	sh->mode = ssc_mode; +	if(was_running) _ssc_start_rx(sh); +	taskEXIT_CRITICAL(); +} + +static inline int _init_ssc_rx(ssc_handle_t *sh) +{ +	tc_cdiv_sync_init(); +	tc_cdiv_sync_enable(); +	 +	if(sh->rx_queue == NULL) { +		sh->rx_queue = xQueueCreate(10, sizeof(sh->rx_buffer[0])); +		if(sh->rx_queue == NULL) +			goto out_fail_queue; +	} +	 +	sh->ssc = AT91C_BASE_SSC; +	sh->pdc = (AT91PS_PDC) &(sh->ssc->SSC_RPR); + +	AT91F_SSC_CfgPMC(); + +	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,  +			    OPENPICC_SSC_DATA | OPENPICC_SSC_CLOCK | +			    OPENPICC_PIO_FRAME, +			    0); +	 +	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); +	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); +	 +	if(OPENPICC->features.data_gating) { +		AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); +		AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); +	} +	 +	if(OPENPICC->features.clock_switching) { +		AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH); +		ssc_select_clock(CLOCK_SELECT_PLL); +	} + +	/* Disable all interrupts */ +	sh->ssc->SSC_IDR = SSC_RX_IRQ_MASK; + +	/* don't divide clock inside SSC, we do that in tc_cdiv */ +	sh->ssc->SSC_CMR = 0; + +	sh->rx_buffer[0] = sh->rx_buffer[1] = NULL; +	 +	/* Will be set to a real value some time later  +	 * FIXME Layering? */ +	tc_fdt_set(0xff00); +	 +	return 1; +	 +out_fail_queue: +	return 0; +} + +static int _ssc_register_callback(ssc_handle_t *sh, ssc_callback_t _callback) +{ +	if(!sh) return -EINVAL; +	if(sh->callback != NULL) return -EBUSY; +	sh->callback = _callback; +	if(sh->callback != NULL)  +		sh->callback(CALLBACK_SETUP, sh); +	return 0; +} + +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 = NULL; +	} +	return 0; +} + +/******* PUBLIC API **********************************************************/ +ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode mode, ssc_callback_t callback) +{ +	ssc_handle_t *sh = &_ssc; +	unsigned int i; +	 +	if(sh->rx_enabled || sh->tx_enabled || sh->rx_running) { +		if( ssc_close(sh) != 0) { +			return NULL; +		} +	} +	 +	for(i=0; i<sizeof(_rx_buffers)/sizeof(_rx_buffers[0]); i++) +		memset(&_rx_buffers[i], 0, sizeof(_rx_buffers[i])); +	 +	if(init_tx) { +		// FIXME Implement +		sh->tx_enabled = 0; +		return NULL; +	} +	 +	if(init_rx) { +		sh->rx_enabled = _init_ssc_rx(sh); +		if(!sh->rx_enabled) { +			ssc_close(sh); +			return NULL; +		} else {  +			_ssc_rx_mode_set(sh, mode); +		} +	} +	 +	if(sh->rx_enabled || sh->tx_enabled) { +		AT91F_AIC_ConfigureIt(AT91C_ID_SSC, +				      OPENPICC_IRQ_PRIO_SSC, +				      AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq); +				      //AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, (THandler)&ssc_irq); +		AT91F_AIC_EnableIt(AT91C_ID_SSC); +	} +	 +	if(callback != NULL) +		_ssc_register_callback(sh, callback); +	 +	if(init_rx) +		_ssc_start_rx(sh); +	 +	return sh; +} + +int ssc_recv(ssc_handle_t* sh, ssc_dma_rx_buffer_t* *buffer,unsigned int timeout) +{ +	if(sh == NULL) return -EINVAL; +	 +	taskENTER_CRITICAL(); +	if(sh->rx_running) { +		if(PRINT_DEBUG) usb_print_string_f("Continuing SSC Rx\n\r",0); // DEBUG OUTPUT +	} else { +		if(PRINT_DEBUG) usb_print_string_f("ERR: SSC halted\n\r",0); // DEBUG OUTPUT +		/* Try starting the Reception */ +		_ssc_start_rx(sh); +	} +	taskEXIT_CRITICAL(); +	 +	if(xQueueReceive(sh->rx_queue, buffer, timeout)){ +		if(*buffer != NULL) return 0; +		else return -EINTR; +	} +	 +	return -ETIMEDOUT; +} + +int ssc_close(ssc_handle_t* sh) +{ +	if(sh->rx_running) +		_ssc_stop_rx(sh); +	 +	if(sh->rx_enabled) { +		// FIXME Implement +		sh->rx_enabled = 0; +	} +	if(sh->tx_enabled) { +		// FIXME Implement +		sh->tx_enabled = 0; +	} +	 +	_ssc_unregister_callback(sh, NULL); +	return 0; +} + +int ssc_get_metric(ssc_metric metric, char **description, int *value) +{ +	char *_name="Undefined"; +	int _value=0; +	int valid=0; +	 +	if(metric < sizeof(ssc_metrics)/sizeof(ssc_metrics[0])) { +		_name  = ssc_metrics[metric].name; +		_value = ssc_metrics[metric].value; +		valid = 1; +	} +		 +	switch(metric) { +		case METRIC_FREE_RX_BUFFERS: +			_value = 0; +			int i; +			for(i=0; i < SSC_DMA_BUFFER_COUNT; i++) +				if(_rx_buffers[i].state == FREE) _value++; +			break; +		case METRIC_MANAGEMENT_ERRORS: +			_value = ssc_metrics[METRIC_MANAGEMENT_ERRORS_1].value + +				ssc_metrics[METRIC_MANAGEMENT_ERRORS_2].value + +				ssc_metrics[METRIC_MANAGEMENT_ERRORS_3].value; +			break; +		default: +			break; +	} +	 +	if(!valid) return 0; +	 +	if(description != NULL) *description = _name; +	if(value != NULL) *value = _value; +	return 1; +} + diff --git a/openpicc/application/ssc.h b/openpicc/application/ssc.h new file mode 100644 index 0000000..0d96920 --- /dev/null +++ b/openpicc/application/ssc.h @@ -0,0 +1,53 @@ +#ifndef SSC_H_ +#define SSC_H_ + +#include "board.h" +#include "ssc_buffer.h" + +typedef enum {  +	METRIC_RX_OVERFLOWS,      // No free buffer during Rx reload +	METRIC_FREE_RX_BUFFERS,   // Free Rx buffers, calculated on-the-fly +	METRIC_MANAGEMENT_ERRORS, // One of the diverse types of management errors +	METRIC_MANAGEMENT_ERRORS_1, // Internal buffer management error type 1 +	METRIC_MANAGEMENT_ERRORS_2, // Internal buffer management error type 2 +	METRIC_MANAGEMENT_ERRORS_3, // Internal buffer management error type 3 +	_MAX_METRICS, +} ssc_metric; + +extern int ssc_get_metric(ssc_metric metric, char **description, int *value); + +typedef enum { +	CALLBACK_RX_STARTED,        // *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_SETUP,             // *data is ssh_handle_t *sh +	CALLBACK_TEARDOWN,          // *data is ssh_handle_t *sh +} ssc_callback_reason; +typedef void (*ssc_callback_t)(ssc_callback_reason reason, void *data); + +enum ssc_clock_source {  +	CLOCK_SELECT_PLL, +	CLOCK_SELECT_CARRIER, +	_MAX_CLOCK_SOURCES, +}; +struct _ssc_handle; + +typedef struct _ssc_handle ssc_handle_t; + +extern void ssc_select_clock(enum ssc_clock_source clock); + +extern void ssc_frame_started(void); + +/* Rx/Tx initialization separate, since Tx disables PWM output ! */ +extern ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode mode , ssc_callback_t callback); + +extern int ssc_recv(ssc_handle_t* sh, ssc_dma_rx_buffer_t* *buffer, unsigned int timeout); + +extern int ssc_close(ssc_handle_t* sh); + +extern void ssc_rx_stop_frame_ended(void); + +#endif /*SSC_H_*/ diff --git a/openpicc/application/ssc_buffer.h b/openpicc/application/ssc_buffer.h new file mode 100644 index 0000000..fdb977f --- /dev/null +++ b/openpicc/application/ssc_buffer.h @@ -0,0 +1,46 @@ +#ifndef SSC_BUFFER_H_ +#define SSC_BUFFER_H_ + +#define SSC_RX_BUFFER_SIZE_AS_UINT8 2048 +#define SSC_DMA_BUFFER_COUNT 4 + +#if SSC_RX_BUFFER_SIZE_AS_UINT8 < DIV_ROUND_UP((ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS*ISO14443A_SAMPLE_LEN),8) +#undef SSC_RX_BUFFER_SIZE_AS_UINT8 +#define SSC_RX_BUFFER_SIZE_AS_UINT8 DIV_ROUND_UP((ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS*ISO14443A_SAMPLE_LEN),8) +#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_dma_buffer_state_t; + +enum ssc_mode { +	SSC_MODE_NONE, +	SSC_MODE_14443A, +}; + +typedef struct { +	enum ssc_mode mode; +	u_int16_t transfersize_ssc; +	u_int16_t transfersize_pdc; +	u_int16_t transfers; +} ssc_mode_def; + +typedef struct { +	volatile ssc_dma_buffer_state_t state; +	u_int32_t len_transfers;            /* Length of the content, in transfers */ +	struct { +		int overflow:1; +	} flags; +	const ssc_mode_def *reception_mode; /* Pointer to the SSC mode definition that the buffer has been loaded for (affects element size and count) */ +	u_int8_t data[SSC_RX_BUFFER_SIZE_AS_UINT8]; +} ssc_dma_rx_buffer_t; + + +typedef struct { +} ssc_dma_tx_buffer_t; + +#endif /*SSC_BUFFER_H_*/ diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c deleted file mode 100644 index df6d7fa..0000000 --- a/openpicc/application/ssc_picc.c +++ /dev/null @@ -1,731 +0,0 @@ -/* AT91SAM7 SSC controller routines for OpenPICC - * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> - * (C) 2007 Henryk Plötz <henryk@ploetzli.ch> - * - *  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; either version 2 of the License, or - *  (at your option) any later version. - * - *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA - * - * We use SSC for both TX and RX side. - * - * RX side is interconnected with demodulated carrier  - * - * TX side is interconnected with load modulation circuitry - */ - -//#undef DEBUG - -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <AT91SAM7.h> -#include <lib_AT91SAM7.h> - -#include <FreeRTOS.h> -#include "queue.h" -#include "task.h" - -#include "dbgu.h" -#include "led.h" -#include "cmd.h" -#include "board.h" -#include "openpicc.h" - -#include "ssc_picc.h" -#include "tc_cdiv_sync.h" -#include "tc_fdt.h" - -#include "pio_irq.h" -#include "usb_print.h" -#include "iso14443_layer3a.h" - -#define DEBUG_SSC_REFILL 1 -#ifdef DEBUG_SSC_REFILL -#define DEBUGR(x, args ...) DEBUGPCRF(x, ## args) -#else -#define DEBUGR(x, args ...) -#endif - -#define DEBUG_LOAD_AND_UNLOAD 0 - -static const AT91PS_SSC ssc = AT91C_BASE_SSC; -static AT91PS_PDC rx_pdc; -static AT91PS_PDC tx_pdc; - -xQueueHandle ssc_rx_queue = NULL; - -struct ssc_state { -	ssc_dma_rx_buffer_t* buffer[2]; -	enum ssc_mode mode; -}; -static struct ssc_state ssc_state; - -/* Note: Only use 8, 16 or 32 for the transfersize. (These are the sizes used by the PDC and even though - * the SSC supports different sizes, all PDC tranfers will be either 8, 16 or 32, rounding up.) */ -static const ssc_mode_def ssc_sizes[] = { -	/* Undefined, no size set */ -	[SSC_MODE_NONE]		   = {SSC_MODE_NONE, 0, 0, 0}, -	/* 14443A Short Frame: 1 transfer of ISO14443A_SHORT_LEN bits */ -	[SSC_MODE_14443A_SHORT]	   = {SSC_MODE_14443A_SHORT, ISO14443A_SHORT_LEN, ISO14443A_SHORT_TRANSFER_SIZE, 1}, -	/* 14443A Standard Frame: FIXME 16 transfers of 32 bits (maximum number), resulting in 512 samples */  -	[SSC_MODE_14443A_STANDARD] = {SSC_MODE_14443A_STANDARD, 32, 32, 16}, -	/* 14443A Frame, don't care if standard or short */ -	[SSC_MODE_14443A]          = {SSC_MODE_14443A,  -		4 * ISO14443A_SAMPLE_LEN,               // transfersize_ssc  -		4 * ISO14443A_SAMPLE_LEN <= 8 ? 8 : 16, // transfersize_pdc  -		ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS}, -	[SSC_MODE_14443B]	   = {SSC_MODE_14443B, 32, 32, 16},	/* 64 bytes */ -	[SSC_MODE_EDGE_ONE_SHOT]   = {SSC_MODE_EDGE_ONE_SHOT, 32, 32,  16},	/* 64 bytes */ -	[SSC_MODE_CONTINUOUS]	   = {SSC_MODE_CONTINUOUS, 32, 32,  511},	/* 2044 bytes */ -}; - -/* ************** SSC BUFFER HANDLING *********************** */ -static ssc_dma_rx_buffer_t dma_buffers[SSC_DMA_BUFFER_COUNT]; -ssc_dma_tx_buffer_t ssc_tx_buffer; - -static volatile int overflows; -static volatile int ssc_buffer_errors; -static volatile int late_frames = 0; - -static int ssc_count_free(void) { -	int i,free = 0; -	for(i=0; i<SSC_DMA_BUFFER_COUNT; i++) { -		if(dma_buffers[i].state == FREE) free++; -	} -	return free; -} - -int ssc_get_metric(ssc_metric metric) { -	switch(metric) { -		case OVERFLOWS: -			return overflows; -			break; -		case BUFFER_ERRORS: -			return ssc_buffer_errors; -			break; -		case FREE_BUFFERS: -			return ssc_count_free(); -			break; -		case LATE_FRAMES: -			return late_frames; -			break; -		case SSC_ERRORS: -			return ssc_get_metric(OVERFLOWS) + ssc_get_metric(BUFFER_ERRORS); -			break; -	} -	return 0; -} - -static ssc_dma_rx_buffer_t* __ramfunc ssc_find_dma_buffer(ssc_dma_buffer_state_t oldstate,  -	ssc_dma_buffer_state_t newstate) -{ -	ssc_dma_rx_buffer_t* result = NULL;  -	int i=0; -	for(i=0; i<SSC_DMA_BUFFER_COUNT; i++) { -		if(dma_buffers[i].state == oldstate) { -			result = &dma_buffers[i]; -			result->state = newstate; -			break; -		} -	} -	return result; -} - - -static int __ramfunc __ssc_rx_load(int secondary); -static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary); -/*  - * Find and load an RX buffer into the DMA controller, using the current SSC mode - */ -static int __ramfunc __ssc_rx_load(int secondary) -{ -	ssc_dma_rx_buffer_t *buffer; -	 -	buffer = ssc_find_dma_buffer(FREE, PENDING); -	if (!buffer) { -		DEBUGP("no_rctx_for_refill! "); -		overflows++; -		return -1; -	} -	DEBUGR("filling SSC RX%u dma ctx: %u (len=%u) ", secondary, -		req_ctx_num(buffer), buffer->size); -	buffer->len_transfers = ssc_sizes[ssc_state.mode].transfers; -	buffer->reception_mode = &ssc_sizes[ssc_state.mode]; -	 -	if(ssc_state.buffer[secondary] != NULL) {  -		/* This condition is not expected to happen and would probably indicate a bug  -		 * of some sort. However, instead of leaking buffers we'll just pretend it to -		 * be free again. */ -		 ssc_buffer_errors++; -		 usb_print_buffer_f("^", 0, 1, 0); -		 if(ssc_state.buffer[secondary]->state == PENDING) { -		 	ssc_state.buffer[secondary]->state = FREE; -		 } -	} -	 -	if (secondary) { -		AT91F_PDC_SetNextRx(rx_pdc, buffer->data, -				    ssc_sizes[ssc_state.mode].transfers); -		ssc_state.buffer[1] = buffer; -	} else { -		AT91F_PDC_SetRx(rx_pdc, buffer->data, -				ssc_sizes[ssc_state.mode].transfers); -		ssc_state.buffer[0] = buffer; -	} -	 -	if(DEBUG_LOAD_AND_UNLOAD) { -	if(secondary) {int i=usb_print_set_default_flush(0); -		DumpStringToUSB("{1:"); -		DumpUIntToUSB(rx_pdc->PDC_RNCR); -		DumpStringToUSB(" "); -		DumpUIntToUSB(rx_pdc->PDC_RNPR); -		DumpStringToUSB("} "); -		usb_print_set_default_flush(i);} -	else {int i=usb_print_set_default_flush(0); -		DumpStringToUSB("{0:"); -		DumpUIntToUSB(rx_pdc->PDC_RCR); -		DumpStringToUSB(" "); -		DumpUIntToUSB(rx_pdc->PDC_RPR); -		DumpStringToUSB("} "); -		usb_print_set_default_flush(i);} -	} - -	return 0; -} - -/* - * Take the RX buffer(s) from the DMA controller, e.g. to abort a currently executing receive process and - * either reclaim the buffer(s) (if no transfer have been done so far) or mark them as used, updating  - * the length fields to match the number of transfers that have actually executed. - * Warning: When this function executes, the mapping in ssc_state is expected to match the mapping in - * the PDC (e.g. ssc_state[0] is the RX Buffer and ssc_state[1] is the Next RX Buffer). Do not use this - * function while the PDC transfer is enabled. Especially do not run it from the SSC RX IRQ. - */ -static int __ramfunc __ssc_tx_unload_all(ssc_dma_rx_buffer_t** primary, ssc_dma_rx_buffer_t** secondary) -{ -	if(primary != NULL)   *primary   = __ssc_rx_unload(0); else __ssc_rx_unload(0); -	if(secondary != NULL) *secondary = __ssc_rx_unload(1); else __ssc_rx_unload(1); -	return 1; -} -static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary) -{ -	ssc_dma_rx_buffer_t *buffer = ssc_state.buffer[secondary]; -	if(buffer == NULL) return NULL; -	 -	if(DEBUG_LOAD_AND_UNLOAD) { -	if(secondary) {int i=usb_print_set_default_flush(0); -		DumpStringToUSB("(1:"); -		DumpUIntToUSB(rx_pdc->PDC_RNCR); -		DumpStringToUSB(" "); -		DumpUIntToUSB(rx_pdc->PDC_RNPR); -		DumpStringToUSB(") "); -		usb_print_set_default_flush(i);} -	else {int i=usb_print_set_default_flush(0); -		DumpStringToUSB("(0:"); -		DumpUIntToUSB(rx_pdc->PDC_RCR); -		DumpStringToUSB(" "); -		DumpUIntToUSB(rx_pdc->PDC_RPR); -		DumpStringToUSB(") "); -		usb_print_set_default_flush(i);} -	} -	 -	u_int16_t remaining_transfers = (secondary ? rx_pdc->PDC_RNCR : rx_pdc->PDC_RCR); -	u_int8_t* next_transfer_location = (u_int8_t*)(secondary ? rx_pdc->PDC_RNPR : rx_pdc->PDC_RPR); -	u_int16_t elapsed_transfers = buffer->reception_mode->transfers - remaining_transfers; -	 -	/* BUG BUG BUG For some reason the RNCR is zero, even though there have been no transfers in the secondary -	 * buffer. For now just assume that secondary==1 && remaining_transfers==0 is a bug condition and actually -	 * means elapsed_transfers == 0. Of course this will fail should they second buffer really be completely full. */ -	if(secondary && remaining_transfers==0) { -		remaining_transfers = buffer->reception_mode->transfers; -		elapsed_transfers = 0; -	} -	 -	u_int32_t elapsed_size = buffer->reception_mode->transfersize_pdc/8  * elapsed_transfers; -	 -	/* Consistency check */ -	if( next_transfer_location - elapsed_size != buffer->data ) { -		int i=usb_print_set_default_flush(0); -		DumpStringToUSB("!!!"); DumpUIntToUSB(secondary); DumpStringToUSB(" ");  -		DumpUIntToUSB((int)next_transfer_location); DumpStringToUSB(" "); -		DumpUIntToUSB(elapsed_size); DumpStringToUSB(" "); DumpUIntToUSB((int)buffer->data); DumpStringToUSB(" "); -		usb_print_set_default_flush(i); -		ssc_buffer_errors++; -		usb_print_buffer_f("°", 0, 1, 0); -		if(buffer->state == PENDING) buffer->state = FREE; -		ssc_state.buffer[secondary] = NULL; -		return NULL; -	} -	 -	if(secondary) { -		AT91F_PDC_SetNextRx(rx_pdc, 0, 0); -	} else { -		AT91F_PDC_SetRx(rx_pdc, 0, 0); -	} -	if(buffer->state == PENDING || buffer->state==FULL) { -		buffer->len_transfers = elapsed_transfers; -		if(DEBUG_LOAD_AND_UNLOAD) -		{int i=usb_print_set_default_flush(0); -			DumpStringToUSB("<"); -			DumpUIntToUSB((unsigned int)buffer); -			DumpStringToUSB(": "); -			DumpUIntToUSB(elapsed_transfers); -			DumpStringToUSB("> "); -		usb_print_set_default_flush(i);} -		if(elapsed_transfers > 0) { -			buffer->state = FULL; -		} else { -			buffer->state = FREE; -		} -	} -	ssc_state.buffer[secondary] = NULL; -	  -	return buffer; -} - -#define SSC_RX_IRQ_MASK	(AT91C_SSC_RXRDY | 	\ -			 AT91C_SSC_OVRUN | 	\ -			 AT91C_SSC_ENDRX |	\ -			 AT91C_SSC_RXBUFF |	\ -			 AT91C_SSC_RXSYN |	\ -			 AT91C_SSC_CP0 |	\ -			 AT91C_SSC_CP1) - -#define SSC_TX_IRQ_MASK (AT91C_SSC_TXRDY |	\ -			 AT91C_SSC_TXEMPTY | 	\ -			 AT91C_SSC_ENDTX |	\ -			 AT91C_SSC_TXBUFE |	\ -			 AT91C_SSC_TXSYN) - -void ssc_rx_mode_set(enum ssc_mode ssc_mode) -{ -	u_int8_t data_len=0, num_data=0, sync_len=0; -	u_int32_t start_cond=0; -	u_int32_t clock_gating=0; -	u_int8_t stop = 0; - -	/* disable Rx and all Rx interrupt sources */ -	AT91F_SSC_DisableRx(AT91C_BASE_SSC); -	AT91F_SSC_DisableIt(ssc, SSC_RX_IRQ_MASK); - -	switch (ssc_mode) { -	case SSC_MODE_14443A_SHORT: -		start_cond = AT91C_SSC_START_0; -		sync_len = ISO14443A_SOF_LEN; -		ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE; -		data_len = ISO14443A_SHORT_LEN; -		num_data = 2; -		clock_gating = (0x2 << 6); -		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 = 16;	/* FIXME */ -		clock_gating = (0x2 << 6); -		break; -	case SSC_MODE_14443A: -		start_cond = AT91C_SSC_START_0; -		sync_len = ISO14443A_EOF_LEN; -		ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE << (ISO14443A_EOF_LEN-ISO14443A_SOF_LEN); -		ssc->SSC_RC1R = ISO14443A_EOF_SAMPLE; -		data_len = ssc_sizes[SSC_MODE_14443A].transfersize_ssc; -		num_data = 16; /* Start with 16, then switch to continuous in the IRQ handler */ -		stop = 1;      /* Actually the documentation indicates that setting STOP makes switching to continuous unnecessary */ -		clock_gating = (0x0 << 6); -		break; -	case SSC_MODE_14443B: -		/* start sampling at first falling data edge */ -		//start_cond =  -		break; -	case SSC_MODE_EDGE_ONE_SHOT: -	case SSC_MODE_CONTINUOUS: -		/* unfortunately we don't have RD and RF interconnected -		 * (at least not yet in the current hardware) */ -		//start_cond = AT91C_SSC_START_EDGE_RF; -		start_cond = AT91C_SSC_START_CONTINOUS; -				//AT91C_SSC_START_RISE_RF; -		sync_len = 0; -		data_len = 32; -		num_data = 16; -		clock_gating = (0x2 << 6); -		break; -	case SSC_MODE_NONE: -		goto out_set_mode; -		break; -	} -	//ssc->SSC_RFMR = AT91C_SSC_MSBF | (data_len-1) & 0x1f | -	ssc->SSC_RFMR = ((data_len-1) & 0x1f) | -			(((num_data-1) & 0x0f) << 8) |  -			(((sync_len-1) & 0x0f) << 16) -			//| AT91C_SSC_MSBF -			; -	ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE |  -			clock_gating | (0&AT91C_SSC_CKI) | start_cond | (stop << 12); - -	/* Enable Rx DMA */ -	AT91F_PDC_EnableRx(rx_pdc); - -	/* Enable RX interrupts */ -/* -	AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN | AT91C_SSC_CP0 | -			   AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF);*/ -out_set_mode: -	ssc_state.mode = ssc_mode; -} - -/* For some reason AT91C_SSC_START_RISE_RF (or AT91C_SSC_START_HIGH_RF or ...) doesn't - * work as a start condition. Instead we'll configure TF as a PIO input pin, enable - * a PIO change interrupt, have Fast Forcing enabled for the PIO change interrupt and - * then activate the SSC TX in the FIQ handler on rising TF. ssc_tx_pending is queried - * by the fiq handler to see whether to start the transmitter. */ -//#define USE_SSC_TX_TF_WORKAROUND -volatile u_int32_t ssc_tx_pending = 0; - -/* This is the time that the TF FIQ should spin until before SWTRG'ing the tc_cdiv. - * See fdt_timing.dia. Note: This means transmission is broken without USE_SSC_TX_TF_WORKAROUND */ -volatile u_int32_t ssc_tx_fiq_fdt_cdiv = 0; -/* This is the time that the TF FIQ should spin until before starting the SSC  - * There must be enough time between these two! */ -volatile u_int32_t ssc_tx_fiq_fdt_ssc = 0; -#ifndef USE_SSC_TX_TF_WORKAROUND -//#error Transmission is broken without USE_SSC_TX_TF_WORKAROUND, see comments in code -#endif - -void ssc_tf_irq(u_int32_t pio); -void ssc_tx_start(ssc_dma_tx_buffer_t *buf) -{ -	u_int8_t data_len, num_data, sync_len; -	u_int32_t start_cond; - -	/* disable Tx */ -	AT91F_PDC_DisableTx(tx_pdc); -	AT91F_SSC_DisableTx(AT91C_BASE_SSC); - -	/* disable all Tx related interrupt sources */ -	AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK); - -#ifdef USE_SSC_TX_TF_WORKAROUND -	start_cond = AT91C_SSC_START_CONTINOUS; -#else -	start_cond = AT91C_SSC_START_HIGH_RF; -#endif -	sync_len = 1; -	data_len = 32; -	num_data = buf->len/(data_len/8); /* FIXME This is broken for more than 64 bytes */ -	 -	ssc->SSC_TFMR = ((data_len-1) & 0x1f) | -			(((num_data-1) & 0x0f) << 8) |  -			(((sync_len-1) & 0x0f) << 16); -	ssc->SSC_TCMR = 0x01 | AT91C_SSC_CKO_NONE | AT91C_SSC_CKI | start_cond; -	 -	AT91F_PDC_SetTx(tx_pdc, buf->data, num_data); -	AT91F_PDC_SetNextTx(tx_pdc, 0, 0); -	buf->state = PENDING; - -	AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDTX); -	/* Enable DMA */ -	AT91F_PDC_EnableTx(tx_pdc); -	//AT91F_PDC_SetTx(tx_pdc, buf->data, num_data); -#ifdef OPENPICC_USE_SSC_DATA_GATING -	ssc_set_data_gate(0); -#endif -	/* Start Transmission */ -#ifndef USE_SSC_TX_TF_WORKAROUND -	AT91F_SSC_EnableTx(AT91C_BASE_SSC); -#else -	ssc_tx_pending = 1; -	pio_irq_enable(OPENPICC_SSC_TF); -	if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_SSC_TF)) { -		/* TF was probably already high when we enabled the PIO change interrupt for it. */ -		ssc_tf_irq(OPENPICC_SSC_TF); -		vLedBlinkRed(); -		late_frames++; -		usb_print_string_f("Late response\n\r", 0); -	} -#endif -} - -#ifdef USE_SSC_TX_TF_WORKAROUND -void ssc_tf_irq(u_int32_t pio) { -	(void)pio; -	if(!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_SSC_TF)) return; -	pio_irq_disable(OPENPICC_SSC_TF); -	if(ssc_tx_pending) { /* Transmit has not yet been started by the FIQ */ -		AT91F_SSC_EnableTx(AT91C_BASE_SSC); -		ssc_tx_pending = 0; -	} -} -#endif - - -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; -} - -void __ramfunc ssc_rx_stop_frame_ended(void) -{ -} - -static void __ramfunc ssc_irq(void) __attribute__ ((naked)); -static void __ramfunc ssc_irq(void) -{ -	portENTER_SWITCHING_ISR(); -	vLedSetRed(1); -	portBASE_TYPE task_woken = pdFALSE; - -	u_int32_t ssc_sr = ssc->SSC_SR; -	u_int32_t orig_ssc_sr = ssc_sr; -	ssc_dma_rx_buffer_t *inbuf=NULL; -	DEBUGP("ssc_sr=0x%08x, mode=%u: ", ssc_sr, ssc_state.mode); -	 -	if ((ssc_sr & AT91C_SSC_CP0) && (ssc_state.mode == SSC_MODE_14443A_SHORT || ssc_state.mode == SSC_MODE_14443A)) { -		/* Short frame, busy loop till the frame is received completely to -		 * prevent a second irq entrance delay when the actual frame end  -		 * irq is raised. (The scheduler masks interrupts for about 56us, -		 * which is too much for anticollision.) */ -		 int i = 0; -		 //vLedBlinkRed(); -		 while( ! ((ssc_sr=ssc->SSC_SR) & (AT91C_SSC_ENDRX | AT91C_SSC_CP1)) ) { -		 	i++; -		 	if(i > 9600) break; /* Break out, clearly this is not a short frame or a reception error happened */ -		 } -		 ssc_sr |= orig_ssc_sr; -		 vLedSetRed(1); -	} -	 -	if(orig_ssc_sr & AT91C_SSC_CP1) {usb_print_string_f("oCP1 ", 0); vLedBlinkRed();} -	if(ssc_sr & AT91C_SSC_CP1) usb_print_string_f("CP1 ", 0); -	 -	if (ssc_sr & (AT91C_SSC_ENDRX | AT91C_SSC_CP1)) { -		inbuf = ssc_state.buffer[0]; -		if(ssc_sr & AT91C_SSC_CP1 && !(ssc_sr & AT91C_SSC_ENDRX)) { -			/* Manually unload buffer 0, since only the SSC has stopped, not the PDC */ -			__ssc_rx_unload(0); -			__ssc_rx_load(0); -		} -		 -		inbuf->state = FULL; -		task_woken = xQueueSendFromISR(ssc_rx_queue, &inbuf, task_woken); -		vLedSetGreen(1); -		 -		if(ssc_sr & AT91C_SSC_ENDRX) { -			/* second buffer got propagated to primary */ -			ssc_state.buffer[0] = ssc_state.buffer[1]; -			ssc_state.buffer[1] = NULL; -		} -		 -		if(ssc_state.mode == SSC_MODE_EDGE_ONE_SHOT || ssc_state.mode == SSC_MODE_14443A_SHORT -			|| ssc_state.mode == SSC_MODE_14443A_STANDARD) { -			// Stop sampling here -			ssc_rx_stop(); -		} else { -			if (ssc_sr & AT91C_SSC_RXBUFF) { -	// FIXME -				DEBUGP("RXBUFF! "); -				if (ssc_state.buffer[0]) { -					//DEBUGP("Sending secondary RCTX(%u, len=%u) ", req_ctx_num(ssc_state.rx_ctx[0]), ssc_state.rx_ctx[0]->tot_len); -					//gaportENTER_CRITICAL(); -					ssc_state.buffer[0]->state = FULL; -					//gaportEXIT_CRITICAL(); -					task_woken = xQueueSendFromISR(ssc_rx_queue, &ssc_state.buffer[0], task_woken); -				} -				if(ssc_sr & AT91C_SSC_RXENA) if (__ssc_rx_load(0) == -1) -					AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX | -							    AT91C_SSC_RXBUFF | -							    AT91C_SSC_OVRUN); -			} -	 -			if(ssc_sr & AT91C_SSC_RXENA && ssc_state.buffer[1] == NULL) if (__ssc_rx_load(1) == -1) -				AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX | -						    AT91C_SSC_RXBUFF | -						    AT91C_SSC_OVRUN); -		} -	} -	 -	if (ssc_sr & AT91C_SSC_OVRUN) -		DEBUGP("RX_OVERRUN "); - -	if (ssc_sr & AT91C_SSC_CP0) -		DEBUGP("CP0 "); -	 -	if (ssc_sr & AT91C_SSC_TXSYN) -		DEBUGP("TXSYN "); -	 -	if(ssc_sr & AT91C_SSC_ENDTX) { -#ifdef OPENPICC_USE_SSC_DATA_GATING -		ssc_set_data_gate(1); -#endif -		AT91F_SSC_EnableTx(AT91C_BASE_SSC); -		//usb_print_string_f("ENDTX ", 0); -		if(ssc_tx_buffer.state == PENDING) { -			ssc_tx_buffer.state = FREE; -			AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK); -		} -	} - -	if(ssc_sr & AT91C_SSC_TXBUFE) -		DEBUGP("TXBUFE "); -	 -	if(irq_extension != NULL) -		irq_extension(ssc_sr, ssc_state.mode, inbuf?inbuf->data:NULL); - - -	DEBUGPCR("I"); -	AT91F_AIC_ClearIt(AT91C_ID_SSC); -	AT91F_AIC_AcknowledgeIt(); -	 -	vLedSetRed(0); -	portEXIT_SWITCHING_ISR(task_woken); -} - -void ssc_print(void) -{ -	DEBUGP("PDC_RPR=0x%08x ", rx_pdc->PDC_RPR); -	DEBUGP("PDC_RCR=0x%08x ", rx_pdc->PDC_RCR); -	DEBUGP("PDC_RNPR=0x%08x ", rx_pdc->PDC_RNPR); -	DEBUGP("PDC_RNCR=0x%08x ", rx_pdc->PDC_RNCR); -} - - -void ssc_rx_unthrottle(void) -{ -	AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDRX | AT91C_SSC_CP0 | -			   AT91C_SSC_RXBUFF | AT91C_SSC_OVRUN); -} - -void ssc_rx_start(void) -{ -	//DEBUGPCRF("starting SSC RX\n"); -	 -	__ssc_rx_load(0); -	if(ssc_state.mode != SSC_MODE_14443A_SHORT) __ssc_rx_load(1); -	 -	/* Enable Reception */ -	AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDRX | AT91C_SSC_CP0 | AT91C_SSC_CP1 | -			   AT91C_SSC_RXBUFF | AT91C_SSC_OVRUN); -	AT91F_PDC_EnableRx(rx_pdc); -	AT91F_SSC_EnableRx(AT91C_BASE_SSC); -	 -	/* Clear the flipflop */ -	tc_cdiv_sync_reset(); -} - -void ssc_rx_stop(void) -{ -	/* Disable reception */ -	AT91F_SSC_DisableRx(AT91C_BASE_SSC); -	AT91F_PDC_DisableRx(rx_pdc); -	AT91F_SSC_DisableIt(ssc, SSC_RX_IRQ_MASK); -	__ssc_tx_unload_all(NULL, NULL); -} - -void ssc_tx_init(void) -{ -	/* IMPORTANT: Disable PA23 (PWM0) output, since it is connected to  -	 * PA17 !! */ -	AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_MOD_PWM); -	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, OPENPICC_MOD_SSC |  -			    OPENPICC_SSC_CLOCK | OPENPICC_SSC_TF, 0); -#ifdef USE_SSC_TX_TF_WORKAROUND -	AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_TF); -	pio_irq_register(OPENPICC_SSC_TF, ssc_tf_irq); -#endif -	 -	tx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR); -} - -void ssc_set_data_gate(int enable) -{ -	if(! OPENPICC->features.clock_gating) return; -	if(enable) -		AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); -	else -		AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); -} - -void ssc_rx_init() -{  -	tc_cdiv_sync_init(); -	tc_cdiv_sync_enable(); -	 -	if(ssc_rx_queue == NULL) -		ssc_rx_queue = xQueueCreate(10, sizeof(ssc_state.buffer[0])); - -	rx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR); - -	AT91F_SSC_CfgPMC(); - -	AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,  -			    OPENPICC_SSC_DATA | OPENPICC_SSC_CLOCK | -			    OPENPICC_PIO_FRAME, -			    0); -	 -	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); -	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); -	 -	if(OPENPICC->features.clock_gating) { -		AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); -		AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC->DATA_GATE); -	} - -	AT91F_AIC_ConfigureIt(AT91C_ID_SSC, -			      OPENPICC_IRQ_PRIO_SSC, -			      AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq); - -	/* don't divide clock inside SSC, we do that in tc_cdiv */ -	ssc->SSC_CMR = 0; - -#if 0 -	ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | -			AT91C_SSC_CKI | AT91C_SSC_START_CONTINOUS; -	/* Data bits per Data N = 32-1 -	 * Data words per Frame = 15-1 (=60 byte)*/ -	ssc->SSC_RFMR = 31 | AT91C_SSC_MSBF | (14 << 8); -#endif -	 -	ssc_rx_mode_set(SSC_MODE_NONE); -	ssc_state.buffer[0] = ssc_state.buffer[1] = NULL; -	 -#if 0 -	AT91F_PDC_EnableRx(rx_pdc); - -	/* Enable RX interrupts */ -	AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN | -			   AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF); -#endif -	/* Will be set to a real value some time later */ -	tc_fdt_set(0xff00); - -	AT91F_AIC_EnableIt(AT91C_ID_SSC); - -	//usb_hdlr_register(&ssc_usb_in, OPENPCD_CMD_CLS_SSC); - -	DEBUGP("\r\n"); -} - -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); -	AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC,  -				 ((unsigned int) 1 << AT91C_ID_SSC)); -} diff --git a/openpicc/application/ssc_picc.h b/openpicc/application/ssc_picc.h deleted file mode 100644 index 3b6182a..0000000 --- a/openpicc/application/ssc_picc.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _SSC_H -#define _SSC_H - -#include "queue.h" -#include "iso14443_layer3a.h" - -extern void ssc_rx_start(void); -extern void ssc_rx_stop(void); - -/* Rx/Tx initialization separate, since Tx disables PWM output ! */ -extern void ssc_tx_init(void); -extern void ssc_rx_init(void); - -extern void ssc_fini(void); -extern void ssc_rx_stop(void); -extern void ssc_rx_unthrottle(void); -extern void __ramfunc ssc_rx_stop_frame_ended(void); - - -enum ssc_mode { -	SSC_MODE_NONE, -	SSC_MODE_14443A_SHORT, -	SSC_MODE_14443A_STANDARD, -	SSC_MODE_14443A, -	SSC_MODE_14443B, -	SSC_MODE_EDGE_ONE_SHOT, -	SSC_MODE_CONTINUOUS, -}; - -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); - -/* These are various SSC performance metrics that can be queried */ -typedef enum { -	OVERFLOWS,     /* Overflows (e.g. no free buffer when reloading DMA controller) */ -	BUFFER_ERRORS, /* Internal buffer management errors */ -	FREE_BUFFERS,  /* Free RX buffers */ -	LATE_FRAMES,   /* Frames that were not ready to be sent when the FDT passed; e.g. sent too late */ -	SSC_ERRORS,    /* General error count, e.g. OVERFLOWS + BUFFER_ERRORS */ -} ssc_metric; -extern int ssc_get_metric(ssc_metric metric); - -#define SSC_RX_BUFFER_SIZE 2048 -#define SSC_DMA_BUFFER_COUNT 4 - -#if SSC_RX_BUFFER_SIZE < ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS -#undef SSC_RX_BUFFER_SIZE -#define SSC_RX_BUFFER_SIZE ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS -#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_dma_buffer_state_t; - -typedef struct { -	enum ssc_mode mode; -	u_int16_t transfersize_ssc; -	u_int16_t transfersize_pdc; -	u_int16_t transfers; -} ssc_mode_def; - -typedef struct { -	volatile ssc_dma_buffer_state_t state; -	u_int32_t len_transfers;  /* Length of the content, in transfers */ -	const ssc_mode_def *reception_mode; /* Pointer to the SSC mode definition that the buffer has been loaded for (affects element size and count) */ -	u_int8_t data[SSC_RX_BUFFER_SIZE]; -} ssc_dma_rx_buffer_t; - -extern xQueueHandle ssc_rx_queue; - -/* in bytes, used for the sample buffer that holds the subcarrier modulation data at fc/8 = 1695 MHz */ -#define SSC_TX_BUFFER_SIZE ((MAXIMUM_FRAME_SIZE*( (8+1)*2 ) ) + 2 + 2) - -typedef struct { -	volatile ssc_dma_buffer_state_t state; -	u_int32_t len;  /* Length of the content */ -	void *source; /* Source pointer for a prefilled buffer; set to NULL if not used */ -	u_int8_t data[SSC_TX_BUFFER_SIZE]; -} ssc_dma_tx_buffer_t; - -/* Declare one TX buffer. This means that only one buffer can ever be pending for sending. That's because - * this buffer must be huge (one frame of 256 bytes of subcarrier modulation data at  1695 MHz sample - * 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); -extern volatile u_int32_t ssc_tx_fiq_fdt_cdiv; -extern volatile u_int32_t ssc_tx_fiq_fdt_ssc; - -extern void ssc_set_data_gate(int enable); - -#endif diff --git a/openpicc/application/tc_fdt.c b/openpicc/application/tc_fdt.c index 2a306ef..3e4023e 100644 --- a/openpicc/application/tc_fdt.c +++ b/openpicc/application/tc_fdt.c @@ -40,7 +40,7 @@  #include "tc_cdiv.h"  #include "tc_fdt.h"  #include "usb_print.h" -#include "ssc_picc.h" +#include "ssc.h"  #include "cmd.h"  static AT91PS_TC tcfdt = AT91C_BASE_TC2; @@ -59,12 +59,19 @@ int tc_fdt_get_next_slot(int reference_time, int slotlen)  } -/* 'count' number of carrier cycles after the last modulation pause,  - * we deem the frame to have ended */ -void tc_frame_end_set(u_int16_t count) -{ -	tcfdt->TC_RB = count; -} +static const struct { char* name; u_int32_t flag;} flags[] = { +		{ "MTIOB", AT91C_TC_MTIOB }, +		{ "MTIOA", AT91C_TC_MTIOA }, +		{ "CLKSTA", AT91C_TC_CLKSTA }, +		{ "ETRGS", AT91C_TC_ETRGS }, +		{ "LDRBS", AT91C_TC_LDRBS }, +		{ "LDRAS", AT91C_TC_LDRAS }, +		{ "CPCS", AT91C_TC_CPCS }, +		{ "CPBS", AT91C_TC_CPBS }, +		{ "CPAS", AT91C_TC_CPAS }, +		{ "LOVRS", AT91C_TC_LOVRS }, +		{ "COVFS", AT91C_TC_COVFS }, +};  static void __ramfunc tc_fdt_irq(void) __attribute__ ((naked));  static void __ramfunc tc_fdt_irq(void) @@ -74,22 +81,18 @@ static void __ramfunc tc_fdt_irq(void)  	u_int32_t sr = tcfdt->TC_SR;  	DEBUGP("tc_fdt_irq: TC2_SR=0x%08x TC2_CV=0x%08x ",   		sr, tcfdt->TC_CV); - +	  	if (sr & AT91C_TC_ETRGS) {  		DEBUGP("Ext_trigger ");  	}  	if (sr & AT91C_TC_CPAS) {  		DEBUGP("FDT_expired ");  	} -	if (sr & AT91C_TC_CPBS) { -	usb_print_string_f("tc_cpbs ", 0); -		DEBUGP("Frame_end "); -		ssc_rx_stop_frame_ended(); -	}  	if (sr & AT91C_TC_CPCS) {  		DEBUGP("Compare_C ");  	}  	DEBUGPCR(""); +	AT91F_AIC_ClearIt(AT91C_ID_TC2);  	AT91F_AIC_AcknowledgeIt();  	//vLedSetGreen(0);  	portRESTORE_CONTEXT(); @@ -113,9 +116,6 @@ void tc_fdt_init(void)  	/* Enable Clock for TC2 */  	tcfdt->TC_CCR = AT91C_TC_CLKEN; -	tcfdt->TC_RC = 0xffff; -	tc_frame_end_set(128*2); -  	/* Clock XC1, Wave Mode, No automatic reset on RC comp  	 * TIOA2 in RA comp = set, TIOA2 on RC comp = clear,  	 * TIOA2 on EEVT = clear, TIOA2 on SWTRG = clear, @@ -128,14 +128,17 @@ void tc_fdt_init(void)  		      AT91C_TC_EEVT_TIOB | AT91C_TC_ETRGEDG_FALLING |  		      AT91C_TC_ENETRG | AT91C_TC_CPCSTOP ; +	tcfdt->TC_RC = 0xffff; +  	/* Reset to start timers */  	tcb->TCB_BCR = 1;  	AT91F_AIC_ConfigureIt(AT91C_ID_TC2,  			      OPENPCD_IRQ_PRIO_TC_FDT,  			      AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&tc_fdt_irq); +	tcfdt->TC_IER = AT91C_TC_CPAS | AT91C_TC_CPCS |  +			AT91C_TC_ETRGS; +	AT91F_AIC_ClearIt(AT91C_ID_TC2);  	AT91F_AIC_EnableIt(AT91C_ID_TC2); -	tcfdt->TC_IER = AT91C_TC_CPAS | AT91C_TC_CPBS | AT91C_TC_CPCS |  -			AT91C_TC_ETRGS;  } diff --git a/openpicc/application/usb_print.c b/openpicc/application/usb_print.c index ccde7de..5ff42b8 100644 --- a/openpicc/application/usb_print.c +++ b/openpicc/application/usb_print.c @@ -114,7 +114,7 @@ void usb_print_flush(void)  	taskEXIT_CRITICAL();  	while(newstart != oldstop) { -		vUSBSendByte(ringbuffer[newstart]); +		vUSBSendByte_blocking(ringbuffer[newstart], 5*portTICK_RATE_MS);  		newstart = (newstart+1) % BUFLEN;  	} | 
