summaryrefslogtreecommitdiff
path: root/openpicc
diff options
context:
space:
mode:
authorhenryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2008-02-29 08:53:20 +0000
committerhenryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2008-02-29 08:53:20 +0000
commitad5b96d584fc9962a9d8504067cd59697fb9a580 (patch)
treea79230629a87dfbb65603d806467499ec632e4e8 /openpicc
parent4b03b310ffda11b017ce5166012a7139b09eee90 (diff)
New cleaned-up (and then messed up again) SSC code
Better layering separation git-svn-id: https://svn.openpcd.org:2342/trunk@434 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpicc')
-rw-r--r--openpicc/Makefile4
-rw-r--r--openpicc/application/cmd.c98
-rw-r--r--openpicc/application/iso14443_layer2a.c96
-rw-r--r--openpicc/application/iso14443_layer2a.h5
-rw-r--r--openpicc/application/iso14443_layer3a.h88
-rw-r--r--openpicc/application/iso14443_sniffer.c10
-rw-r--r--openpicc/application/iso14443a_miller.c2
-rw-r--r--openpicc/application/main.c153
-rw-r--r--openpicc/application/openpicc.h1
-rw-r--r--openpicc/application/ssc.c599
-rw-r--r--openpicc/application/ssc.h53
-rw-r--r--openpicc/application/ssc_buffer.h46
-rw-r--r--openpicc/application/ssc_picc.c731
-rw-r--r--openpicc/application/ssc_picc.h105
-rw-r--r--openpicc/application/tc_fdt.c39
-rw-r--r--openpicc/application/usb_print.c2
-rw-r--r--openpicc/os/usb/USB-CDC.c8
-rw-r--r--openpicc/os/usb/USB-CDC.h1
18 files changed, 943 insertions, 1098 deletions
diff --git a/openpicc/Makefile b/openpicc/Makefile
index 73c1c72..b60ca00 100644
--- a/openpicc/Makefile
+++ b/openpicc/Makefile
@@ -84,13 +84,12 @@ ARM_SRC= \
application/adc.c \
application/pll.c \
application/pio_irq.c \
- application/ssc_picc.c \
+ application/ssc.c \
application/tc_cdiv_sync.c \
application/tc_fdt.c \
application/tc_cdiv.c \
application/usb_print.c \
application/iso14443_layer2a.c \
- application/iso14443_layer3a.c \
application/iso14443_sniffer.c \
application/iso14443a_manchester.c \
application/iso14443a_miller.c \
@@ -108,6 +107,7 @@ ARM_SRC= \
os/core/MemMang/heap_2.c \
os/usb/USB-CDC.c \
os/usb/USBIsr.c
+# application/iso14443_layer3a.c
#
# Define all object files.
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;
}
diff --git a/openpicc/os/usb/USB-CDC.c b/openpicc/os/usb/USB-CDC.c
index 13435b4..1b840c9 100644
--- a/openpicc/os/usb/USB-CDC.c
+++ b/openpicc/os/usb/USB-CDC.c
@@ -262,11 +262,17 @@ vUSBCDCTask (void *pvParameters)
void
vUSBSendByte (portCHAR cByte)
{
+ vUSBSendByte_blocking(cByte, usbNO_BLOCK);
+}
+
+void
+vUSBSendByte_blocking (portCHAR cByte, portTickType xTicksToWait)
+{
char chunk[CHUNK_SIZE];
chunk[0] = 1;
chunk[1] = cByte;
/* Queue the byte to be sent. The USB task will send it. */
- xQueueSend (xTxCDC, &chunk, usbNO_BLOCK);
+ xQueueSend (xTxCDC, &chunk, xTicksToWait);
}
#define MIN(a,b) ((a)>(b)?(b):(a))
diff --git a/openpicc/os/usb/USB-CDC.h b/openpicc/os/usb/USB-CDC.h
index 511c8a8..6074956 100644
--- a/openpicc/os/usb/USB-CDC.h
+++ b/openpicc/os/usb/USB-CDC.h
@@ -82,6 +82,7 @@ void vUSBCDCTask (void *pvParameters);
/* Send cByte down the USB port. Characters are simply buffered and not
sent unless the port is connected. */
void vUSBSendByte (portCHAR cByte);
+void vUSBSendByte_blocking (portCHAR cByte, portTickType xTicksToWait);
void vUSBSendBuffer (unsigned char *buffer, portBASE_TYPE offset, portBASE_TYPE length);
portLONG vUSBRecvByte (portCHAR *cByte,portLONG size, portTickType xTicksToWait);
personal git repositories of Harald Welte. Your mileage may vary