From: adam@algroup.co.uk Date: Sat, 4 Jul 2009 16:45:17 +0000 (+0000) Subject: send LF commands to TAG (locomread) X-Git-Tag: v1.0.0~585 X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/959baa89f737bdf91ea0ec56957ab5aabbf39ff8 send LF commands to TAG (locomread) --- diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 681bba99..01e3efc9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1,32 +1,32 @@ -//----------------------------------------------------------------------------- -// The main application code. This is the first thing called after start.c -// executes. -// Jonathan Westhues, Mar 2006 -// Edits by Gerhard de Koning Gans, Sep 2007 (##) -//----------------------------------------------------------------------------- - - -#include -#include "apps.h" -#ifdef WITH_LCD -#include "fonts.h" -#include "LCD.h" -#endif - -// The large multi-purpose buffer, typically used to hold A/D samples, -// maybe pre-processed in some way. -DWORD BigBuf[16000]; - -//============================================================================= -// A buffer where we can queue things up to be sent through the FPGA, for -// any purpose (fake tag, as reader, whatever). We go MSB first, since that -// is the order in which they go out on the wire. -//============================================================================= - -BYTE ToSend[256]; -int ToSendMax; -static int ToSendBit; - +//----------------------------------------------------------------------------- +// The main application code. This is the first thing called after start.c +// executes. +// Jonathan Westhues, Mar 2006 +// Edits by Gerhard de Koning Gans, Sep 2007 (##) +//----------------------------------------------------------------------------- + + +#include +#include "apps.h" +#ifdef WITH_LCD +#include "fonts.h" +#include "LCD.h" +#endif + +// The large multi-purpose buffer, typically used to hold A/D samples, +// maybe pre-processed in some way. +DWORD BigBuf[16000]; + +//============================================================================= +// A buffer where we can queue things up to be sent through the FPGA, for +// any purpose (fake tag, as reader, whatever). We go MSB first, since that +// is the order in which they go out on the wire. +//============================================================================= + +BYTE ToSend[256]; +int ToSendMax; +static int ToSendBit; + void BufferClear(void) { @@ -34,137 +34,201 @@ void BufferClear(void) DbpString("Buffer cleared"); } -void ToSendReset(void) -{ - ToSendMax = -1; - ToSendBit = 8; -} - -void ToSendStuffBit(int b) -{ - if(ToSendBit >= 8) { - ToSendMax++; - ToSend[ToSendMax] = 0; - ToSendBit = 0; - } - - if(b) { - ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); - } - - ToSendBit++; - - if(ToSendBit >= sizeof(ToSend)) { - ToSendBit = 0; - DbpString("ToSendStuffBit overflowed!"); - } -} - -//============================================================================= -// Debug print functions, to go out over USB, to the usual PC-side client. -//============================================================================= - -void DbpString(char *str) -{ - UsbCommand c; - c.cmd = CMD_DEBUG_PRINT_STRING; - c.ext1 = strlen(str); - memcpy(c.d.asBytes, str, c.ext1); - - UsbSendPacket((BYTE *)&c, sizeof(c)); - // TODO fix USB so stupid things like this aren't req'd - SpinDelay(50); -} - -void DbpIntegers(int x1, int x2, int x3) -{ - UsbCommand c; - c.cmd = CMD_DEBUG_PRINT_INTEGERS; - c.ext1 = x1; - c.ext2 = x2; - c.ext3 = x3; - - UsbSendPacket((BYTE *)&c, sizeof(c)); - // XXX - SpinDelay(50); -} - -void AcquireRawAdcSamples125k(BOOL at134khz) -{ - BYTE *dest = (BYTE *)BigBuf; - int n = sizeof(BigBuf); - int i; - - memset(dest,0,n); - - if(at134khz) { - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); - } else { - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); - } - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - i = 0; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; - LED_D_ON(); - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - dest[i] = (BYTE)SSC_RECEIVE_HOLDING; - i++; - LED_D_OFF(); - if(i >= n) { - break; - } - } - } - DbpIntegers(dest[0], dest[1], at134khz); -} - -//----------------------------------------------------------------------------- -// Read an ADC channel and block till it completes, then return the result -// in ADC units (0 to 1023). Also a routine to average 32 samples and -// return that. -//----------------------------------------------------------------------------- -static int ReadAdc(int ch) -{ - DWORD d; - - ADC_CONTROL = ADC_CONTROL_RESET; - ADC_MODE = ADC_MODE_PRESCALE(32) | ADC_MODE_STARTUP_TIME(16) | - ADC_MODE_SAMPLE_HOLD_TIME(8); - ADC_CHANNEL_ENABLE = ADC_CHANNEL(ch); - - ADC_CONTROL = ADC_CONTROL_START; - while(!(ADC_STATUS & ADC_END_OF_CONVERSION(ch))) - ; - d = ADC_CHANNEL_DATA(ch); - - return d; -} - -static int AvgAdc(int ch) -{ - int i; - int a = 0; - - for(i = 0; i < 32; i++) { - a += ReadAdc(ch); - } - - return (a + 15) >> 5; -} +void ToSendReset(void) +{ + ToSendMax = -1; + ToSendBit = 8; +} + +void ToSendStuffBit(int b) +{ + if(ToSendBit >= 8) { + ToSendMax++; + ToSend[ToSendMax] = 0; + ToSendBit = 0; + } + + if(b) { + ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); + } + + ToSendBit++; + + if(ToSendBit >= sizeof(ToSend)) { + ToSendBit = 0; + DbpString("ToSendStuffBit overflowed!"); + } +} + +//============================================================================= +// Debug print functions, to go out over USB, to the usual PC-side client. +//============================================================================= + +void DbpString(char *str) +{ + UsbCommand c; + c.cmd = CMD_DEBUG_PRINT_STRING; + c.ext1 = strlen(str); + memcpy(c.d.asBytes, str, c.ext1); + + UsbSendPacket((BYTE *)&c, sizeof(c)); + // TODO fix USB so stupid things like this aren't req'd + SpinDelay(50); +} + +void DbpIntegers(int x1, int x2, int x3) +{ + UsbCommand c; + c.cmd = CMD_DEBUG_PRINT_INTEGERS; + c.ext1 = x1; + c.ext2 = x2; + c.ext3 = x3; + + UsbSendPacket((BYTE *)&c, sizeof(c)); + // XXX + SpinDelay(50); +} + +void AcquireRawAdcSamples125k(BOOL at134khz) +{ + if(at134khz) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); + } else { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + } + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // Now call the acquisition routine + DoAcquisition125k(at134khz); +} + +// split into two routines so we can avoid timing issues after sending commands // +void DoAcquisition125k(BOOL at134khz) +{ + BYTE *dest = (BYTE *)BigBuf; + int n = sizeof(BigBuf); + int i; + + memset(dest,0,n); + i = 0; + for(;;) { + if(SSC_STATUS & (SSC_STATUS_TX_READY)) { + SSC_TRANSMIT_HOLDING = 0x43; + LED_D_ON(); + } + if(SSC_STATUS & (SSC_STATUS_RX_READY)) { + dest[i] = (BYTE)SSC_RECEIVE_HOLDING; + i++; + LED_D_OFF(); + if(i >= n) { + break; + } + } + } + DbpIntegers(dest[0], dest[1], at134khz); +} + +void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,BYTE *command) +{ + BOOL at134khz; + + // see if 'h' was specified + if(command[strlen(command) - 1] == 'h') + at134khz= TRUE; + else + at134khz= FALSE; + + if(at134khz) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); + } else { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + } + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // now modulate the reader field + while(*command != '\0' && *command != ' ') + { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + if(at134khz) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); + } else { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + } + LED_D_ON(); + if(*(command++) == '0') + SpinDelayUs(period_0); + else + SpinDelayUs(period_1); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + if(at134khz) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); + } else { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + } + + // now do the read + DoAcquisition125k(at134khz); +} + +//----------------------------------------------------------------------------- +// Read an ADC channel and block till it completes, then return the result +// in ADC units (0 to 1023). Also a routine to average 32 samples and +// return that. +//----------------------------------------------------------------------------- +static int ReadAdc(int ch) +{ + DWORD d; + + ADC_CONTROL = ADC_CONTROL_RESET; + ADC_MODE = ADC_MODE_PRESCALE(32) | ADC_MODE_STARTUP_TIME(16) | + ADC_MODE_SAMPLE_HOLD_TIME(8); + ADC_CHANNEL_ENABLE = ADC_CHANNEL(ch); + + ADC_CONTROL = ADC_CONTROL_START; + while(!(ADC_STATUS & ADC_END_OF_CONVERSION(ch))) + ; + d = ADC_CHANNEL_DATA(ch); + + return d; +} + +static int AvgAdc(int ch) +{ + int i; + int a = 0; + + for(i = 0; i < 32; i++) { + a += ReadAdc(ch); + } + + return (a + 15) >> 5; +} /* * Sweeps the useful LF range of the proxmark from @@ -172,645 +236,671 @@ static int AvgAdc(int ch) * reads the voltage in the antenna: the result is a graph * which should clearly show the resonating frequency of your * LF antenna ( hopefully around 90 if it is tuned to 125kHz!) - */ -void SweepLFrange() -{ - BYTE *dest = (BYTE *)BigBuf; - int i; - - // clear buffer - memset(BigBuf,0,sizeof(BigBuf)); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - for (i=255; i>19; i--) { - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); - SpinDelay(20); - dest[i] = (137500 * AvgAdc(4)) >> 18; - } -} - -void MeasureAntennaTuning(void) -{ -// Impedances are Zc = 1/(j*omega*C), in ohms -#define LF_TUNING_CAP_Z 1273 // 1 nF @ 125 kHz -#define HF_TUNING_CAP_Z 235 // 50 pF @ 13.56 MHz - - int vLf125, vLf134, vHf; // in mV - - UsbCommand c; - - // Let the FPGA drive the low-frequency antenna around 125 kHz. - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); - SpinDelay(20); - vLf125 = AvgAdc(4); - // Vref = 3.3V, and a 10000:240 voltage divider on the input - // can measure voltages up to 137500 mV - vLf125 = (137500 * vLf125) >> 10; - - // Let the FPGA drive the low-frequency antenna around 134 kHz. - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); - SpinDelay(20); - vLf134 = AvgAdc(4); - // Vref = 3.3V, and a 10000:240 voltage divider on the input - // can measure voltages up to 137500 mV - vLf134 = (137500 * vLf134) >> 10; - - // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(20); - vHf = AvgAdc(5); - // Vref = 3300mV, and an 10:1 voltage divider on the input - // can measure voltages up to 33000 mV - vHf = (33000 * vHf) >> 10; - - c.cmd = CMD_MEASURED_ANTENNA_TUNING; - c.ext1 = (vLf125 << 0) | (vLf134 << 16); - c.ext2 = vHf; - c.ext3 = (LF_TUNING_CAP_Z << 0) | (HF_TUNING_CAP_Z << 16); - UsbSendPacket((BYTE *)&c, sizeof(c)); -} - -void SimulateTagLowFrequency(int period) -{ - int i; - BYTE *tab = (BYTE *)BigBuf; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); - - PIO_ENABLE = (1 << GPIO_SSC_DOUT) | (1 << GPIO_SSC_CLK); - - PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT); - PIO_OUTPUT_DISABLE = (1 << GPIO_SSC_CLK); - -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) - - i = 0; - for(;;) { - while(!(PIO_PIN_DATA_STATUS & (1<0xFFF) { - DbpString("Tags can only have 44 bits."); - return; - } - fc(0,&n); - // special start of frame marker containing invalid bit sequences - fc(8, &n); fc(8, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 - fc(10, &n); fc(10, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 - - WDT_HIT(); - // manchester encode bits 43 to 32 - for (i=11; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - - WDT_HIT(); - // manchester encode bits 31 to 0 - for (i=31; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((lo>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - - LED_A_ON(); - SimulateTagLowFrequency(n); - LED_A_OFF(); -} - -// loop to capture raw HID waveform then FSK demodulate the TAG ID from it -static void CmdHIDdemodFSK(void) -{ - BYTE *dest = (BYTE *)BigBuf; - int m=0, n=0, i=0, idx=0, found=0, lastval=0; - DWORD hi=0, lo=0; - - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - for(;;) { - WDT_HIT(); - LED_A_ON(); - if(BUTTON_PRESS()) { - LED_A_OFF(); - return; - } - - i = 0; - m = sizeof(BigBuf); - memset(dest,128,m); - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0x43; - LED_D_ON(); - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - dest[i] = (BYTE)SSC_RECEIVE_HOLDING; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; - i++; - LED_D_OFF(); - if(i >= m) { - break; - } - } - } - - // FSK demodulator - - // sync to first lo-hi transition - for( idx=1; idx>1)&0xffff); - hi=0; - lo=0; - found=0; - } - } - if (found) { - if (dest[idx] && (!dest[idx+1]) ) { - hi=(hi<<1)|(lo>>31); - lo=(lo<<1)|0; - } else if ( (!dest[idx]) && dest[idx+1]) { - hi=(hi<<1)|(lo>>31); - lo=(lo<<1)|1; - } else { - found=0; - hi=0; - lo=0; - } - idx++; - } - if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) - { - found=1; - idx+=6; - if (found && (hi|lo)) { - DbpString("TAG ID"); - DbpIntegers(hi, lo, (lo>>1)&0xffff); - hi=0; - lo=0; - found=0; - } - } - } - WDT_HIT(); - } -} - -void SimulateTagHfListen(void) -{ - BYTE *dest = (BYTE *)BigBuf; - int n = sizeof(BigBuf); - BYTE v = 0; - int i; - int p = 0; - - // We're using this mode just so that I can test it out; the simulated - // tag mode would work just as well and be simpler. - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); - - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - FpgaSetupSsc(); - - i = 0; - for(;;) { - if(SSC_STATUS & (SSC_STATUS_TX_READY)) { - SSC_TRANSMIT_HOLDING = 0xff; - } - if(SSC_STATUS & (SSC_STATUS_RX_READY)) { - BYTE r = (BYTE)SSC_RECEIVE_HOLDING; - - v <<= 1; - if(r & 1) { - v |= 1; - } - p++; - - if(p >= 8) { - dest[i] = v; - v = 0; - p = 0; - i++; - - if(i >= n) { - break; - } - } - } - } - DbpString("simulate tag (now type bitsamples)"); -} - -void UsbPacketReceived(BYTE *packet, int len) -{ - UsbCommand *c = (UsbCommand *)packet; - - switch(c->cmd) { - case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: - AcquireRawAdcSamples125k(c->ext1); - break; - - case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: - AcquireRawAdcSamplesIso15693(); - break; + */ +void SweepLFrange() +{ + BYTE *dest = (BYTE *)BigBuf; + int i; + + // clear buffer + memset(BigBuf,0,sizeof(BigBuf)); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + for (i=255; i>19; i--) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); + SpinDelay(20); + dest[i] = (137500 * AvgAdc(4)) >> 18; + } +} + +void MeasureAntennaTuning(void) +{ +// Impedances are Zc = 1/(j*omega*C), in ohms +#define LF_TUNING_CAP_Z 1273 // 1 nF @ 125 kHz +#define HF_TUNING_CAP_Z 235 // 50 pF @ 13.56 MHz + + int vLf125, vLf134, vHf; // in mV + + UsbCommand c; + + // Let the FPGA drive the low-frequency antenna around 125 kHz. + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + SpinDelay(20); + vLf125 = AvgAdc(4); + // Vref = 3.3V, and a 10000:240 voltage divider on the input + // can measure voltages up to 137500 mV + vLf125 = (137500 * vLf125) >> 10; + + // Let the FPGA drive the low-frequency antenna around 134 kHz. + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ); + SpinDelay(20); + vLf134 = AvgAdc(4); + // Vref = 3.3V, and a 10000:240 voltage divider on the input + // can measure voltages up to 137500 mV + vLf134 = (137500 * vLf134) >> 10; + + // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(20); + vHf = AvgAdc(5); + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + vHf = (33000 * vHf) >> 10; + + c.cmd = CMD_MEASURED_ANTENNA_TUNING; + c.ext1 = (vLf125 << 0) | (vLf134 << 16); + c.ext2 = vHf; + c.ext3 = (LF_TUNING_CAP_Z << 0) | (HF_TUNING_CAP_Z << 16); + UsbSendPacket((BYTE *)&c, sizeof(c)); +} + +void SimulateTagLowFrequency(int period) +{ + int i; + BYTE *tab = (BYTE *)BigBuf; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); + + PIO_ENABLE = (1 << GPIO_SSC_DOUT) | (1 << GPIO_SSC_CLK); + + PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT); + PIO_OUTPUT_DISABLE = (1 << GPIO_SSC_CLK); + +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + + i = 0; + for(;;) { + while(!(PIO_PIN_DATA_STATUS & (1<0xFFF) { + DbpString("Tags can only have 44 bits."); + return; + } + fc(0,&n); + // special start of frame marker containing invalid bit sequences + fc(8, &n); fc(8, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 + fc(10, &n); fc(10, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 + + WDT_HIT(); + // manchester encode bits 43 to 32 + for (i=11; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + + WDT_HIT(); + // manchester encode bits 31 to 0 + for (i=31; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((lo>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } + + LED_A_ON(); + SimulateTagLowFrequency(n); + LED_A_OFF(); +} + +// loop to capture raw HID waveform then FSK demodulate the TAG ID from it +static void CmdHIDdemodFSK(void) +{ + BYTE *dest = (BYTE *)BigBuf; + int m=0, n=0, i=0, idx=0, found=0, lastval=0; + DWORD hi=0, lo=0; + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + for(;;) { + WDT_HIT(); + LED_A_ON(); + if(BUTTON_PRESS()) { + LED_A_OFF(); + return; + } + + i = 0; + m = sizeof(BigBuf); + memset(dest,128,m); + for(;;) { + if(SSC_STATUS & (SSC_STATUS_TX_READY)) { + SSC_TRANSMIT_HOLDING = 0x43; + LED_D_ON(); + } + if(SSC_STATUS & (SSC_STATUS_RX_READY)) { + dest[i] = (BYTE)SSC_RECEIVE_HOLDING; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; + i++; + LED_D_OFF(); + if(i >= m) { + break; + } + } + } + + // FSK demodulator + + // sync to first lo-hi transition + for( idx=1; idx>1)&0xffff); + hi=0; + lo=0; + found=0; + } + } + if (found) { + if (dest[idx] && (!dest[idx+1]) ) { + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|0; + } else if ( (!dest[idx]) && dest[idx+1]) { + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|1; + } else { + found=0; + hi=0; + lo=0; + } + idx++; + } + if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) + { + found=1; + idx+=6; + if (found && (hi|lo)) { + DbpString("TAG ID"); + DbpIntegers(hi, lo, (lo>>1)&0xffff); + hi=0; + lo=0; + found=0; + } + } + } + WDT_HIT(); + } +} + +void SimulateTagHfListen(void) +{ + BYTE *dest = (BYTE *)BigBuf; + int n = sizeof(BigBuf); + BYTE v = 0; + int i; + int p = 0; + + // We're using this mode just so that I can test it out; the simulated + // tag mode would work just as well and be simpler. + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + FpgaSetupSsc(); + + i = 0; + for(;;) { + if(SSC_STATUS & (SSC_STATUS_TX_READY)) { + SSC_TRANSMIT_HOLDING = 0xff; + } + if(SSC_STATUS & (SSC_STATUS_RX_READY)) { + BYTE r = (BYTE)SSC_RECEIVE_HOLDING; + + v <<= 1; + if(r & 1) { + v |= 1; + } + p++; + + if(p >= 8) { + dest[i] = v; + v = 0; + p = 0; + i++; + + if(i >= n) { + break; + } + } + } + } + DbpString("simulate tag (now type bitsamples)"); +} + +void UsbPacketReceived(BYTE *packet, int len) +{ + UsbCommand *c = (UsbCommand *)packet; + + switch(c->cmd) { + case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: + AcquireRawAdcSamples125k(c->ext1); + break; + + case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K: + ModThenAcquireRawAdcSamples125k(c->ext1,c->ext2,c->ext3,c->d.asBytes); + break; + + case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: + AcquireRawAdcSamplesIso15693(); + break; case CMD_BUFF_CLEAR: BufferClear(); break; - - case CMD_READER_ISO_15693: - ReaderIso15693(c->ext1); - break; - - case CMD_SIMTAG_ISO_15693: - SimTagIso15693(c->ext1); - break; - - case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: - AcquireRawAdcSamplesIso14443(c->ext1); - break; + + case CMD_READER_ISO_15693: + ReaderIso15693(c->ext1); + break; + + case CMD_SIMTAG_ISO_15693: + SimTagIso15693(c->ext1); + break; + + case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: + AcquireRawAdcSamplesIso14443(c->ext1); + break; case CMD_READ_SRI512_TAG: ReadSRI512Iso14443(c->ext1); break; - - case CMD_READER_ISO_14443a: - ReaderIso14443a(c->ext1); - break; - - case CMD_SNOOP_ISO_14443: - SnoopIso14443(); - break; - - case CMD_SNOOP_ISO_14443a: - SnoopIso14443a(); - break; - - case CMD_SIMULATE_TAG_HF_LISTEN: - SimulateTagHfListen(); - break; - - 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_MEASURE_ANTENNA_TUNING: - MeasureAntennaTuning(); - break; - - case CMD_HID_DEMOD_FSK: - CmdHIDdemodFSK(); // Demodulate HID tag - break; - - case CMD_HID_SIM_TAG: - CmdHIDsimTAG(c->ext1, c->ext2); // Simulate HID tag by ID - break; - - case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - LED_D_OFF(); // LED D indicates field ON or OFF - break; - - case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: - case CMD_DOWNLOAD_RAW_BITS_TI_TYPE: { - UsbCommand n; - if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) { - n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K; - } else { - n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE; - } - n.ext1 = c->ext1; - memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD)); - UsbSendPacket((BYTE *)&n, sizeof(n)); - break; - } - case CMD_DOWNLOADED_SIM_SAMPLES_125K: { - BYTE *b = (BYTE *)BigBuf; - memcpy(b+c->ext1, c->d.asBytes, 48); - break; - } - case CMD_SIMULATE_TAG_125K: - LED_A_ON(); - SimulateTagLowFrequency(c->ext1); - LED_A_OFF(); - break; -#ifdef WITH_LCD - case CMD_LCD_RESET: - LCDReset(); - break; -#endif - case CMD_SWEEP_LF: - SweepLFrange(); - break; - - case CMD_SET_LF_DIVISOR: - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->ext1); - break; -#ifdef WITH_LCD - case CMD_LCD: - LCDSend(c->ext1); - break; -#endif - case CMD_SETUP_WRITE: - case CMD_FINISH_WRITE: - case CMD_HARDWARE_RESET: - USB_D_PLUS_PULLUP_OFF(); - SpinDelay(1000); - SpinDelay(1000); - RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET; - for(;;) { - // We're going to reset, and the bootrom will take control. - } - break; - - - default: - DbpString("unknown command"); - break; - } -} - -void AppMain(void) -{ - memset(BigBuf,0,sizeof(BigBuf)); - SpinDelay(100); - - LED_D_OFF(); - LED_C_OFF(); - LED_B_OFF(); - LED_A_OFF(); - - UsbStart(); - - // The FPGA gets its clock from us from PCK0 output, so set that up. - PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0); - PIO_DISABLE = (1 << GPIO_PCK0); - PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0; - // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz - PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK | - PMC_CLK_PRESCALE_DIV_4; - PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0); - - // Reset SPI - SPI_CONTROL = SPI_CONTROL_RESET; - // Reset SSC - SSC_CONTROL = SSC_CONTROL_RESET; - - // Load the FPGA image, which we have stored in our flash. - FpgaDownloadAndGo(); - -#ifdef WITH_LCD - - LCDInit(); - - // test text on different colored backgrounds - LCDString(" The quick brown fox ", &FONT6x8,1,1+8*0,WHITE ,BLACK ); - LCDString(" jumped over the ", &FONT6x8,1,1+8*1,BLACK ,WHITE ); - LCDString(" lazy dog. ", &FONT6x8,1,1+8*2,YELLOW ,RED ); - LCDString(" AaBbCcDdEeFfGgHhIiJj ", &FONT6x8,1,1+8*3,RED ,GREEN ); - LCDString(" KkLlMmNnOoPpQqRrSsTt ", &FONT6x8,1,1+8*4,MAGENTA,BLUE ); - LCDString("UuVvWwXxYyZz0123456789", &FONT6x8,1,1+8*5,BLUE ,YELLOW); - LCDString("`-=[]_;',./~!@#$%^&*()", &FONT6x8,1,1+8*6,BLACK ,CYAN ); - LCDString(" _+{}|:\\\"<>? ",&FONT6x8,1,1+8*7,BLUE ,MAGENTA); - - // color bands - LCDFill(0, 1+8* 8, 132, 8, BLACK); - LCDFill(0, 1+8* 9, 132, 8, WHITE); - LCDFill(0, 1+8*10, 132, 8, RED); - LCDFill(0, 1+8*11, 132, 8, GREEN); - LCDFill(0, 1+8*12, 132, 8, BLUE); - LCDFill(0, 1+8*13, 132, 8, YELLOW); - LCDFill(0, 1+8*14, 132, 8, CYAN); - LCDFill(0, 1+8*15, 132, 8, MAGENTA); - -#endif - - for(;;) { - UsbPoll(FALSE); - WDT_HIT(); - } -} - -void SpinDelay(int ms) -{ - int ticks = (48000*ms) >> 10; - - // Borrow a PWM unit for my real-time clock - PWM_ENABLE = PWM_CHANNEL(0); - // 48 MHz / 1024 gives 46.875 kHz - PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10); - PWM_CH_DUTY_CYCLE(0) = 0; - PWM_CH_PERIOD(0) = 0xffff; - - WORD start = (WORD)PWM_CH_COUNTER(0); - - for(;;) { - WORD now = (WORD)PWM_CH_COUNTER(0); - if(now == (WORD)(start + ticks)) { - return; - } - WDT_HIT(); - } -} + + case CMD_READER_ISO_14443a: + ReaderIso14443a(c->ext1); + break; + + case CMD_SNOOP_ISO_14443: + SnoopIso14443(); + break; + + case CMD_SNOOP_ISO_14443a: + SnoopIso14443a(); + break; + + case CMD_SIMULATE_TAG_HF_LISTEN: + SimulateTagHfListen(); + break; + + 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_MEASURE_ANTENNA_TUNING: + MeasureAntennaTuning(); + break; + + case CMD_HID_DEMOD_FSK: + CmdHIDdemodFSK(); // Demodulate HID tag + break; + + case CMD_HID_SIM_TAG: + CmdHIDsimTAG(c->ext1, c->ext2); // Simulate HID tag by ID + break; + + case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + LED_D_OFF(); // LED D indicates field ON or OFF + break; + + case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: + case CMD_DOWNLOAD_RAW_BITS_TI_TYPE: { + UsbCommand n; + if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) { + n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K; + } else { + n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE; + } + n.ext1 = c->ext1; + memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD)); + UsbSendPacket((BYTE *)&n, sizeof(n)); + break; + } + case CMD_DOWNLOADED_SIM_SAMPLES_125K: { + BYTE *b = (BYTE *)BigBuf; + memcpy(b+c->ext1, c->d.asBytes, 48); + break; + } + case CMD_SIMULATE_TAG_125K: + LED_A_ON(); + SimulateTagLowFrequency(c->ext1); + LED_A_OFF(); + break; +#ifdef WITH_LCD + case CMD_LCD_RESET: + LCDReset(); + break; +#endif + case CMD_SWEEP_LF: + SweepLFrange(); + break; + + case CMD_SET_LF_DIVISOR: + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->ext1); + break; +#ifdef WITH_LCD + case CMD_LCD: + LCDSend(c->ext1); + break; +#endif + case CMD_SETUP_WRITE: + case CMD_FINISH_WRITE: + case CMD_HARDWARE_RESET: + USB_D_PLUS_PULLUP_OFF(); + SpinDelay(1000); + SpinDelay(1000); + RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET; + for(;;) { + // We're going to reset, and the bootrom will take control. + } + break; + + + default: + DbpString("unknown command"); + break; + } +} + +void AppMain(void) +{ + memset(BigBuf,0,sizeof(BigBuf)); + SpinDelay(100); + + LED_D_OFF(); + LED_C_OFF(); + LED_B_OFF(); + LED_A_OFF(); + + UsbStart(); + + // The FPGA gets its clock from us from PCK0 output, so set that up. + PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0); + PIO_DISABLE = (1 << GPIO_PCK0); + PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0; + // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz + PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK | + PMC_CLK_PRESCALE_DIV_4; + PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0); + + // Reset SPI + SPI_CONTROL = SPI_CONTROL_RESET; + // Reset SSC + SSC_CONTROL = SSC_CONTROL_RESET; + + // Load the FPGA image, which we have stored in our flash. + FpgaDownloadAndGo(); + +#ifdef WITH_LCD + + LCDInit(); + + // test text on different colored backgrounds + LCDString(" The quick brown fox ", &FONT6x8,1,1+8*0,WHITE ,BLACK ); + LCDString(" jumped over the ", &FONT6x8,1,1+8*1,BLACK ,WHITE ); + LCDString(" lazy dog. ", &FONT6x8,1,1+8*2,YELLOW ,RED ); + LCDString(" AaBbCcDdEeFfGgHhIiJj ", &FONT6x8,1,1+8*3,RED ,GREEN ); + LCDString(" KkLlMmNnOoPpQqRrSsTt ", &FONT6x8,1,1+8*4,MAGENTA,BLUE ); + LCDString("UuVvWwXxYyZz0123456789", &FONT6x8,1,1+8*5,BLUE ,YELLOW); + LCDString("`-=[]_;',./~!@#$%^&*()", &FONT6x8,1,1+8*6,BLACK ,CYAN ); + LCDString(" _+{}|:\\\"<>? ",&FONT6x8,1,1+8*7,BLUE ,MAGENTA); + + // color bands + LCDFill(0, 1+8* 8, 132, 8, BLACK); + LCDFill(0, 1+8* 9, 132, 8, WHITE); + LCDFill(0, 1+8*10, 132, 8, RED); + LCDFill(0, 1+8*11, 132, 8, GREEN); + LCDFill(0, 1+8*12, 132, 8, BLUE); + LCDFill(0, 1+8*13, 132, 8, YELLOW); + LCDFill(0, 1+8*14, 132, 8, CYAN); + LCDFill(0, 1+8*15, 132, 8, MAGENTA); + +#endif + + for(;;) { + UsbPoll(FALSE); + WDT_HIT(); + } +} + +void SpinDelayUs(int us) +{ + int ticks = (48*us) >> 10; + + // Borrow a PWM unit for my real-time clock + PWM_ENABLE = PWM_CHANNEL(0); + // 48 MHz / 1024 gives 46.875 kHz + PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10); + PWM_CH_DUTY_CYCLE(0) = 0; + PWM_CH_PERIOD(0) = 0xffff; + + WORD start = (WORD)PWM_CH_COUNTER(0); + + for(;;) { + WORD now = (WORD)PWM_CH_COUNTER(0); + if(now == (WORD)(start + ticks)) { + return; + } + WDT_HIT(); + } +} + +void SpinDelay(int ms) +{ + int ticks = (48000*ms) >> 10; + + // Borrow a PWM unit for my real-time clock + PWM_ENABLE = PWM_CHANNEL(0); + // 48 MHz / 1024 gives 46.875 kHz + PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10); + PWM_CH_DUTY_CYCLE(0) = 0; + PWM_CH_PERIOD(0) = 0xffff; + + WORD start = (WORD)PWM_CH_COUNTER(0); + + for(;;) { + WORD now = (WORD)PWM_CH_COUNTER(0); + if(now == (WORD)(start + ticks)) { + return; + } + WDT_HIT(); + } +} diff --git a/armsrc/apps.h b/armsrc/apps.h index 1dc22e51..01567b56 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -12,8 +12,11 @@ void AppMain(void); void DbpIntegers(int a, int b, int c); void DbpString(char *str); void SpinDelay(int ms); +void SpinDelayUs(int us); void ToSendStuffBit(int b); void ToSendReset(void); +void AcquireRawAdcSamples125k(BOOL at134khz); +void DoAcquisition125k(BOOL at134khz); extern int ToSendMax; extern BYTE ToSend[]; extern DWORD BigBuf[]; diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 78b48425..9dc4d3e2 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -48,6 +48,7 @@ typedef struct { #define CMD_HID_SIM_TAG 0x0209 // ## New command: simulate HID tag by ID #define CMD_SET_LF_DIVISOR 0x020A #define CMD_SWEEP_LF 0x020B +#define CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K 0x020C // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 diff --git a/winsrc/command.cpp b/winsrc/command.cpp index 3fa75431..1f77c488 100644 --- a/winsrc/command.cpp +++ b/winsrc/command.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "prox.h" #include "../common/iso14443_crc.c" @@ -535,6 +536,21 @@ static void CmdLoread(char *str) SendCommand(&c, FALSE); } +/* send a command before reading */ +static void CmdLoCommandRead(char *str) +{ + static char dummy[3]; + + dummy[0]= ' '; + + UsbCommand c; + c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K; + sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, &c.d.asBytes,&dummy+1); + // in case they specified 'h' + strcpy(&c.d.asBytes + strlen(c.d.asBytes),dummy); + SendCommand(&c, FALSE); +} + static void CmdLosamples(char *str) { int cnt = 0; @@ -2065,7 +2081,7 @@ static void Cmdmanchestermod(char *str) * Typical values can be 64, 32, 128... */ static void Cmdmanchesterdemod(char *str) { - int i, j, invert= 0; + int i, j; int bit; int clock; int lastval; @@ -2077,16 +2093,6 @@ static void Cmdmanchesterdemod(char *str) { int bit2idx = 0; int warnings = 0; - /* check if we're inverting output */ - if(*str == 'i') - { - PrintToScrollback("Inverting output"); - invert= 1; - do - ++str; - while(*str == ' '); // in case a 2nd argument was given - } - /* Holds the decoded bitstream: each clock period contains 2 bits */ /* later simplified to 1 bit after manchester decoding. */ /* Add 10 bits to allow for noisy / uncertain traces without aborting */ @@ -2157,7 +2163,7 @@ static void Cmdmanchesterdemod(char *str) { if (!hithigh || !hitlow) bit ^= 1; - BitStream[bit2idx++] = bit ^ invert; + BitStream[bit2idx++] = bit; } } @@ -2165,7 +2171,7 @@ static void Cmdmanchesterdemod(char *str) { else { - /* Then detect duration between 2 successive transitions */ + /* Then detect duration between 2 successive transitions */ for (bitidx = 1; i < GraphTraceLen; i++) { if (GraphBuffer[i-1] != GraphBuffer[i]) @@ -2200,18 +2206,18 @@ static void Cmdmanchesterdemod(char *str) { PrintToScrollback("Error: too many detection errors, aborting."); return; } - } } } + } - // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream - // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful - // to stop output at the final bitidx2 value, not bitidx - for (i = 0; i < bitidx; i += 2) { - if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { - BitStream[bit2idx++] = 1 ^ invert; + // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream + // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful + // to stop output at the final bitidx2 value, not bitidx + for (i = 0; i < bitidx; i += 2) { + if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { + BitStream[bit2idx++] = 1; } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { - BitStream[bit2idx++] = 0 ^ invert; + BitStream[bit2idx++] = 0; } else { // We cannot end up in this state, this means we are unsynchronized, // move up 1 bit: @@ -2225,8 +2231,8 @@ static void Cmdmanchesterdemod(char *str) { PrintToScrollback("Error: too many decode errors, aborting."); return; } - } - } + } + } } PrintToScrollback("Manchester decoded bitstream"); @@ -2450,11 +2456,12 @@ static struct { "lcd", CmdLcd,0, " -- Send command/data to LCD", "lcdreset", CmdLcdReset,0, " Hardware reset LCD", "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)", "losamples", CmdLosamples,0, "[128 - 16000] -- Get raw samples for LF tag", "losim", CmdLosim,0, " Simulate LF tag", "ltrim", CmdLtrim,1, " -- Trim samples from left of trace", - "mandemod", Cmdmanchesterdemod,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)", + "mandemod", Cmdmanchesterdemod,1, "[clock rate] -- Try a Manchester demodulation on a binary stream", "manmod", Cmdmanchestermod,1, "[clock rate] -- Manchester modulate a binary stream", "norm", CmdNorm,1, " Normalize max/min to +/-500", "plot", CmdPlot,1, " Show graph window", diff --git a/winsrc/prox.h b/winsrc/prox.h index e93975de..a9f3a2ef 100644 --- a/winsrc/prox.h +++ b/winsrc/prox.h @@ -51,6 +51,7 @@ int CmdClearGraph(int redraw); static void CmdAppendGraph(int redraw, int clock, int bit); static void CmdEM410xsim(char *str); static void CmdLosim(char *str); +static void CmdLoCommandRead(char *str); static void CmdLoread(char *str); static void CmdLosamples(char *str); static void CmdBitsamples(char *str);