summaryrefslogtreecommitdiff
path: root/openpicc
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc')
-rw-r--r--openpicc/Makefile2
-rw-r--r--openpicc/application/clock_switch.c53
-rw-r--r--openpicc/application/clock_switch.h7
-rw-r--r--openpicc/application/cmd.c5
-rw-r--r--openpicc/application/iso14443.h1
-rw-r--r--openpicc/application/iso14443_layer2a.c10
-rw-r--r--openpicc/application/iso14443a_diffmiller.c346
-rw-r--r--openpicc/application/iso14443a_diffmiller.h12
-rw-r--r--openpicc/application/iso14443a_miller.c2
-rw-r--r--openpicc/application/iso14443a_pretender.c8
-rw-r--r--openpicc/application/ssc.c21
-rw-r--r--openpicc/application/ssc.h6
-rw-r--r--openpicc/application/tc_sniffer.c76
-rw-r--r--openpicc/config/board.c3
-rw-r--r--openpicc/config/board.h6
15 files changed, 523 insertions, 35 deletions
diff --git a/openpicc/Makefile b/openpicc/Makefile
index d826582..f0721c2 100644
--- a/openpicc/Makefile
+++ b/openpicc/Makefile
@@ -92,7 +92,9 @@ ARM_SRC= \
application/iso14443_layer2a.c \
application/iso14443a_manchester.c \
application/iso14443a_miller.c \
+ application/iso14443a_diffmiller.c \
application/load_modulation.c \
+ application/clock_switch.c \
application/decoder_miller.c \
application/decoder_nrzl.c \
application/decoder.c \
diff --git a/openpicc/application/clock_switch.c b/openpicc/application/clock_switch.c
new file mode 100644
index 0000000..16c1bf1
--- /dev/null
+++ b/openpicc/application/clock_switch.c
@@ -0,0 +1,53 @@
+/***************************************************************
+ *
+ * OpenPICC - clock switch driver
+ *
+ * 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 <openpicc.h>
+
+#include "clock_switch.h"
+
+static int initialized = 0;
+
+void clock_switch(enum clock_source clock)
+{
+ if(!OPENPICC->features.clock_switching) return;
+ if(!initialized)
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH);
+
+ 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;
+ }
+}
+
+void clock_switch_init(void)
+{
+ if(!OPENPICC->features.clock_switching) return;
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH);
+ clock_switch(OPENPICC->default_clock);
+ initialized = 1;
+}
diff --git a/openpicc/application/clock_switch.h b/openpicc/application/clock_switch.h
new file mode 100644
index 0000000..550b33a
--- /dev/null
+++ b/openpicc/application/clock_switch.h
@@ -0,0 +1,7 @@
+#ifndef CLOCK_SWITCH_H_
+#define CLOCK_SWITCH_H_
+
+extern void clock_switch(enum clock_source clock);
+extern void clock_switch_init(void);
+
+#endif /*CLOCK_SWITCH_H_*/
diff --git a/openpicc/application/cmd.c b/openpicc/application/cmd.c
index 50b59d3..5991694 100644
--- a/openpicc/application/cmd.c
+++ b/openpicc/application/cmd.c
@@ -19,6 +19,7 @@
#include "tc_cdiv_sync.h"
#include "pio_irq.h"
#include "ssc.h"
+#include "clock_switch.h"
#include "usb_print.h"
#include "load_modulation.h"
#include "tc_sniffer.h"
@@ -374,8 +375,8 @@ void prvExecCommand(u_int32_t cmd, portCHAR *args) {
DumpStringToUSB("* This hardware is not clock switching capable\n\r");
break;
}
- clock_select = (clock_select+1) % _MAX_CLOCK_SOURCES;
- ssc_select_clock(clock_select);
+ clock_select = (clock_select+1) % 2;
+ clock_switch(clock_select);
DumpStringToUSB("Active clock is now ");
DumpUIntToUSB(clock_select);
DumpStringToUSB("\n\r");
diff --git a/openpicc/application/iso14443.h b/openpicc/application/iso14443.h
index cc7a640..d3439d1 100644
--- a/openpicc/application/iso14443.h
+++ b/openpicc/application/iso14443.h
@@ -85,6 +85,7 @@ typedef struct {
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;
+ enum { CRC_UNCALCULATED = 2, CRC_OK = 1, CRC_ERROR = 0} crc;
} a;
} parameters;
u_int32_t numbytes;
diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c
index 65ca91e..3c55967 100644
--- a/openpicc/application/iso14443_layer2a.c
+++ b/openpicc/application/iso14443_layer2a.c
@@ -45,6 +45,7 @@
#include "tc_cdiv.h"
#include "tc_cdiv_sync.h"
#include "load_modulation.h"
+#include "clock_switch.h"
#include "pio_irq.h"
#include "usb_print.h"
@@ -129,7 +130,7 @@ int iso14443_transmit(ssc_dma_tx_buffer_t *buffer, unsigned int fdt, u_int8_t as
tx_pending = 1;
/* Immediately set up FDT and clock */
- ssc_select_clock(CLOCK_SELECT_CARRIER);
+ clock_switch(CLOCK_SELECT_CARRIER);
ssc_set_gate(0);
tc_fdt_set(fdt);
tc_cdiv_set_divider(8); // FIXME Magic hardcoded number
@@ -191,7 +192,7 @@ static void iso14443_ssc_callback(ssc_callback_reason reason, void *data)
}
if( reason == CALLBACK_RX_FRAME_ENDED && fast_receive ) {
- ssc_select_clock(CLOCK_SELECT_CARRIER); /* A Tx might be coming up */
+ clock_switch(CLOCK_SELECT_CARRIER); /* A Tx might be coming up */
ssc_dma_rx_buffer_t *buffer = data;
if(callback != NULL)
@@ -201,10 +202,10 @@ static void iso14443_ssc_callback(ssc_callback_reason reason, void *data)
if( (reason == CALLBACK_RX_FRAME_ENDED && !tx_pending) || reason == CALLBACK_RX_STARTING
|| reason == CALLBACK_TX_FRAME_ENDED ) {
/* For regular SSC Rx we'd set the clock to
- // ssc_select_clock(CLOCK_SELECT_PLL);
+ // clock_switch(CLOCK_SELECT_PLL);
* however, the SSC Rx code is going to go away (at least for 14443-A)
* and switching clocks messes up the Tx timing, so we do a */
- ssc_select_clock(CLOCK_SELECT_CARRIER);
+ clock_switch(CLOCK_SELECT_CARRIER);
ssc_set_gate(1);
tc_fdt_set(0xff00);
tc_cdiv_set_divider(RX_DIVIDER);
@@ -233,6 +234,7 @@ int iso14443_layer2a_init(u_int8_t enable_fast_receive)
tc_cdiv_init();
tc_fdt_init();
+ clock_switch_init();
load_mod_init();
iso14443_set_fast_receive(enable_fast_receive);
diff --git a/openpicc/application/iso14443a_diffmiller.c b/openpicc/application/iso14443a_diffmiller.c
new file mode 100644
index 0000000..85f9518
--- /dev/null
+++ b/openpicc/application/iso14443a_diffmiller.c
@@ -0,0 +1,346 @@
+/* ISO14443A Miller decoder for OpenPICC, working with differential time samples
+ *
+ * Copyright 2007 Milosch Meriac <meriac@bitmanufaktur.de>
+ * Copyright 2007 Karsten Nohl <honk98@web.de>
+ * Copyright 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
+ *
+ */
+
+#include <openpicc.h>
+#include <FreeRTOS.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iso14443.h"
+#include "iso14443a_diffmiller.h"
+#include "usb_print.h"
+
+#define DEBUGP (void)
+#define printf usb_print_string
+
+struct diffmiller_state {
+ int initialized, pauses_count;
+ iso14443_frame *frame;
+ u_int32_t counter;
+ u_int16_t byte,crc;
+ u_int8_t parity;
+ struct {
+ u_int8_t in_frame:1;
+ u_int8_t frame_finished:1;
+ u_int8_t overflow:1;
+ u_int8_t error:1;
+ } flags;
+};
+
+struct diffmiller_state _state;
+
+/*
+ * Decoding Methodology: We'll only see the edges for the start of modulation pauses and not
+ * all symbols generate modulation pauses at all. Two phases:
+ * + Old state and next edge delta to sequence of symbols (might be more than one symbol per edge)
+ * + Symbols to EOF/SOF marker and bits
+ *
+ * These are the possible old-state/delta combinations and the symbols they yield:
+ *
+ * old_state delta (in bit_len/4) symbol(s)
+ * none 3 ZZ
+ * none 5 ZX
+ * X 3 X
+ * X 5 YZ
+ * X 7 YX
+ * X >=9 YY
+ * Y 3 ZZ
+ * Y 5 ZX
+ * Z 3 Z
+ * Z 5 X
+ * Z >=7 Y
+ *
+ * All other combinations are invalid and likely en- or decoding errors. (Note that old_state
+ * Y is exactly the same as old_state none.)
+ *
+ * The mapping from symbol sequences to SOF/EOF/bit is as follows:
+ * X: 1
+ * 0, then Y: EOF
+ * other Y: 0
+ * first Z: SOF
+ * other Z: 0
+ */
+
+#define BIT_LEN 128
+/* The theoretical error margin for the timing measurement is about 7 (note: that is a jitter of 7 in
+ * total, e.g. +/- 3.5), but we'll round that up to +/- 8. However, the specification allows pause
+ * times from 2us to 3us, e.g. 1us difference, so we'll add another 13.
+ */
+#define BIT_LEN_ERROR_MAX (8+13)
+#define PAUSE_LEN 20
+/* Subtract the mean error margin (about 4, see comment above) from the bit length
+ * Also subtract the pause length for the case when the clock is not counting during
+ * a pause. Will subtract this length below for the when the clock *is* counting during
+ * pauses.
+ */
+#define BIT_OFFSET (-4 -PAUSE_LEN)
+#define BIT_LEN_3 ((BIT_LEN*3)/4 +BIT_OFFSET)
+#define BIT_LEN_5 ((BIT_LEN*5)/4 +BIT_OFFSET)
+#define BIT_LEN_7 ((BIT_LEN*7)/4 +BIT_OFFSET)
+#define BIT_LEN_9 ((BIT_LEN*9)/4 +BIT_OFFSET)
+
+#define ALMOST_EQUAL(a,b) ( abs(a-b) <= BIT_LEN_ERROR_MAX )
+#define MUCH_GREATER_THAN(a,b) ( a > (b+BIT_LEN_ERROR_MAX) )
+#define ALMOST_GREATER_THAN_OR_EQUAL(a,b) (a >= (b-BIT_LEN_ERROR_MAX))
+
+enum symbol {NO_SYM=0, sym_x, sym_y, sym_z};
+enum bit { BIT_ERROR, BIT_SOF, BIT_0, BIT_1, BIT_EOF };
+enum bit_length { out_of_range=0, len_3=1, len_5=2, len_7=3, len_9_or_greater=4 };
+const char *bit_length_descriptions[] = {
+ [out_of_range] = "OOR",
+ [len_3] = "3/4",
+ [len_5] = "5/4",
+ [len_7] = "7/4",
+ [len_9_or_greater] = ">=9/4",
+};
+#define NIENTE {NO_SYM, NO_SYM}
+
+struct decoder_table_entry { enum symbol first, second; };
+const struct decoder_table_entry decoder_table[][5] = {
+ /* out_of_range len_3 len_5 len_7 len_9_or_greater*/
+ [NO_SYM] = {NIENTE, {sym_z, sym_z}, {sym_z, sym_x}, },
+ [sym_x] = {NIENTE, {sym_x, NO_SYM}, {sym_y, sym_z}, {sym_y, sym_x}, {sym_y, sym_y}, },
+ [sym_y] = {NIENTE, {sym_z, sym_z}, {sym_z, sym_x}, },
+ [sym_z] = {NIENTE, {sym_z, NO_SYM}, {sym_x, NO_SYM}, {sym_y, NO_SYM}, {sym_y, NO_SYM}, },
+};
+
+int print_bits = 1;
+
+inline void start_frame(struct diffmiller_state * const state)
+{
+ state->counter=0;
+ state->byte=0;
+ state->parity=0;
+ state->crc=0x6363;
+
+ memset(&state->flags, 0, sizeof(state->flags));
+ state->flags.in_frame = 1;
+
+ memset(state->frame, 0, sizeof(*state->frame));
+}
+
+static inline void append_to_frame(struct diffmiller_state *const state,
+ const u_int8_t byte, const u_int8_t parity, const u_int8_t valid_bits) {
+
+ iso14443_frame * const f = state->frame;
+
+ if(f->numbytes >= sizeof(f->data)/sizeof(f->data[0])-1) { /* -1, because the last byte may be half filled */
+ state->flags.overflow = 1;
+ return;
+ }
+
+ if(f->numbits != 0) {
+ DEBUGP("Appending to a frame with incomplete byte");
+ }
+
+ f->data[f->numbytes] = byte & 0xff;
+ f->parity[f->numbytes/8] |= ((parity&1)<<(f->numbytes%8));
+
+ if(valid_bits == 8) {
+ f->numbytes++;
+ } else {
+ f->numbits += valid_bits;
+ }
+}
+
+
+static void end_frame(struct diffmiller_state * const state)
+{
+ if(state->frame != NULL) {
+ if(state->counter > 0) {
+ append_to_frame(state, state->byte, 0, state->counter);
+ }
+
+ if(!state->crc)
+ state->frame->parameters.a.crc = CRC_OK;
+ else
+ state->frame->parameters.a.crc = CRC_ERROR;
+
+ state->flags.frame_finished = 1;
+ }
+}
+
+static void Miller_Bit(struct diffmiller_state * const state, const enum bit bit)
+{
+ switch(bit) {
+ case BIT_SOF:
+ if(print_bits) printf("SOF");
+ start_frame(state);
+ break;
+ case BIT_0:
+ if(print_bits) printf(" 0");
+ break;
+ case BIT_1:
+ if(print_bits) printf(" 1");
+ break;
+ case BIT_EOF:
+ if(print_bits) printf(" EOF\n");
+ end_frame(state);
+ break;
+ default:
+ if(print_bits) printf(" ERROR\n");
+ state->flags.error = 1;
+ end_frame(state);
+ break;
+ }
+
+ int bit_value;
+ if(bit==BIT_0) bit_value = 0;
+ else if(bit==BIT_1) bit_value = 1;
+ else return;
+
+ if(state->counter<8) {
+ state->byte=state->byte | (bit_value<<state->counter);
+ if(bit_value)
+ state->parity++;
+ } else DEBUGP((((~state->parity)&1)==bit_value) ? " ":"!" );
+
+ if(++state->counter==9) {
+ state->counter=0;
+ append_to_frame(state, state->byte, bit_value, 8);
+
+ //DEBUGP(" ==0x%02X\n",byte);
+
+ state->byte=(state->byte ^ state->crc)&0xFF;
+ state->byte=(state->byte ^ state->byte<<4)&0xFF;
+ state->crc=((state->crc>>8)^(state->byte<<8)^(state->byte<<3)^(state->byte>>4))&0xFFFF;
+
+ //printf(" [%04X]\n",crc);
+
+ state->byte=0;
+ state->parity=0;
+ }
+}
+
+static void Miller_Symbol(struct diffmiller_state * const state, const enum symbol symbol)
+{
+ static enum bit last_bit = BIT_ERROR;
+ static int in_frame = 0;
+ enum bit bit = BIT_ERROR;
+
+ //DEBUGP("%c ", 'X'+(symbol-1));
+ if(!in_frame) {
+ if(symbol == sym_z)
+ bit = BIT_SOF;
+ else
+ bit = BIT_ERROR;
+ } else {
+ switch(symbol) {
+ case sym_y:
+ if(last_bit == BIT_0)
+ bit = BIT_EOF;
+ else
+ bit = BIT_0;
+ break;
+ case sym_x:
+ bit = BIT_1;
+ break;
+ case sym_z:
+ bit = BIT_0;
+ break;
+ default:
+ bit = BIT_ERROR;
+ break;
+ }
+ }
+
+ if(bit != BIT_EOF && last_bit == BIT_0)
+ Miller_Bit(state, last_bit);
+ if(bit != BIT_0) Miller_Bit(state, bit);
+
+ last_bit = bit;
+ if(bit==BIT_SOF) {
+ in_frame = 1;
+ last_bit = BIT_ERROR;
+ } else if(bit==BIT_EOF || bit==BIT_ERROR) {
+ in_frame = 0;
+ }
+
+}
+
+static void Miller_Edge(struct diffmiller_state * const state, const unsigned int delta)
+{
+ static enum symbol old_state = NO_SYM;
+ enum bit_length length = out_of_range;
+
+ if( ALMOST_EQUAL(delta, BIT_LEN_3) ) {
+ length = len_3;
+ } else if( ALMOST_EQUAL(delta, BIT_LEN_5) ) {
+ length = len_5;
+ } else if( ALMOST_EQUAL(delta, BIT_LEN_7) ) {
+ length = len_7;
+ } else if( ALMOST_GREATER_THAN_OR_EQUAL(delta, BIT_LEN_9)) {
+ length = len_9_or_greater;
+ }
+
+ const struct decoder_table_entry *entry;
+ entry = &decoder_table[old_state][length];
+ //DEBUGP(" %c{%i}[%s]", 'X'-sym_x+old_state, delta, bit_length_descriptions[length]);
+ if(entry->first != NO_SYM) {
+ //DEBUGP("%c ", 'X'-sym_x+entry->first);
+ Miller_Symbol(state, old_state = entry->first);
+ } else {
+ DEBUGP("! ");
+ }
+
+ if(entry->second != NO_SYM) {
+ //DEBUGP("%c ", 'X'-sym_x+entry->second);
+ Miller_Symbol(state, old_state = entry->second);
+ }
+}
+
+
+int iso14443a_decode_diffmiller(struct diffmiller_state * const state, iso14443_frame * const frame,
+ const u_int32_t buffer[], unsigned int * const offset, const unsigned int buflen)
+{
+ if(state == NULL || !state->initialized) return -EINVAL;
+ if(state->frame != NULL && state->frame != frame) return -EINVAL;
+ state->frame = frame;
+
+ for(; *offset < buflen; ) {
+ if(state->pauses_count)
+ Miller_Edge(state, buffer[(*offset)++] - PAUSE_LEN);
+ else
+ Miller_Edge(state, buffer[(*offset)++]);
+
+ if(state->flags.frame_finished) {
+ state->flags.frame_finished = 0;
+ return 0;
+ }
+ }
+
+ return -EBUSY;
+}
+
+struct diffmiller_state *iso14443a_init_diffmiller(int pauses_count)
+{
+ if(_state.initialized) return NULL;
+ struct diffmiller_state *state = &_state;
+ state->initialized = 1;
+ state->pauses_count = pauses_count;
+ state->frame = NULL;
+ state->flags.frame_finished = 0;
+
+ return state;
+}
diff --git a/openpicc/application/iso14443a_diffmiller.h b/openpicc/application/iso14443a_diffmiller.h
new file mode 100644
index 0000000..f5336d6
--- /dev/null
+++ b/openpicc/application/iso14443a_diffmiller.h
@@ -0,0 +1,12 @@
+#ifndef ISO14443A_DIFFMILLER_H_
+#define ISO14443A_DIFFMILLER_H_
+
+#include "iso14443.h"
+
+struct diffmiller_state;
+
+extern int iso14443a_decode_diffmiller(struct diffmiller_state *state, iso14443_frame *frame,
+ const u_int32_t buffer[], unsigned int *offset, const unsigned int buflen);
+extern struct diffmiller_state *iso14443a_init_diffmiller(int pauses_count);
+
+#endif /*ISO14443A_DIFFMILLER_H_*/
diff --git a/openpicc/application/iso14443a_miller.c b/openpicc/application/iso14443a_miller.c
index c902bb7..4e01d22 100644
--- a/openpicc/application/iso14443a_miller.c
+++ b/openpicc/application/iso14443a_miller.c
@@ -1,4 +1,4 @@
-/* ISO14443A Manchester encoder for OpenPICC
+/* ISO14443A Miller decoder for OpenPICC
* (C) 2007 by Henryk Plötz <henryk@ploetzli.ch>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/openpicc/application/iso14443a_pretender.c b/openpicc/application/iso14443a_pretender.c
index 9045f53..64112d1 100644
--- a/openpicc/application/iso14443a_pretender.c
+++ b/openpicc/application/iso14443a_pretender.c
@@ -42,7 +42,7 @@ extern volatile int fdt_offset;
static const iso14443_frame ATQA_FRAME = {
TYPE_A,
- {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE}},
+ {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
2,
0, 0,
{4, 0},
@@ -51,7 +51,7 @@ static const iso14443_frame ATQA_FRAME = {
static const iso14443_frame UID_FRAME = {
TYPE_A,
- {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE}},
+ {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
5,
0, 0,
{0xF4, 0xAC, 0xF9, 0xD7, 0x76},
@@ -60,7 +60,7 @@ static const iso14443_frame UID_FRAME = {
static const iso14443_frame ATS_FRAME = {
TYPE_A,
- {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE}},
+ {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
3,
0, 0,
{0x08, 0xB6, 0xDD},
@@ -69,7 +69,7 @@ static const iso14443_frame ATS_FRAME = {
static const iso14443_frame NONCE_FRAME = {
TYPE_A,
- {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE}},
+ {{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
4,
0, 0,
{0xFF, 0xCF, 0x80, 0xE3},
diff --git a/openpicc/application/ssc.c b/openpicc/application/ssc.c
index a490d42..7c63104 100644
--- a/openpicc/application/ssc.c
+++ b/openpicc/application/ssc.c
@@ -34,6 +34,7 @@
#include "ssc.h"
#include "iso14443.h"
+#include "clock_switch.h"
#include "tc_cdiv_sync.h"
#include "tc_fdt.h"
#include "led.h"
@@ -331,20 +332,6 @@ static __ramfunc ssc_dma_rx_buffer_t* _unload_rx(ssc_handle_t *sh)
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;
- }
-}
-
void ssc_set_gate(int data_enabled) {
if(OPENPICC->features.data_gating) {
if(data_enabled) {
@@ -478,7 +465,7 @@ static inline int _init_ssc_rx(ssc_handle_t *sh)
if(OPENPICC->features.clock_switching) {
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH);
- ssc_select_clock(CLOCK_SELECT_PLL);
+ clock_switch(CLOCK_SELECT_PLL);
}
/* Disable all interrupts */
@@ -512,8 +499,8 @@ static inline int _init_ssc_tx(ssc_handle_t *sh)
OPENPICC_SSC_CLOCK | OPENPICC_SSC_TF, 0);
if(OPENPICC->features.clock_switching) {
- AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC->CLOCK_SWITCH);
- /* Users: remember to ssc_select_clock(CLOCK_SELECT_CARRIER) as
+ clock_switch_init();
+ /* Users: remember to clock_switch(CLOCK_SELECT_CARRIER) as
* early as possible, e.g. right after receive end */
}
diff --git a/openpicc/application/ssc.h b/openpicc/application/ssc.h
index ac74255..2f72e93 100644
--- a/openpicc/application/ssc.h
+++ b/openpicc/application/ssc.h
@@ -31,16 +31,10 @@ typedef enum {
} 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_set_gate(int data_enabled);
extern void ssc_frame_started(void);
diff --git a/openpicc/application/tc_sniffer.c b/openpicc/application/tc_sniffer.c
index abf04c0..a77d790 100644
--- a/openpicc/application/tc_sniffer.c
+++ b/openpicc/application/tc_sniffer.c
@@ -41,11 +41,18 @@
#include "usb_print.h"
#include "cmd.h"
#include "pio_irq.h"
+#include "led.h"
+#include "clock_switch.h"
+
+#include "iso14443a_diffmiller.h"
/* Problem: We want to receive data from the FIQ without locking (the FIQ must not be blocked ever)
* Strategy: Double buffering.
*/
+struct diffmiller_state *decoder;
+iso14443_frame rx_frame;
+
#define BUFSIZE 1024
#define WAIT_TICKS (20*portTICK_RATE_MS)
typedef struct {
@@ -57,18 +64,63 @@ fiq_buffer_t fiq_buffers[2];
fiq_buffer_t *tc_sniffer_next_buffer_for_fiq = 0;
portBASE_TYPE currently_sniffing = 0;
-enum { NONE, REQUEST_START, REQUEST_STOP } request_change = NONE;
+enum { NONE, REQUEST_START, REQUEST_STOP } request_change = REQUEST_START;
+
+//#define PRINT_TIMES
+//#define USE_BINARY_PROTOCOL
#define MIN(a, b) ((a)>(b)?(b):(a))
+static int overruns = 0;
void flush_buffer(fiq_buffer_t *buffer)
{
/* Write all data from the given buffer out, then zero the count */
if(buffer->count > 0) {
+ if(buffer->count >= BUFSIZE) {
+ DumpStringToUSB("Warning: Possible buffer overrun detected\n\r");
+ overruns++;
+ }
+ buffer->count = MIN(buffer->count, BUFSIZE);
+#ifdef USE_BINARY_PROTOCOL
vUSBSendBuffer_blocking((unsigned char*)(&(buffer->data[0])), 0, MIN(buffer->count,BUFSIZE)*4, WAIT_TICKS);
if(buffer->count >= BUFSIZE)
vUSBSendBuffer_blocking((unsigned char*)"////", 0, 4, WAIT_TICKS);
else
vUSBSendBuffer_blocking((unsigned char*)"____", 0, 4, WAIT_TICKS);
+#elif defined(PRINT_TIMES)
+ unsigned int i=0;
+ for(i=0; i<buffer->count; i++) {
+ DumpUIntToUSB(buffer->data[i]);
+ DumpStringToUSB(" ");
+ }
+ DumpStringToUSB("\n\r");
+#else
+ unsigned int offset = 0;
+ while(offset < buffer->count) {
+ int ret = iso14443a_decode_diffmiller(decoder, &rx_frame, buffer->data, &offset, buffer->count);
+ DumpStringToUSB("\n\r");
+ if(ret < 0) {
+ DumpStringToUSB("-");
+ DumpUIntToUSB(-ret);
+ } else {
+ DumpUIntToUSB(ret);
+ }
+ DumpStringToUSB(" ");
+ DumpUIntToUSB(offset); DumpStringToUSB(" "); DumpUIntToUSB(buffer->count); DumpStringToUSB(" "); DumpUIntToUSB(overruns);
+ DumpStringToUSB("\n\r");
+ if(ret >= 0) {
+ DumpStringToUSB("Frame finished, ");
+ DumpUIntToUSB(rx_frame.numbytes);
+ DumpStringToUSB(" bytes, ");
+ DumpUIntToUSB(rx_frame.numbits);
+ DumpStringToUSB(" bits\n\r");
+ switch(rx_frame.parameters.a.crc) {
+ case CRC_OK: DumpStringToUSB("CRC OK\n\r"); break;
+ case CRC_ERROR: DumpStringToUSB("CRC ERROR\n\r"); break;
+ case CRC_UNCALCULATED: DumpStringToUSB("CRC UNCALCULATED\n\r"); break;
+ }
+ }
+ }
+#endif
buffer->count = 0;
}
}
@@ -93,6 +145,8 @@ void tc_sniffer (void *pvParameters)
load_mod_init();
load_mod_level(0);
+ clock_switch_init();
+
pll_init();
pll_inhibit(0);
@@ -103,6 +157,22 @@ void tc_sniffer (void *pvParameters)
/* Wait for the USB and CMD threads to start up */
vTaskDelay(1000 * portTICK_RATE_MS);
+ if(OPENPICC->features.clock_switching) {
+ clock_switch(CLOCK_SELECT_CARRIER);
+ decoder = iso14443a_init_diffmiller(0);
+ } else {
+ switch(OPENPICC->default_clock) {
+ case CLOCK_SELECT_CARRIER:
+ decoder = iso14443a_init_diffmiller(0);
+ break;
+ case CLOCK_SELECT_PLL:
+ decoder = iso14443a_init_diffmiller(1);
+ break;
+ }
+ }
+
+ if(!decoder) vLedHaltBlinking(1);
+
// The change interrupt is going to be handled by the FIQ
AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_DATA);
pio_irq_enable(OPENPICC_SSC_DATA);
@@ -125,16 +195,20 @@ void tc_sniffer (void *pvParameters)
tc_sniffer_next_buffer_for_fiq = 0;
memset(fiq_buffers, 0, sizeof(fiq_buffers));
current = 0;
+#ifdef USE_BINARY_PROTOCOL
vUSBSendBuffer_blocking((unsigned char *)"----", 0, 4, WAIT_TICKS);
usb_print_set_force_silence(0);
+#endif
} else vTaskDelay(2* portTICK_RATE_MS);
} else {
// Do nothing, wait longer
if(request_change == REQUEST_START) {
// Prevent usb_print code from barging in
+#ifdef USE_BINARY_PROTOCOL
usb_print_set_force_silence(1);
vUSBSendBuffer_blocking((unsigned char *)"----", 0, 4, WAIT_TICKS);
+#endif
currently_sniffing = 1;
request_change = NONE;
} else vTaskDelay(100 * portTICK_RATE_MS);
diff --git a/openpicc/config/board.c b/openpicc/config/board.c
index 129cc37..b730809 100644
--- a/openpicc/config/board.c
+++ b/openpicc/config/board.c
@@ -24,6 +24,7 @@ const struct openpicc_hardware OPENPICC_HARDWARE[] = {
[OPENPICC_v0_4] = {OPENPICC_v0_4,
"OpenPICC v0.4", // release name
{0, 0, 0,}, // features: data_gating, clock_gating, clock_switching
+ CLOCK_SELECT_PLL, // default_clock
AT91C_PIO_PA4, // PLL_LOCK
-1, // CLOCK_GATE
-1, // DATA_GATE
@@ -32,6 +33,7 @@ const struct openpicc_hardware OPENPICC_HARDWARE[] = {
[OPENPICC_v0_4_p1] = {OPENPICC_v0_4_p1,
"OpenPICC v0.4 patchlevel 1",
{1, 1, 0,},
+ CLOCK_SELECT_PLL,
AT91C_PIO_PA5,
AT91C_PIO_PA4,
AT91C_PIO_PA31,
@@ -40,6 +42,7 @@ const struct openpicc_hardware OPENPICC_HARDWARE[] = {
[OPENPICC_v0_4_p2] = {OPENPICC_v0_4_p2,
"OpenPICC v0.4 patchlevel 2",
{1, 1, 1,},
+ CLOCK_SELECT_CARRIER,
AT91C_PIO_PA5,
AT91C_PIO_PA4,
AT91C_PIO_PA31,
diff --git a/openpicc/config/board.h b/openpicc/config/board.h
index ac6bf81..55a965b 100644
--- a/openpicc/config/board.h
+++ b/openpicc/config/board.h
@@ -64,6 +64,11 @@ enum openpicc_release {
* using PA30
*/
};
+enum clock_source {
+ CLOCK_SELECT_PLL,
+ CLOCK_SELECT_CARRIER,
+};
+
struct openpicc_hardware {
enum openpicc_release release;
char *release_name;
@@ -72,6 +77,7 @@ struct openpicc_hardware {
int clock_gating:1;
int clock_switching:1;
} features;
+ enum clock_source default_clock;
int PLL_LOCK;
personal git repositories of Harald Welte. Your mileage may vary