Add new miller decoder (not working yet)
Vastly improve timing through CPU cycle counting. Jitter is now like 40ns (the SSC_DATA edge detection fuzziness) in 2 main clusters 4 CPU cycles (83ns) apart, plus an occasional glitch adding 4 CPU cycles in either direction git-svn-id: https://svn.openpcd.org:2342/trunk@385 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
This commit is contained in:
parent
3d0e1db9d1
commit
202b56a42c
|
@ -90,6 +90,7 @@ ARM_SRC= \
|
||||||
application/usb_print.c \
|
application/usb_print.c \
|
||||||
application/iso14443_layer3a.c \
|
application/iso14443_layer3a.c \
|
||||||
application/iso14443a_manchester.c \
|
application/iso14443a_manchester.c \
|
||||||
|
application/iso14443a_miller.c \
|
||||||
application/load_modulation.c \
|
application/load_modulation.c \
|
||||||
application/decoder_miller.c \
|
application/decoder_miller.c \
|
||||||
application/decoder_nrzl.c \
|
application/decoder_nrzl.c \
|
||||||
|
|
|
@ -37,13 +37,14 @@
|
||||||
#include "load_modulation.h"
|
#include "load_modulation.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
#include "iso14443a_manchester.h"
|
#include "iso14443a_manchester.h"
|
||||||
|
#include "iso14443a_miller.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
|
||||||
static enum ISO14443_STATES state = STARTING_UP;
|
static enum ISO14443_STATES state = STARTING_UP;
|
||||||
const iso14443_frame ATQA_FRAME = {
|
const iso14443_frame ATQA_FRAME = {
|
||||||
TYPE_A,
|
TYPE_A,
|
||||||
{{STANDARD_FRAME, PARITY}},
|
{{STANDARD_FRAME, PARITY}},
|
||||||
2,
|
2,
|
||||||
0, 0,
|
0, 0,
|
||||||
{4, 0},
|
{4, 0},
|
||||||
{}
|
{}
|
||||||
|
@ -85,11 +86,11 @@ const iso14443_frame NULL_FRAME = {
|
||||||
void iso14443_transmit(ssc_dma_tx_buffer_t *buf, int fdt, int div)
|
void iso14443_transmit(ssc_dma_tx_buffer_t *buf, int fdt, int div)
|
||||||
{
|
{
|
||||||
tc_cdiv_set_divider(div);
|
tc_cdiv_set_divider(div);
|
||||||
if(fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0 ||
|
if(fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0) {
|
||||||
fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1) {
|
fdt = tc_fdt_get_next_slot(ISO14443A_FDT_SHORT_0, ISO14443A_FDT_SLOTLEN);
|
||||||
/* FIXME Implement */
|
} else if (fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1) {
|
||||||
return;
|
fdt = tc_fdt_get_next_slot(ISO14443A_FDT_SHORT_1, ISO14443A_FDT_SLOTLEN);
|
||||||
}
|
}
|
||||||
ssc_tx_fiq_fdt_cdiv = fdt -3*div -1;
|
ssc_tx_fiq_fdt_cdiv = fdt -3*div -1;
|
||||||
tc_fdt_set(ssc_tx_fiq_fdt_cdiv -MAX_TF_FIQ_ENTRY_DELAY -MAX_TF_FIQ_OVERHEAD);
|
tc_fdt_set(ssc_tx_fiq_fdt_cdiv -MAX_TF_FIQ_ENTRY_DELAY -MAX_TF_FIQ_OVERHEAD);
|
||||||
ssc_tx_fiq_fdt_ssc = fdt -div +1;
|
ssc_tx_fiq_fdt_ssc = fdt -div +1;
|
||||||
|
@ -162,7 +163,7 @@ static int prefill_buffer(ssc_dma_tx_buffer_t *dest, const iso14443_frame *src)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u_int8_t received_buffer[256];
|
static iso14443_frame received_frame;
|
||||||
|
|
||||||
static void enable_reception(enum ssc_mode mode) {
|
static void enable_reception(enum ssc_mode mode) {
|
||||||
tc_fdt_set(0xff00);
|
tc_fdt_set(0xff00);
|
||||||
|
@ -307,6 +308,12 @@ void iso14443_layer3a_state_machine (void *pvParameters)
|
||||||
LAYER3_DEBUG(", woke up to send ATQA\n\r");
|
LAYER3_DEBUG(", woke up to send ATQA\n\r");
|
||||||
atqa_sent = 0;
|
atqa_sent = 0;
|
||||||
}
|
}
|
||||||
|
if(1) {
|
||||||
|
DumpStringToUSB("Decoded: ");
|
||||||
|
iso14443a_decode_miller(&received_frame, buffer->data, buffer->len);
|
||||||
|
DumpBufferToUSB((char*)received_frame.data, 100);
|
||||||
|
DumpStringToUSB("\n\r");
|
||||||
|
}
|
||||||
/* For debugging, wait 1ms, then wait for another frame
|
/* For debugging, wait 1ms, then wait for another frame
|
||||||
* Normally we'd go to anticol from here*/
|
* Normally we'd go to anticol from here*/
|
||||||
vTaskDelay(portTICK_RATE_MS);
|
vTaskDelay(portTICK_RATE_MS);
|
||||||
|
@ -320,12 +327,12 @@ void iso14443_layer3a_state_machine (void *pvParameters)
|
||||||
break;
|
break;
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
case ACTIVE_STAR:
|
case ACTIVE_STAR:
|
||||||
if(0) {
|
#if 0
|
||||||
DumpStringToUSB("Decoded: ");
|
DumpStringToUSB("Decoded: ");
|
||||||
decoder_decode(DECODER_MILLER, (const char*)buffer->data, buffer->len, received_buffer);
|
decoder_decode(DECODER_MILLER, (const char*)buffer->data, buffer->len, received_buffer);
|
||||||
DumpBufferToUSB((char*)received_buffer, 100);
|
DumpBufferToUSB((char*)received_buffer, 100);
|
||||||
DumpStringToUSB("\n\r");
|
DumpStringToUSB("\n\r");
|
||||||
}
|
#endif
|
||||||
/* Wait for another frame */
|
/* Wait for another frame */
|
||||||
if(0) {
|
if(0) {
|
||||||
ssc_rx_mode_set(SSC_MODE_14443A_STANDARD);
|
ssc_rx_mode_set(SSC_MODE_14443A_STANDARD);
|
||||||
|
@ -336,7 +343,7 @@ void iso14443_layer3a_state_machine (void *pvParameters)
|
||||||
if(prefill_buffer(&ssc_tx_buffer, &NULL_FRAME)) {
|
if(prefill_buffer(&ssc_tx_buffer, &NULL_FRAME)) {
|
||||||
usb_print_string_f("Sending response ...",0);
|
usb_print_string_f("Sending response ...",0);
|
||||||
ssc_tx_buffer.state = PROCESSING;
|
ssc_tx_buffer.state = PROCESSING;
|
||||||
iso14443_transmit(&ssc_tx_buffer, 1, 8);
|
iso14443_transmit(&ssc_tx_buffer, ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1, 8);
|
||||||
while( ssc_tx_buffer.state != FREE ) {
|
while( ssc_tx_buffer.state != FREE ) {
|
||||||
vTaskDelay(portTICK_RATE_MS);
|
vTaskDelay(portTICK_RATE_MS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,21 +16,6 @@ enum ISO14443_STATES {
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************** RX ************************************/
|
/******************** RX ************************************/
|
||||||
/* Magic delay, don't know where it comes from */
|
|
||||||
#define MAGIC_OFFSET -32
|
|
||||||
/* Delay from modulation till detection in SSC_DATA */
|
|
||||||
#define DETECTION_DELAY 11
|
|
||||||
/* See fdt_timinig.dia for these values */
|
|
||||||
#define MAX_TF_FIQ_ENTRY_DELAY 16
|
|
||||||
#define MAX_TF_FIQ_OVERHEAD 75 /* guesstimate */
|
|
||||||
extern volatile int fdt_offset;
|
|
||||||
/* standard derived magic values */
|
|
||||||
#define ISO14443A_FDT_SLOTLEN 128
|
|
||||||
#define ISO14443A_FDT_OFFSET_1 84
|
|
||||||
#define ISO14443A_FDT_OFFSET_0 20
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#ifdef FOUR_TIMES_OVERSAMPLING
|
#ifdef FOUR_TIMES_OVERSAMPLING
|
||||||
/* definitions for four-times oversampling */
|
/* definitions for four-times oversampling */
|
||||||
/* Sample values for the REQA and WUPA short frames */
|
/* Sample values for the REQA and WUPA short frames */
|
||||||
|
@ -82,6 +67,21 @@ extern volatile int fdt_offset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/******************** TX ************************************/
|
/******************** TX ************************************/
|
||||||
|
/* Magic delay, don't know where it comes from */
|
||||||
|
#define MAGIC_OFFSET -32
|
||||||
|
/* Delay from modulation till detection in SSC_DATA */
|
||||||
|
#define DETECTION_DELAY 11
|
||||||
|
/* See fdt_timinig.dia for these values */
|
||||||
|
#define MAX_TF_FIQ_ENTRY_DELAY 16
|
||||||
|
#define MAX_TF_FIQ_OVERHEAD 75 /* guesstimate */
|
||||||
|
extern volatile int fdt_offset;
|
||||||
|
/* standard derived magic values */
|
||||||
|
#define ISO14443A_FDT_SLOTLEN 128
|
||||||
|
#define ISO14443A_FDT_OFFSET_1 84
|
||||||
|
#define ISO14443A_FDT_OFFSET_0 20
|
||||||
|
#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 */
|
/* in bytes, not counting parity */
|
||||||
#define MAXIMUM_FRAME_SIZE 256
|
#define MAXIMUM_FRAME_SIZE 256
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* ISO14443A Manchester encoder for OpenPICC
|
/* ISO14443A Manchester encoder for OpenPICC
|
||||||
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
|
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
|
||||||
|
* (C) 2007 by Henryk Plötz <henryk@ploetzli.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* ISO14443A Manchester encoder for OpenPICC
|
||||||
|
* (C) 2007 by 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 <string.h>
|
||||||
|
|
||||||
|
#include "iso14443_layer3a.h"
|
||||||
|
#include "usb_print.h"
|
||||||
|
#include "cmd.h"
|
||||||
|
|
||||||
|
#ifdef FOUR_TIMES_OVERSAMPLING
|
||||||
|
#define OVERSAMPLING_RATE 4
|
||||||
|
|
||||||
|
/* definitions for four-times oversampling */
|
||||||
|
#define SEQ_X 0x4
|
||||||
|
#define SEQ_Y 0x0
|
||||||
|
#define SEQ_Z 0x1
|
||||||
|
#else
|
||||||
|
#define OVERSAMPLING_RATE 2
|
||||||
|
#define SEQ_X 0x2
|
||||||
|
#define SEQ_Y 0x0
|
||||||
|
#define SEQ_Z 0x1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum miller_sequence {
|
||||||
|
SEQUENCE_X,
|
||||||
|
SEQUENCE_Y,
|
||||||
|
SEQUENCE_Z,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BIT_ENDMARKER -1
|
||||||
|
|
||||||
|
int iso14443a_decode_miller(iso14443_frame *frame,
|
||||||
|
const u_int8_t *sample_buf, const u_int16_t sample_buf_len)
|
||||||
|
{
|
||||||
|
signed int i, j, bit = 0, last_bit = 0;
|
||||||
|
enum miller_sequence current_seq;
|
||||||
|
unsigned int bitpos = 0;
|
||||||
|
|
||||||
|
memset(frame, 0, sizeof(frame));
|
||||||
|
frame->type = TYPE_A;
|
||||||
|
frame->parameters.a.parity = GIVEN_PARITY;
|
||||||
|
|
||||||
|
for(i=0; i<sample_buf_len && bit != BIT_ENDMARKER; i++) {
|
||||||
|
for(j=0; j<(signed)(sizeof(sample_buf[0])*8)/OVERSAMPLING_RATE && bit != BIT_ENDMARKER; j++) {
|
||||||
|
int sample = (sample_buf[i]>>(j*OVERSAMPLING_RATE)) & ~(~0 << OVERSAMPLING_RATE);
|
||||||
|
switch(sample) {
|
||||||
|
case SEQ_X: current_seq = SEQUENCE_X; break;
|
||||||
|
case SEQ_Y: current_seq = SEQUENCE_Y; break;
|
||||||
|
case SEQ_Z: current_seq = SEQUENCE_Z; break;
|
||||||
|
default: current_seq = SEQUENCE_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(current_seq) {
|
||||||
|
case SEQ_X:
|
||||||
|
DumpStringToUSB("X");
|
||||||
|
bit = 1; break;
|
||||||
|
case SEQ_Y: /* Fall-through to SEQ_Z */
|
||||||
|
DumpStringToUSB("Y");
|
||||||
|
if(last_bit == 0) {
|
||||||
|
bit = BIT_ENDMARKER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SEQ_Z:
|
||||||
|
DumpStringToUSB("Z");
|
||||||
|
bit = 0; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(bit) {
|
||||||
|
case BIT_ENDMARKER:
|
||||||
|
bitpos--;
|
||||||
|
break;
|
||||||
|
case 0: /* Fall-through */
|
||||||
|
case 1: {
|
||||||
|
int bytepos = bitpos/9;
|
||||||
|
if(bitpos % 9 == 8) { /* Parity bit */
|
||||||
|
frame->parity[ bytepos/8 ] |= (bit<<(bytepos%8));
|
||||||
|
} else {
|
||||||
|
frame->data[ bytepos ] |= (bit<<(bitpos%9));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_bit = bit;
|
||||||
|
bitpos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->numbytes = bitpos/9;
|
||||||
|
frame->numbits = bitpos%9;
|
||||||
|
DumpStringToUSB("\n\r");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef ISO14443A_MILLER_H_
|
||||||
|
#define ISO14443A_MILLER_H_
|
||||||
|
|
||||||
|
extern int iso14443a_decode_miller(iso14443_frame *frame, const u_int8_t *sample_buf, const u_int16_t sample_buf_len);
|
||||||
|
|
||||||
|
#endif /*ISO14443A_MILLER_H_*/
|
|
@ -50,16 +50,12 @@ void tc_fdt_set(u_int16_t count)
|
||||||
tcfdt->TC_RA = count;
|
tcfdt->TC_RA = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __ramfunc tc_fdt_set_to_next_slot(int last_bit)
|
int tc_fdt_get_next_slot(int reference_time, int slotlen)
|
||||||
{
|
{
|
||||||
int reference_time;
|
/*if(tcfdt->TC_SR & AT91C_TC_CLKSTA)
|
||||||
if(last_bit == 0) reference_time = ISO14443A_FDT_OFFSET_0;
|
|
||||||
else reference_time = ISO14443A_FDT_OFFSET_1;
|
|
||||||
|
|
||||||
if(tcfdt->TC_SR & AT91C_TC_CLKSTA)
|
|
||||||
while(tcfdt->TC_CV != 0xFFFF && (tcfdt->TC_CV - reference_time) % 128 != 0);
|
while(tcfdt->TC_CV != 0xFFFF && (tcfdt->TC_CV - reference_time) % 128 != 0);
|
||||||
tcfdt->TC_CCR = AT91C_TC_SWTRG;
|
tcfdt->TC_CCR = AT91C_TC_SWTRG;*/
|
||||||
tc_fdt_set(2*128);
|
return tcfdt->TC_CV + (slotlen-((tcfdt->TC_CV - reference_time) % slotlen)) + 3*slotlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
|
|
||||||
extern void tc_fdt_init(void);
|
extern void tc_fdt_init(void);
|
||||||
extern void tc_fdt_set(u_int16_t count);
|
extern void tc_fdt_set(u_int16_t count);
|
||||||
extern void __ramfunc tc_fdt_set_to_next_slot(int last_bit);
|
extern int tc_fdt_get_next_slot(int reference_time, int slotlen);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -250,10 +250,39 @@ my_fiq_handler:
|
||||||
ldr r11, =ssc_tx_fiq_fdt_cdiv
|
ldr r11, =ssc_tx_fiq_fdt_cdiv
|
||||||
ldr r11, [r11] /* r11 == ssc_tx_fiq_fdt_cdiv */
|
ldr r11, [r11] /* r11 == ssc_tx_fiq_fdt_cdiv */
|
||||||
|
|
||||||
|
/* Problem: LDR from the timer still takes too long and causes us to miss the exact time.
|
||||||
|
* Strategy: Spin on TC2 till we are very near the actual time. Then load the timer value, calculate
|
||||||
|
* the difference to the target, then do a countdown spin without reading the timer.
|
||||||
|
*
|
||||||
|
* At 47.923200 MHz 7 processor cycles are 2 carrier cycles of the 13.56MHz carrier
|
||||||
|
*/
|
||||||
|
.equ SUB_TIME, 20 /* subtract 20 carrier cycles == 70 processor cycles */
|
||||||
|
.equ ADD_TIME, (70-20) /* Add x processor cycles */
|
||||||
|
|
||||||
|
mov r8, #SUB_TIME
|
||||||
|
sub r11, r11, r8
|
||||||
|
|
||||||
.wait_for_fdt_cdiv:
|
.wait_for_fdt_cdiv:
|
||||||
ldr r8, [r12, #TC2_CV]
|
ldr r8, [r12, #TC2_CV]
|
||||||
cmp r8, r11
|
cmp r8, r11
|
||||||
bmi .wait_for_fdt_cdiv /* spin while TC2.CV is less fdt_cdiv */
|
bmi .wait_for_fdt_cdiv /* spin while TC2.CV is less fdt_cdiv-SUB_TIM */
|
||||||
|
|
||||||
|
ldr r8, [r12, #TC2_CV]
|
||||||
|
sub r11, r11, r8 /* r11 == fdt_cdiv-SUB_TIME - TC2.CV */
|
||||||
|
|
||||||
|
mov r8, #0x07
|
||||||
|
mul r11, r8, r11 /* r11 = r11 * 7 */
|
||||||
|
mov r11, r11, ASR #1 /* r11 = r11 / 2 */
|
||||||
|
|
||||||
|
mov r8, #ADD_TIME
|
||||||
|
add r11, r11, r8 /* r11 = r11 + ADD_TIME */
|
||||||
|
|
||||||
|
mov r11, r11, ASR #2 /* r11 = r11 / 4 (4 is the number of cycles per loop run below) */
|
||||||
|
|
||||||
|
mov r8, #1
|
||||||
|
.wait_for_my_time:
|
||||||
|
subs r11, r11, r8
|
||||||
|
bge .wait_for_my_time
|
||||||
|
|
||||||
str r9, [r12, #TC_CCR] /* SWTRG on TC0 */
|
str r9, [r12, #TC_CCR] /* SWTRG on TC0 */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue