From 6be69f0de0c5455758c7ab3a6a3c7d37a061e5fa Mon Sep 17 00:00:00 2001
From: henryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>
Date: Sat, 9 Feb 2008 17:49:39 +0000
Subject: Commit a first version of an iso 14443 layer 2 and a passive sniffer.
 Works for short frames, and sometimes even for long frames. Pending some
 major cleanup

git-svn-id: https://svn.openpcd.org:2342/trunk@408 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
---
 openpicc/application/iso14443_layer2a.c | 172 ++++++++++++++++++++++++++++++++
 openpicc/application/iso14443_layer2a.h |  77 ++++++++++++++
 openpicc/application/iso14443_layer3a.c |   2 +-
 openpicc/application/iso14443_sniffer.c | 109 ++++++++++++++++++++
 openpicc/application/iso14443_sniffer.h |   6 ++
 openpicc/application/main.c             |   5 +-
 openpicc/application/ssc_picc.c         |  62 ++++--------
 7 files changed, 387 insertions(+), 46 deletions(-)
 create mode 100644 openpicc/application/iso14443_layer2a.c
 create mode 100644 openpicc/application/iso14443_layer2a.h
 create mode 100644 openpicc/application/iso14443_sniffer.c
 create mode 100644 openpicc/application/iso14443_sniffer.h

(limited to 'openpicc/application')

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);
-- 
cgit v1.2.3