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