From 6304718e371e590b09e176c05df21fc5fb631cec Mon Sep 17 00:00:00 2001 From: henryk Date: Wed, 5 Mar 2008 05:03:36 +0000 Subject: Port over the differential miller decoder from the sniffonly host tool Move clock switch to its own header file Specify default (and for non-clock switching capable hardware: single) clock source in hardware definitions git-svn-id: https://svn.openpcd.org:2342/trunk@443 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/Makefile | 2 + openpicc/application/clock_switch.c | 53 +++++ openpicc/application/clock_switch.h | 7 + openpicc/application/cmd.c | 5 +- openpicc/application/iso14443.h | 1 + openpicc/application/iso14443_layer2a.c | 10 +- openpicc/application/iso14443a_diffmiller.c | 346 ++++++++++++++++++++++++++++ openpicc/application/iso14443a_diffmiller.h | 12 + openpicc/application/iso14443a_miller.c | 2 +- openpicc/application/iso14443a_pretender.c | 8 +- openpicc/application/ssc.c | 21 +- openpicc/application/ssc.h | 6 - openpicc/application/tc_sniffer.c | 76 +++++- openpicc/config/board.c | 3 + openpicc/config/board.h | 6 + 15 files changed, 523 insertions(+), 35 deletions(-) create mode 100644 openpicc/application/clock_switch.c create mode 100644 openpicc/application/clock_switch.h create mode 100644 openpicc/application/iso14443a_diffmiller.c create mode 100644 openpicc/application/iso14443a_diffmiller.h 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 + * + *************************************************************** + + 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 +#include + +#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 + * Copyright 2007 Karsten Nohl + * Copyright 2007,2008 Henryk Plötz + * + * 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 +#include + +#include +#include +#include + +#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<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 * * 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; icount; 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; -- cgit v1.2.3