diff options
Diffstat (limited to 'openpicc/application')
| -rw-r--r-- | openpicc/application/iso14443_layer2a.c | 172 | ||||
| -rw-r--r-- | openpicc/application/iso14443_layer2a.h | 77 | ||||
| -rw-r--r-- | openpicc/application/iso14443_layer3a.c | 2 | ||||
| -rw-r--r-- | openpicc/application/iso14443_sniffer.c | 109 | ||||
| -rw-r--r-- | openpicc/application/iso14443_sniffer.h | 6 | ||||
| -rw-r--r-- | openpicc/application/main.c | 5 | ||||
| -rw-r--r-- | openpicc/application/ssc_picc.c | 62 | 
7 files changed, 387 insertions, 46 deletions
diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c new file mode 100644 index 0000000..b91b67c --- /dev/null +++ b/openpicc/application/iso14443_layer2a.c @@ -0,0 +1,172 @@ +/*************************************************************** + * + * OpenPICC - ISO 14443 Layer 2 Type A PICC transceiver code + * Manages receiving, sending and parts of framing + *  + * This does not fully implement layer 2 in that it won't  + * automatically call the Miller decoder or Manchester encoder + * for you. Instead you'll be given ssc rx buffer pointers and + * are expected to hand in ssc tx buffer pointers. You've got + * to call iso14443a_manchester and iso14443a_miller yourself. + * The reason is that this makes it possible for the layer 3 + * implementation to work on raw samples without en/de-coding + * time to enable fast responses during anticollision. + * + * Copyright 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; version 2. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License along +    with this program; if not, write to the Free Software Foundation, Inc., +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*/ + +#include <FreeRTOS.h> +#include <board.h> +#include <task.h> +#include <errno.h> + +#include "openpicc.h" +#include "iso14443_layer2a.h" +#include "ssc_picc.h" +#include "pll.h" +#include "tc_fdt.h" +#include "tc_cdiv.h" +#include "tc_cdiv_sync.h" +#include "load_modulation.h" + +static u_int8_t fast_receive; +static volatile u_int8_t receiving = 0; + +#ifdef FOUR_TIMES_OVERSAMPLING +#define RX_DIVIDER 32 +#else +#define RX_DIVIDER 64 +#endif + +int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t **buffer, unsigned int timeout) +{ +	int was_receiving = receiving; +	(void)callback; +	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(_buffer == NULL) { +			/* Can this happen? */ +			return -ETIMEDOUT; +		} +		 +		portENTER_CRITICAL(); +		_buffer->state = PROCESSING; +		portEXIT_CRITICAL(); +		 +		len = _buffer->len_transfers; +		 +		if(buffer != NULL) *buffer = _buffer; +		else { +			portENTER_CRITICAL(); +			_buffer->state = FREE; +			portEXIT_CRITICAL(); +		} +		 +		return len; +	} +	 +	if(!was_receiving) +		iso14443_l2a_rx_stop(); +	 +	return -ETIMEDOUT; +} + +int iso14443_wait_for_carrier(unsigned int timeout) +{ +	(void)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; +	fast_receive = enable_fast_receive; +	return old_value; +} + +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) +{ +	(void) ssc_mode; (void) samples; +	if( (ssc_sr & AT91C_SSC_CP1) && receiving) { +		tc_fdt_set(0xff00); +		tc_cdiv_set_divider(RX_DIVIDER); +		tc_cdiv_sync_reset(); +	} +} + +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); +	return 0; +} diff --git a/openpicc/application/iso14443_layer2a.h b/openpicc/application/iso14443_layer2a.h new file mode 100644 index 0000000..abe019a --- /dev/null +++ b/openpicc/application/iso14443_layer2a.h @@ -0,0 +1,77 @@ +#ifndef ISO14443_LAYER2A_H_ +#define ISO14443_LAYER2A_H_ + +#include "ssc_picc.h" + +/* Callback type for iso14443_receive(). + * Parameter buffer is being passed a pointer to an SSC Rx buffer structure that this receive happened + * on. You might want to pass this into iso14443a_decode_miller(). + * Parameter in_irq is true if the callback has been called while still in IRQ mode. It must then *NOT* + * perform any calls that might upset the IRQ processing. Especially it may not call into FreeRTOS or + * any parts of the applications that do. + */ +typedef void (*iso14443_receive_callback_t)(ssc_dma_rx_buffer_t *buffer, u_int8_t in_irq); + +/* Wait for and receive a frame. Parameters callback and buffer are optional. If you omit them you'll lose + * the received frame, obviously. + * Parameter callback is a callback function that will be called for each received frame and might + * then trigger a response. + * Parameter buffer is an output pointer to a pointer to an SSC Rx buffer structure containing the + * received frame. + * Parameter timeout gives an optional timeout for the receive operation after which the receive will + * be aborted. When timeout is 0 the receive will not time out. + * This call will block until a frame is received or an exception happens. Obviously it must not be run + * from IRQ context. + *  + * Warning: When you get a buffer from the function then it's state is set to PROCESSING and you must  + * FREE it yourself. + *  + * Return values: + * >= 0        Frame received, return value is buffer length (yes, 0 is a valid buffer length) + * -ENETDOWN   PLL is not locked or PLL lock lost + * -ETIMEDOUT  Receive timed out without receiving anything (usually not regarded an error condition) + * -EBUSY      A Tx is currently running or pending; can't receive + * -EALREADY   There's already an iso14443_receive() invocation running + */ +extern int iso14443_receive(iso14443_receive_callback_t callback, ssc_dma_rx_buffer_t **buffer, unsigned int timeout); + +/* + * Transmit a frame. Starts transmitting fdt carrier cycles after the end of the received frame. + * Parameters buffer and fdt specify the SSC Tx buffer to be sent and the frame delay time in carrier cycles. + * When parameter async is set then this call will only schedule the buffer for sending and return immediately, + * otherwise the call will block until the buffer has been sent completely, until the specified timeout is reached + * or an error occurs. + * This function may be run from IRQ context, especially from within the iso14443_receive callback, with the async + * parameter set. + *  + * Note: When your callback calls iso14443_transmit() from IRQ context it must set the async parameter to have transmit + * return immediately and then not block within the callback. When the scheduled transmission has not happened by the next + * time you call iso14443_receive() it will abort with -EBUSY and you can then either decide to wait for the transmission + * to go through, or abort the scheduled transmission with iso14443_tx_abort(). You can check for whether a Tx is currently + * pending or running with iso14443_tx_busy(). + */ +extern int iso14443_transmit(ssc_dma_tx_buffer_t *buffer, unsigned int fdt, u_int8_t async, unsigned int timeout); + +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. + */ +extern int iso14443_wait_for_carrier(unsigned int timeout); + +/* Initialize the layer 2 transceiver code. + * Parameter enable_fast_receive, when set, will enable special code to guarantee fast response times + * for frames shorter than or equal to 56 data bits (bit oriented anticollision frame length). This + * generally involves running the callback from an IRQ handler.  + */ +extern int iso14443_layer2a_init(u_int8_t enable_fast_receive); + +extern u_int8_t iso14443_set_fast_receive(u_int8_t enable_fast_receive); +extern u_int8_t iso14443_get_fast_receive(void); + +#endif /*ISO14443_LAYER2A_H_*/ diff --git a/openpicc/application/iso14443_layer3a.c b/openpicc/application/iso14443_layer3a.c index fdb6836..daac8dd 100644 --- a/openpicc/application/iso14443_layer3a.c +++ b/openpicc/application/iso14443_layer3a.c @@ -78,7 +78,7 @@ const u_int8_t ISO14443A_SHORT_FRAME_WUPA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH]  #define INITIAL_FRAME NULL_FRAME  #endif -#if 0 +#if 1  #define SHORT_MODE SSC_MODE_14443A_SHORT  #define STANDARD_MODE SSC_MODE_14443A_STANDARD  #else diff --git a/openpicc/application/iso14443_sniffer.c b/openpicc/application/iso14443_sniffer.c new file mode 100644 index 0000000..d5cf9c2 --- /dev/null +++ b/openpicc/application/iso14443_sniffer.c @@ -0,0 +1,109 @@ +/*************************************************************** + * + * OpenPICC - ISO 14443 Layer 2 Type A Sniffer + * Also serves as PoC code for iso14443_layer2a usage + * + * Copyright 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; version 2. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License along +    with this program; if not, write to the Free Software Foundation, Inc., +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*/ + +#include <FreeRTOS.h> +#include <board.h> +#include <task.h> +#include <errno.h> + +#include "openpicc.h" +#include "iso14443_sniffer.h" +#include "iso14443_layer2a.h" +#include "iso14443a_miller.h" +#include "usb_print.h" +#include "cmd.h" + +static iso14443_frame rx_frame; + +void iso14443_sniffer (void *pvParameters) +{ +	(void)pvParameters; +	int res; +	 +	/* Delay until USB print etc. are ready */ +	vTaskDelay(1000 * portTICK_RATE_MS); +	 +	do { +		res = iso14443_layer2a_init(0); +		if(res < 0) { +			usb_print_string("Sniffer: Initialization failed\n\r"); +			vTaskDelay(10000 * portTICK_RATE_MS); +		} +	} while(res < 0); +	 +	usb_print_string("Waiting for carrier. "); +	while(iso14443_wait_for_carrier(1000 * portTICK_RATE_MS) != 0) { +	} +	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) { +			DumpStringToUSB("\n\r"); +			DumpTimeToUSB(xTaskGetTickCount()); +			usb_print_string(": Frame received, consists of "); +			DumpUIntToUSB(res); +			usb_print_string(" transfers ("); +			DumpUIntToUSB(buffer->reception_mode->transfersize_ssc); +			usb_print_string(" bits from SSC each)\n\r                  "); +			if(buffer->len_transfers < 200) +				DumpBufferToUSB((char*)buffer->data, (buffer->len_transfers * buffer->reception_mode->transfersize_pdc)/8); +			else { +				DumpBufferToUSB((char*)buffer->data, (200 * buffer->reception_mode->transfersize_pdc)/8); +				usb_print_string("..."); +			} +			usb_print_string("\n\r                  "); +			 +			iso14443a_decode_miller(&rx_frame, buffer); +			 +			usb_print_string("Decodes to "); +			DumpUIntToUSB(rx_frame.numbytes); +			usb_print_string(" bytes and "); +			DumpUIntToUSB(rx_frame.numbits); +			usb_print_string(" bits:  "); +			DumpBufferToUSB((char*)rx_frame.data, rx_frame.numbytes + (rx_frame.numbits+7)/8 ); +			usb_print_string("\n\r"); +			 +			portENTER_CRITICAL(); +			buffer->state = FREE; +			portEXIT_CRITICAL(); +		} else { +			if(res != -ETIMEDOUT) { +				usb_print_string("Receive error: "); +				switch(res) { +					case -ENETDOWN:   usb_print_string("PLL is not locked or PLL lock lost\n\r"); break; +					case -EBUSY:      usb_print_string("A Tx is currently running or pending, can't receive\n\r"); break; +					case -EALREADY:   usb_print_string("There's already an iso14443_receive() invocation running\n\r"); break; +				} +				vTaskDelay(1000 * portTICK_RATE_MS); // FIXME Proper error handling, e.g. wait for Tx end in case of EBUSY +			} else if(0) { +				DumpStringToUSB("\n\r"); +				DumpTimeToUSB(xTaskGetTickCount()); +				usb_print_string(": -- Mark --"); +			} +		} +	} +} diff --git a/openpicc/application/iso14443_sniffer.h b/openpicc/application/iso14443_sniffer.h new file mode 100644 index 0000000..59a406a --- /dev/null +++ b/openpicc/application/iso14443_sniffer.h @@ -0,0 +1,6 @@ +#ifndef ISO14443_SNIFFER_H_ +#define ISO14443_SNIFFER_H_ + +extern void iso14443_sniffer (void *pvParameters); + +#endif /*ISO14443_SNIFFER_H_*/ diff --git a/openpicc/application/main.c b/openpicc/application/main.c index 38a08b5..1125153 100644 --- a/openpicc/application/main.c +++ b/openpicc/application/main.c @@ -48,6 +48,7 @@  #include "tc_fdt.h"  #include "usb_print.h"  #include "iso14443_layer3a.h" +#include "iso14443_sniffer.h"  #include "decoder.h"  /**********************************************************************/ @@ -173,7 +174,9 @@ int main (void)      /*xTaskCreate (vMainTestSSCRXConsumer, (signed portCHAR *) "SSC_CONSUMER", TASK_USB_STACK,  	NULL, TASK_USB_PRIORITY, NULL);*/ -    xTaskCreate (iso14443_layer3a_state_machine, (signed portCHAR *) "ISO14443A-3", TASK_ISO_STACK, +    /*xTaskCreate (iso14443_layer3a_state_machine, (signed portCHAR *) "ISO14443A-3", TASK_ISO_STACK, +	NULL, TASK_ISO_PRIORITY, NULL);*/ +    xTaskCreate (iso14443_sniffer, (signed portCHAR *) "ISO14443-SNIFF", TASK_ISO_STACK,  	NULL, TASK_ISO_PRIORITY, NULL);      xTaskCreate (vUSBCDCTask, (signed portCHAR *) "USB", TASK_USB_STACK, diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c index dd3cb02..1eabeb2 100644 --- a/openpicc/application/ssc_picc.c +++ b/openpicc/application/ssc_picc.c @@ -167,6 +167,7 @@ static int __ramfunc __ssc_rx_load(int secondary)  		 * 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;  		 } @@ -260,6 +261,7 @@ static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary)  		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; @@ -370,7 +372,7 @@ void ssc_rx_mode_set(enum ssc_mode ssc_mode)  			//| AT91C_SSC_MSBF  			;  	ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE |  -			clock_gating | AT91C_SSC_CKI | start_cond | (stop << 12); +			clock_gating | (0&AT91C_SSC_CKI) | start_cond | (stop << 12);  	/* Enable Rx DMA */  	AT91F_PDC_EnableRx(rx_pdc); @@ -488,8 +490,6 @@ static void __ramfunc ssc_irq(void)  	u_int32_t ssc_sr = ssc->SSC_SR;  	u_int32_t orig_ssc_sr = 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); @@ -499,7 +499,7 @@ static void __ramfunc ssc_irq(void)  		 * irq is raised. (The scheduler masks interrupts for about 56us,  		 * which is too much for anticollision.) */  		 int i = 0; -		 vLedBlinkRed(); +		 //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 */ @@ -508,55 +508,29 @@ static void __ramfunc ssc_irq(void)  		 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)) { -#if 0 -// Bitrotten -		/* Ignore empty frames */ -		if (ssc_state.mode == SSC_MODE_CONTINUOUS) { -			/* This code section is probably bitrotten by now. */ -			tmp = (u_int32_t*)ssc_state.buffer[0]->data; -			emptyframe = 1; -			for(i = (ssc_state.buffer[0]->len) / 4 - 8/*WTF?*/; i > 0; i--) { -				if( *tmp++ != 0x0 ) { -					DEBUGPCR("NONEMPTY(%08x, %i): %08x", tmp, i, *(tmp-1)); -					emptyframe = 0; -					break; -				} else { -					//DEBUGPCR("DUNNO(%08x, %i): %08x", tmp, i, tmp[i]); -				} -			} -		} -#else -		(void)i; -		(void)tmp; -#endif -		//DEBUGP("Sending primary RCTX(%u, len=%u) ", req_ctx_num(ssc_state.rx_ctx[0]), ssc_state.rx_ctx[0]->tot_len); -		/* Mark primary RCTX as ready to send for usb */ -		if(!emptyframe) { -			//unsigned int i; -			DEBUGP("NONEMPTY"); -			//gaportENTER_CRITICAL(); -			ssc_state.buffer[0]->state = FULL; -			//gaportEXIT_CRITICAL(); -			task_woken = xQueueSendFromISR(ssc_rx_queue, &ssc_state.buffer[0], task_woken); -		} else { -			DEBUGP("EMPTY"); -			//gaportENTER_CRITICAL(); -			ssc_state.buffer[0]->state = FREE; -			//gaportEXIT_CRITICAL();			 +		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); - -		inbuf = ssc_state.buffer[0]; +		  		if(ssc_sr & AT91C_SSC_ENDRX) { -			/* second buffer gets propagated to primary */ +			/* 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 || (ssc_state.mode == SSC_MODE_14443A && ssc_sr & AT91C_SSC_CP1)) { +			|| ssc_state.mode == SSC_MODE_14443A_STANDARD) {  			// Stop sampling here  			ssc_rx_stop();  		} else { @@ -576,7 +550,7 @@ static void __ramfunc ssc_irq(void)  							    AT91C_SSC_OVRUN);  			} -			if(ssc_sr & AT91C_SSC_RXENA) if (__ssc_rx_load(1) == -1) +			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);  | 
