From a7247d858b195bd21eeba6d65a882323ad71d030 Mon Sep 17 00:00:00 2001 From: "henryk@ploetzli.ch" Date: Mon, 12 Oct 2009 11:47:39 +0000 Subject: [PATCH] Add basic LEGIC RF communication in tag simulation mode --- armsrc/Makefile | 1 + armsrc/appmain.c | 7 +- armsrc/legicrf.c | 172 +++++++++++++++++++++++++++++++++++++++++++++ armsrc/legicrf.h | 12 ++++ include/usb_cmd.h | 1 + winsrc/command.cpp | 8 +++ 6 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 armsrc/legicrf.c create mode 100644 armsrc/legicrf.h diff --git a/armsrc/Makefile b/armsrc/Makefile index d73f2e77..516e5835 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -19,6 +19,7 @@ THUMBSRC = start.c \ lfops.c \ util.c \ hitag2.c \ + legicrf.c \ usb.c # These are to be compiled in ARM mode diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5313202a..c83400da 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -8,6 +8,7 @@ #include #include #include "apps.h" +#include "legicrf.h" #ifdef WITH_LCD #include "fonts.h" #include "LCD.h" @@ -583,11 +584,15 @@ void UsbPacketReceived(BYTE *packet, int len) case CMD_SIMULATE_TAG_ISO_14443: SimulateIso14443Tag(); break; - + case CMD_SIMULATE_TAG_ISO_14443a: SimulateIso14443aTag(c->ext1, c->ext2); // ## Simulate iso14443a tag - pass tag type & UID break; + case CMD_SIMULATE_TAG_LEGIC_RF: + LegicRfSimulate(); + break; + case CMD_MEASURE_ANTENNA_TUNING: MeasureAntennaTuning(); break; diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c new file mode 100644 index 00000000..867c1ad7 --- /dev/null +++ b/armsrc/legicrf.c @@ -0,0 +1,172 @@ +/* + * LEGIC RF simulation code + * + * (c) 2009 Henryk Plötz + */ + +#include + +#include "apps.h" +#include "legicrf.h" + +static struct legic_frame { + int num_bytes; + int num_bits; + char data[10]; +} current_frame; +static char response = 0x2b; /* 1101 01 */ + +static void frame_send(char *response, int num_bytes, int num_bits) +{ +#if 0 + /* Use the SSC to send a response. 8-bit transfers, LSBit first, 100us per bit */ +#else + /* Bitbang the response */ + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + /* Wait for the frame start */ + while(AT91C_BASE_TC1->TC_CV < 490) ; + + int i; + for(i=0; i<(num_bytes*8+num_bits); i++) { + int nextbit = AT91C_BASE_TC1->TC_CV + 150; + int bit = response[i/8] & (1<<(i%8)); + if(bit) + AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; + else + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + while(AT91C_BASE_TC1->TC_CV < nextbit) ; + } + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; +#endif +} + +static void frame_respond(struct legic_frame *f) +{ + LED_D_ON(); + if(f->num_bytes == 0 && f->num_bits == 7) { + /* This seems to be the initial dialogue, just send 6 bits of static data */ + frame_send(&response, 0, 6); + } + LED_D_OFF(); +} + +static void frame_append_bit(struct legic_frame *f, int bit) +{ + if(f->num_bytes >= (int)sizeof(f->data)) + return; /* Overflow, won't happen */ + f->data[f->num_bytes] |= (bit<num_bits); + f->num_bits++; + if(f->num_bits > 7) { + f->num_bits = 0; + f->num_bytes++; + } +} + +static int frame_is_empty(struct legic_frame *f) +{ + return( (f->num_bytes + f->num_bits) <= 4 ); +} + +static void frame_handle(struct legic_frame *f) +{ + if( !frame_is_empty(f) ) { + frame_respond(f); + } +} + +static void frame_clean(struct legic_frame *f) +{ + if(!frame_is_empty(f)) + memset(f->data, 0, sizeof(f->data)); + f->num_bits = 0; + f->num_bytes = 0; +} + +static void emit(int bit) +{ + if(bit == -1) { + frame_handle(¤t_frame); + frame_clean(¤t_frame); + } else if(bit == 0) { + frame_append_bit(¤t_frame, 0); + } else if(bit == 1) { + frame_append_bit(¤t_frame, 1); + } +} + +void LegicRfSimulate(void) +{ + /* ADC path high-frequency peak detector, FPGA in high-frequency simulator mode, + * modulation mode set to 212kHz subcarrier. We are getting the incoming raw + * envelope waveform on DIN and should send our response on DOUT. + * + * The LEGIC RF protocol is pulse-pause-encoding from reader to card, so we'll + * measure the time between two rising edges on DIN, and no encoding on the + * subcarrier from card to reader, so we'll just shift out our verbatim data + * on DOUT, 1 bit is 100us. The time from reader to card frame is still unclear, + * seems to be 300us-ish. + */ + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K); + + /* Bitbang the receiver */ + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; + + /* Set up Timer 1 to use for measuring time between pulses. Since we're bit-banging + * this it won't be terribly accurate but should be good enough. + */ + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK3; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + int old_level = 0; + +/* At TIMER_CLOCK3 (MCK/32) */ +#define BIT_TIME_1 150 +#define BIT_TIME_0 90 +#define BIT_TIME_FUZZ 20 + + int active = 0; + while(!BUTTON_PRESS()) { + int level = !!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN); + int time = AT91C_BASE_TC1->TC_CV; + + if(level != old_level) { + if(level == 1) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + if(time > (BIT_TIME_1-BIT_TIME_FUZZ) && time < (BIT_TIME_1+BIT_TIME_FUZZ)) { + /* 1 bit */ + emit(1); + active = 1; + } else if(time > (BIT_TIME_0-BIT_TIME_FUZZ) && time < (BIT_TIME_0+BIT_TIME_FUZZ)) { + /* 0 bit */ + emit(0); + active = 0; + } else { + /* invalid */ + emit(-1); + active = 0; + } + } + } + + if(time >= (BIT_TIME_1+2*BIT_TIME_FUZZ) && active) { + /* Frame end */ + emit(-1); + active = 0; + } + + if(time >= (20*BIT_TIME_1) && (AT91C_BASE_TC1->TC_SR & AT91C_TC_CLKSTA)) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + } + + + old_level = level; + WDT_HIT(); + } +} diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h new file mode 100644 index 00000000..39119dd1 --- /dev/null +++ b/armsrc/legicrf.h @@ -0,0 +1,12 @@ +/* + * LEGIC RF emulation public interface + * + * (c) 2009 Henryk Plötz + */ + +#ifndef LEGICRF_H_ +#define LEGICRF_H_ + +extern void LegicRfSimulate(void); + +#endif /* LEGICRF_H_ */ diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 437629fd..5ff2f260 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -69,6 +69,7 @@ typedef struct { #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 #define CMD_SIMULATE_MIFARE_CARD 0x0386 +#define CMD_SIMULATE_TAG_LEGIC_RF 0x387 // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 diff --git a/winsrc/command.cpp b/winsrc/command.cpp index da0f2388..b2258640 100644 --- a/winsrc/command.cpp +++ b/winsrc/command.cpp @@ -207,6 +207,13 @@ static void CmdHi14asnoop(char *str) SendCommand(&c, FALSE); } +static void CmdLegicRfSim(char *str) +{ + UsbCommand c; + c.cmd = CMD_SIMULATE_TAG_LEGIC_RF; + SendCommand(&c, FALSE); +} + static void CmdFPGAOff(char *str) // ## FPGA Control { UsbCommand c; @@ -2900,6 +2907,7 @@ static struct { {"indalademod", CmdIndalademod, 0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"}, {"lcd", CmdLcd, 0, " -- Send command/data to LCD"}, {"lcdreset", CmdLcdReset, 0, "Hardware reset LCD"}, + {"legicrfsim", CmdLegicRfSim, 0, "Start the LEGIC RF tag simulator"}, {"load", CmdLoad, 1, " -- Load trace (to graph window"}, {"locomread", CmdLoCommandRead, 0, " <'0' period> <'1' period> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"}, {"loread", CmdLoread, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"}, -- 2.39.2