-//-----------------------------------------------------------------------------
-// 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 <proxmark3.h>
-#include <stdlib.h>
-#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];
-int usbattached = 0;
-
-//=============================================================================
-// 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)
-{
- memset(BigBuf,0,sizeof(BigBuf));
- 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)
-{
- /* this holds up stuff unless we're connected to usb */
-// if (!usbattached)
-// return;
-
- 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)
-{
- /* this holds up stuff unless we're connected to usb */
-// if (!usbattached)
-// return;
-
- 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);
- } else {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- }
-
- // 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((char *) command) - 1] == 'h')
- at134khz= TRUE;
- else
- at134khz= FALSE;
-
- if(at134khz) {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- } else {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- }
-
- // 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);
- } else {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- }
- 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);
- } else {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- }
-
- // now do the read
- DoAcquisition125k(at134khz);
-}
-
-void AcquireTiType(void)
-{
- int i;
- int n = 5000;
-
- // clear buffer
- memset(BigBuf,0,sizeof(BigBuf));
-
- // Set up the synchronous serial port
- PIO_DISABLE = (1<<GPIO_SSC_DIN);
- PIO_PERIPHERAL_A_SEL = (1<<GPIO_SSC_DIN);
-
- // steal this pin from the SSP and use it to control the modulation
- PIO_ENABLE = (1<<GPIO_SSC_DOUT);
- PIO_OUTPUT_ENABLE = (1<<GPIO_SSC_DOUT);
-
- SSC_CONTROL = SSC_CONTROL_RESET;
- SSC_CONTROL = SSC_CONTROL_RX_ENABLE | SSC_CONTROL_TX_ENABLE;
-
- // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long
- // 48/2 = 24 MHz clock must be divided by 12
- SSC_CLOCK_DIVISOR = 12;
-
- SSC_RECEIVE_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(0);
- SSC_RECEIVE_FRAME_MODE = SSC_FRAME_MODE_BITS_IN_WORD(32) | SSC_FRAME_MODE_MSB_FIRST;
- SSC_TRANSMIT_CLOCK_MODE = 0;
- SSC_TRANSMIT_FRAME_MODE = 0;
-
- LED_D_ON();
-
- // modulate antenna
- PIO_OUTPUT_DATA_SET = (1<<GPIO_SSC_DOUT);
-
- // Charge TI tag for 50ms.
- SpinDelay(50);
-
- // stop modulating antenna and listen
- PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_SSC_DOUT);
-
- LED_D_OFF();
-
- i = 0;
- for(;;) {
- if(SSC_STATUS & SSC_STATUS_RX_READY) {
- BigBuf[i] = SSC_RECEIVE_HOLDING; // store 32 bit values in buffer
- i++; if(i >= n) return;
- }
- WDT_HIT();
- }
-
- // return stolen pin ro SSP
- PIO_DISABLE = (1<<GPIO_SSC_DOUT);
- PIO_PERIPHERAL_A_SEL = (1<<GPIO_SSC_DIN) | (1<<GPIO_SSC_DOUT);
-}
-
-void AcquireRawBitsTI(void)
-{
- LED_D_ON();
- // TI tags charge at 134.2Khz
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
- // Place FPGA in passthrough mode, in this mode the CROSS_LO line
- // connects to SSP_DIN and the SSP_DOUT logic level controls
- // whether we're modulating the antenna (high)
- // or listening to the antenna (low)
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
-
- // get TI tag data into the buffer
- AcquireTiType();
-
- FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-}
-
-//-----------------------------------------------------------------------------
-// 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 MeasureAntennaTuning(void)
-{
- BYTE *dest = (BYTE *)BigBuf;
- int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;
- int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
-
- UsbCommand c;
-
- DbpString("Measuring antenna characteristics, please wait.");
- memset(BigBuf,0,sizeof(BigBuf));
-
-/*
- * Sweeps the useful LF range of the proxmark from
- * 46.8kHz (divisor=255) to 600kHz (divisor=19) and
- * read the voltage in the antenna, the result left
- * in the buffer is a graph which should clearly show
- * the resonating frequency of your LF antenna
- * ( hopefully around 95 if it is tuned to 125kHz!)
- */
- FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
- for (i=255; i>19; i--) {
- FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
- SpinDelay(20);
- // Vref = 3.3V, and a 10000:240 voltage divider on the input
- // can measure voltages up to 137500 mV
- adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);
- if (i==95) vLf125 = adcval; // voltage at 125Khz
- if (i==89) vLf134 = adcval; // voltage at 134Khz
-
- dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes
- if(dest[i] > peak) {
- peakv = adcval;
- peak = dest[i];
- peakf = i;
- ptr = i;
- }
- }
-
- // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
- SpinDelay(20);
- // Vref = 3300mV, and an 10:1 voltage divider on the input
- // can measure voltages up to 33000 mV
- vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
-
- c.cmd = CMD_MEASURED_ANTENNA_TUNING;
- c.ext1 = (vLf125 << 0) | (vLf134 << 16);
- c.ext2 = vHf;
- c.ext3 = peakf | (peakv << 16);
- UsbSendPacket((BYTE *)&c, sizeof(c));
-}
-
-void SimulateTagLowFrequency(int period, int ledcontrol)
-{
- 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<<GPIO_SSC_CLK))) {
- if(BUTTON_PRESS()) {
- DbpString("Stopped");
- return;
- }
- WDT_HIT();
- }
-
- if (ledcontrol)
- LED_D_ON();
-
- if(tab[i])
- OPEN_COIL();
- else
- SHORT_COIL();
-
- if (ledcontrol)
- LED_D_OFF();
-
- while(PIO_PIN_DATA_STATUS & (1<<GPIO_SSC_CLK)) {
- if(BUTTON_PRESS()) {
- DbpString("Stopped");
- return;
- }
- WDT_HIT();
- }
-
- i++;
- if(i == period) i = 0;
- }
-}
-
-// compose fc/8 fc/10 waveform
-static void fc(int c, int *n) {
- BYTE *dest = (BYTE *)BigBuf;
- int idx;
-
- // for when we want an fc8 pattern every 4 logical bits
- if(c==0) {
- dest[((*n)++)]=1;
- dest[((*n)++)]=1;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- }
- // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples
- if(c==8) {
- for (idx=0; idx<6; idx++) {
- dest[((*n)++)]=1;
- dest[((*n)++)]=1;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- }
- }
-
- // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples
- if(c==10) {
- for (idx=0; idx<5; idx++) {
- dest[((*n)++)]=1;
- dest[((*n)++)]=1;
- dest[((*n)++)]=1;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- dest[((*n)++)]=0;
- }
- }
-}
-
-// prepare a waveform pattern in the buffer based on the ID given then
-// simulate a HID tag until the button is pressed
-static void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
-{
- int n=0, i=0;
- /*
- HID tag bitstream format
- The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits
- A 1 bit is represented as 6 fc8 and 5 fc10 patterns
- A 0 bit is represented as 5 fc10 and 6 fc8 patterns
- A fc8 is inserted before every 4 bits
- A special start of frame pattern is used consisting a0b0 where a and b are neither 0
- nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)
- */
-
- if (hi>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
- }
- }
-
- if (ledcontrol)
- LED_A_ON();
- SimulateTagLowFrequency(n, ledcontrol);
-
- if (ledcontrol)
- LED_A_OFF();
-}
-
-// loop to capture raw HID waveform then FSK demodulate the TAG ID from it
-static void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
-{
- 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);
-
- // 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();
- if (ledcontrol)
- LED_A_ON();
- if(BUTTON_PRESS()) {
- DbpString("Stopped");
- if (ledcontrol)
- 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;
- if (ledcontrol)
- 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++;
- if (ledcontrol)
- LED_D_OFF();
- if(i >= m) {
- break;
- }
- }
- }
-
- // FSK demodulator
-
- // sync to first lo-hi transition
- for( idx=1; idx<m; idx++) {
- if (dest[idx-1]<dest[idx])
- lastval=idx;
- break;
- }
- WDT_HIT();
-
- // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
- // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere
- // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
- for( i=0; idx<m; idx++) {
- if (dest[idx-1]<dest[idx]) {
- dest[i]=idx-lastval;
- if (dest[i] <= 8) {
- dest[i]=1;
- } else {
- dest[i]=0;
- }
-
- lastval=idx;
- i++;
- }
- }
- m=i;
- WDT_HIT();
-
- // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns
- lastval=dest[0];
- idx=0;
- i=0;
- n=0;
- for( idx=0; idx<m; idx++) {
- if (dest[idx]==lastval) {
- n++;
- } else {
- // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,
- // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets
- // swallowed up by rounding
- // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding
- // special start of frame markers use invalid manchester states (no transitions) by using sequences
- // like 111000
- if (dest[idx-1]) {
- n=(n+1)/6; // fc/8 in sets of 6
- } else {
- n=(n+1)/5; // fc/10 in sets of 5
- }
- switch (n) { // stuff appropriate bits in buffer
- case 0:
- case 1: // one bit
- dest[i++]=dest[idx-1];
- break;
- case 2: // two bits
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- break;
- case 3: // 3 bit start of frame markers
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- break;
- // When a logic 0 is immediately followed by the start of the next transmisson
- // (special pattern) a pattern of 4 bit duration lengths is created.
- case 4:
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- dest[i++]=dest[idx-1];
- break;
- default: // this shouldn't happen, don't stuff any bits
- break;
- }
- n=0;
- lastval=dest[idx];
- }
- }
- m=i;
- WDT_HIT();
-
- // final loop, go over previously decoded manchester data and decode into usable tag ID
- // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0
- for( idx=0; idx<m-6; idx++) {
- // search for a start of frame marker
- 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);
- /* if we're only looking for one tag */
- if (findone)
- {
- *high = hi;
- *low = lo;
- return;
- }
- 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);
- /* if we're only looking for one tag */
- if (findone)
- {
- *high = hi;
- *low = lo;
- return;
- }
- 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_BITS_TI_TYPE:
- AcquireRawBitsTI();
- 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_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_LISTEN_READER_FIELD:
- ListenReaderField(c->ext1);
- break;
-
- case CMD_HID_DEMOD_FSK:
- CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
- break;
-
- case CMD_HID_SIM_TAG:
- CmdHIDsimTAG(c->ext1, c->ext2, 1); // 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, 1);
- LED_A_OFF();
- break;
-#ifdef WITH_LCD
- case CMD_LCD_RESET:
- LCDReset();
- break;
-#endif
- case CMD_READ_MEM:
- ReadMem(c->ext1);
- 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 ReadMem(int addr)
-{
- const DWORD *data = ((DWORD *)addr);
- int i;
-
- DbpString("Reading memory at address");
- DbpIntegers(0, 0, addr);
- for (i = 0; i < 8; i+= 2)
- DbpIntegers(0, data[i], data[i+1]);
-}
-
-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(;;) {
- usbattached = UsbPoll(FALSE);
- WDT_HIT();
-
- if (BUTTON_HELD(1000) > 0)
- SamyRun();
- }
-}
-
-
-// samy's sniff and repeat routine
-void SamyRun()
-{
- DbpString("Stand-alone mode! No PC necessary.");
-
- // 3 possible options? no just 2 for now
-#define OPTS 2
-
- int high[OPTS], low[OPTS];
-
- // Oooh pretty -- notify user we're in elite samy mode now
- LED(LED_RED, 200);
- LED(LED_ORANGE, 200);
- LED(LED_GREEN, 200);
- LED(LED_ORANGE, 200);
- LED(LED_RED, 200);
- LED(LED_ORANGE, 200);
- LED(LED_GREEN, 200);
- LED(LED_ORANGE, 200);
- LED(LED_RED, 200);
-
- int selected = 0;
- int playing = 0;
-
- // Turn on selected LED
- LED(selected + 1, 0);
-
- for (;;)
- {
- usbattached = UsbPoll(FALSE);
- WDT_HIT();
-
- // Was our button held down or pressed?
- int button_pressed = BUTTON_HELD(1000);
- SpinDelay(300);
-
- // Button was held for a second, begin recording
- if (button_pressed > 0)
- {
- LEDsoff();
- LED(selected + 1, 0);
- LED(LED_RED2, 0);
-
- // record
- DbpString("Starting recording");
-
- // wait for button to be released
- while(BUTTON_PRESS())
- WDT_HIT();
-
- /* need this delay to prevent catching some weird data */
- SpinDelay(500);
-
- CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
- DbpString("Recorded");
- DbpIntegers(selected, high[selected], low[selected]);
-
- LEDsoff();
- LED(selected + 1, 0);
- // Finished recording
-
- // If we were previously playing, set playing off
- // so next button push begins playing what we recorded
- playing = 0;
- }
-
- // Change where to record (or begin playing)
- else if (button_pressed)
- {
- // Next option if we were previously playing
- if (playing)
- selected = (selected + 1) % OPTS;
- playing = !playing;
-
- LEDsoff();
- LED(selected + 1, 0);
-
- // Begin transmitting
- if (playing)
- {
- LED(LED_GREEN, 0);
- DbpString("Playing");
- // wait for button to be released
- while(BUTTON_PRESS())
- WDT_HIT();
- DbpIntegers(selected, high[selected], low[selected]);
- CmdHIDsimTAG(high[selected], low[selected], 0);
- DbpString("Done playing");
- if (BUTTON_HELD(1000) > 0)
- {
- DbpString("Exiting");
- LEDsoff();
- return;
- }
-
- /* We pressed a button so ignore it here with a delay */
- SpinDelay(300);
-
- // when done, we're done playing, move to next option
- selected = (selected + 1) % OPTS;
- playing = !playing;
- LEDsoff();
- LED(selected + 1, 0);
- }
- else
- while(BUTTON_PRESS())
- WDT_HIT();
- }
- }
-}
-
-
-/* \r
+//-----------------------------------------------------------------------------\r
+// The main application code. This is the first thing called after start.c\r
+// executes.\r
+// Jonathan Westhues, Mar 2006\r
+// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
+//-----------------------------------------------------------------------------\r
+\r
+#include <proxmark3.h>\r
+#include <stdlib.h>\r
+#include "apps.h"\r
+#include "legicrf.h"\r
+#ifdef WITH_LCD\r
+#include "fonts.h"\r
+#include "LCD.h"\r
+#endif\r
+\r
+#define va_list __builtin_va_list\r
+#define va_start __builtin_va_start\r
+#define va_arg __builtin_va_arg\r
+#define va_end __builtin_va_end\r
+int kvsprintf(char const *fmt, void *arg, int radix, va_list ap);\r
+ \r
+//=============================================================================\r
+// A buffer where we can queue things up to be sent through the FPGA, for\r
+// any purpose (fake tag, as reader, whatever). We go MSB first, since that\r
+// is the order in which they go out on the wire.\r
+//=============================================================================\r
+\r
+BYTE ToSend[512];\r
+int ToSendMax;\r
+static int ToSendBit;\r
+struct common_area common_area __attribute__((section(".commonarea")));\r
+\r
+void BufferClear(void)\r
+{\r
+ memset(BigBuf,0,sizeof(BigBuf));\r
+ Dbprintf("Buffer cleared (%i bytes)",sizeof(BigBuf));\r
+}\r
+\r
+void ToSendReset(void)\r
+{\r
+ ToSendMax = -1;\r
+ ToSendBit = 8;\r
+}\r
+\r
+void ToSendStuffBit(int b)\r
+{\r
+ if(ToSendBit >= 8) {\r
+ ToSendMax++;\r
+ ToSend[ToSendMax] = 0;\r
+ ToSendBit = 0;\r
+ }\r
+\r
+ if(b) {\r
+ ToSend[ToSendMax] |= (1 << (7 - ToSendBit));\r
+ }\r
+\r
+ ToSendBit++;\r
+\r
+ if(ToSendBit >= sizeof(ToSend)) {\r
+ ToSendBit = 0;\r
+ DbpString("ToSendStuffBit overflowed!");\r
+ }\r
+}\r
+\r
+//=============================================================================\r
+// Debug print functions, to go out over USB, to the usual PC-side client.\r
+//=============================================================================\r
+\r
+void DbpString(char *str)\r
+{\r
+ /* this holds up stuff unless we're connected to usb */\r
+ if (!UsbConnected())\r
+ return;\r
+\r
+ UsbCommand c;\r
+ c.cmd = CMD_DEBUG_PRINT_STRING;\r
+ c.arg[0] = strlen(str);\r
+ if(c.arg[0] > sizeof(c.d.asBytes)) {\r
+ c.arg[0] = sizeof(c.d.asBytes);\r
+ }\r
+ memcpy(c.d.asBytes, str, c.arg[0]);\r
+\r
+ UsbSendPacket((BYTE *)&c, sizeof(c));\r
+ // TODO fix USB so stupid things like this aren't req'd\r
+ SpinDelay(50);\r
+}\r
+\r
+#if 0\r
+void DbpIntegers(int x1, int x2, int x3)\r
+{\r
+ /* this holds up stuff unless we're connected to usb */\r
+ if (!UsbConnected())\r
+ return;\r
+\r
+ UsbCommand c;\r
+ c.cmd = CMD_DEBUG_PRINT_INTEGERS;\r
+ c.arg[0] = x1;\r
+ c.arg[1] = x2;\r
+ c.arg[2] = x3;\r
+\r
+ UsbSendPacket((BYTE *)&c, sizeof(c));\r
+ // XXX\r
+ SpinDelay(50);\r
+}\r
+#endif\r
+\r
+void Dbprintf(const char *fmt, ...) {\r
+// should probably limit size here; oh well, let's just use a big buffer\r
+ char output_string[128];\r
+ va_list ap;\r
+\r
+ va_start(ap, fmt);\r
+ kvsprintf(fmt, output_string, 10, ap);\r
+ va_end(ap);\r
+ \r
+ DbpString(output_string);\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Read an ADC channel and block till it completes, then return the result\r
+// in ADC units (0 to 1023). Also a routine to average 32 samples and\r
+// return that.\r
+//-----------------------------------------------------------------------------\r
+static int ReadAdc(int ch)\r
+{\r
+ DWORD d;\r
+\r
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;\r
+ AT91C_BASE_ADC->ADC_MR =\r
+ ADC_MODE_PRESCALE(32) |\r
+ ADC_MODE_STARTUP_TIME(16) |\r
+ ADC_MODE_SAMPLE_HOLD_TIME(8);\r
+ AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);\r
+\r
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;\r
+ while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch)))\r
+ ;\r
+ d = AT91C_BASE_ADC->ADC_CDR[ch];\r
+\r
+ return d;\r
+}\r
+\r
+static int AvgAdc(int ch)\r
+{\r
+ int i;\r
+ int a = 0;\r
+\r
+ for(i = 0; i < 32; i++) {\r
+ a += ReadAdc(ch);\r
+ }\r
+\r
+ return (a + 15) >> 5;\r
+}\r
+\r
+void MeasureAntennaTuning(void)\r
+{\r
+ BYTE *dest = (BYTE *)BigBuf;\r
+ int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;\r
+ int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV\r
+\r
+ UsbCommand c;\r
+\r
+ DbpString("Measuring antenna characteristics, please wait.");\r
+ memset(BigBuf,0,sizeof(BigBuf));\r
+\r
+/*\r
+ * Sweeps the useful LF range of the proxmark from\r
+ * 46.8kHz (divisor=255) to 600kHz (divisor=19) and\r
+ * read the voltage in the antenna, the result left\r
+ * in the buffer is a graph which should clearly show\r
+ * the resonating frequency of your LF antenna\r
+ * ( hopefully around 95 if it is tuned to 125kHz!)\r
+ */\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);\r
+ for (i=255; i>19; i--) {\r
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);\r
+ SpinDelay(20);\r
+ // Vref = 3.3V, and a 10000:240 voltage divider on the input\r
+ // can measure voltages up to 137500 mV\r
+ adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);\r
+ if (i==95) vLf125 = adcval; // voltage at 125Khz\r
+ if (i==89) vLf134 = adcval; // voltage at 134Khz\r
+\r
+ dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes\r
+ if(dest[i] > peak) {\r
+ peakv = adcval;\r
+ peak = dest[i];\r
+ peakf = i;\r
+ ptr = i;\r
+ }\r
+ }\r
+\r
+ // Let the FPGA drive the high-frequency antenna around 13.56 MHz.\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ SpinDelay(20);\r
+ // Vref = 3300mV, and an 10:1 voltage divider on the input\r
+ // can measure voltages up to 33000 mV\r
+ vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;\r
+\r
+ c.cmd = CMD_MEASURED_ANTENNA_TUNING;\r
+ c.arg[0] = (vLf125 << 0) | (vLf134 << 16);\r
+ c.arg[1] = vHf;\r
+ c.arg[2] = peakf | (peakv << 16);\r
+ UsbSendPacket((BYTE *)&c, sizeof(c));\r
+}\r
+\r
+void MeasureAntennaTuningHf(void)\r
+{\r
+ int vHf = 0; // in mV\r
+\r
+ DbpString("Measuring HF antenna, press button to exit");\r
+\r
+ for (;;) {\r
+ // Let the FPGA drive the high-frequency antenna around 13.56 MHz.\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ SpinDelay(20);\r
+ // Vref = 3300mV, and an 10:1 voltage divider on the input\r
+ // can measure voltages up to 33000 mV\r
+ vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;\r
+ \r
+ Dbprintf("%d mV",vHf);\r
+ if (BUTTON_PRESS()) break;\r
+ }\r
+ DbpString("cancelled");\r
+}\r
+\r
+\r
+void SimulateTagHfListen(void)\r
+{\r
+ BYTE *dest = (BYTE *)BigBuf;\r
+ int n = sizeof(BigBuf);\r
+ BYTE v = 0;\r
+ int i;\r
+ int p = 0;\r
+\r
+ // We're using this mode just so that I can test it out; the simulated\r
+ // tag mode would work just as well and be simpler.\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);\r
+\r
+ // We need to listen to the high-frequency, peak-detected path.\r
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+ FpgaSetupSsc();\r
+\r
+ i = 0;\r
+ for(;;) {\r
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {\r
+ AT91C_BASE_SSC->SSC_THR = 0xff;\r
+ }\r
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {\r
+ BYTE r = (BYTE)AT91C_BASE_SSC->SSC_RHR;\r
+\r
+ v <<= 1;\r
+ if(r & 1) {\r
+ v |= 1;\r
+ }\r
+ p++;\r
+\r
+ if(p >= 8) {\r
+ dest[i] = v;\r
+ v = 0;\r
+ p = 0;\r
+ i++;\r
+\r
+ if(i >= n) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ DbpString("simulate tag (now type bitsamples)");\r
+}\r
+\r
+void ReadMem(int addr)\r
+{\r
+ const BYTE *data = ((BYTE *)addr);\r
+\r
+ Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",\r
+ addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);\r
+}\r
+\r
+/* osimage version information is linked in */\r
+extern struct version_information version_information;\r
+/* bootrom version information is pointed to from _bootphase1_version_pointer */\r
+extern char *_bootphase1_version_pointer, _flash_start, _flash_end;\r
+void SendVersion(void)\r
+{\r
+ char temp[48]; /* Limited data payload in USB packets */\r
+ DbpString("Prox/RFID mark3 RFID instrument");\r
+ \r
+ /* Try to find the bootrom version information. Expect to find a pointer at \r
+ * symbol _bootphase1_version_pointer, perform slight sanity checks on the\r
+ * pointer, then use it.\r
+ */\r
+ char *bootrom_version = *(char**)&_bootphase1_version_pointer;\r
+ if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {\r
+ DbpString("bootrom version information appears invalid");\r
+ } else {\r
+ FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);\r
+ DbpString(temp);\r
+ }\r
+ \r
+ FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);\r
+ DbpString(temp);\r
+ \r
+ FpgaGatherVersion(temp, sizeof(temp));\r
+ DbpString(temp);\r
+}\r
+\r
+#ifdef WITH_LF\r
+// samy's sniff and repeat routine\r
+void SamyRun()\r
+{\r
+ DbpString("Stand-alone mode! No PC necessary.");\r
+\r
+ // 3 possible options? no just 2 for now\r
+#define OPTS 2\r
+\r
+ int high[OPTS], low[OPTS];\r
+\r
+ // Oooh pretty -- notify user we're in elite samy mode now\r
+ LED(LED_RED, 200);\r
+ LED(LED_ORANGE, 200);\r
+ LED(LED_GREEN, 200);\r
+ LED(LED_ORANGE, 200);\r
+ LED(LED_RED, 200);\r
+ LED(LED_ORANGE, 200);\r
+ LED(LED_GREEN, 200);\r
+ LED(LED_ORANGE, 200);\r
+ LED(LED_RED, 200);\r
+\r
+ int selected = 0;\r
+ int playing = 0;\r
+\r
+ // Turn on selected LED\r
+ LED(selected + 1, 0);\r
+\r
+ for (;;)\r
+ {\r
+ UsbPoll(FALSE);\r
+ WDT_HIT();\r
+\r
+ // Was our button held down or pressed?\r
+ int button_pressed = BUTTON_HELD(1000);\r
+ SpinDelay(300);\r
+\r
+ // Button was held for a second, begin recording\r
+ if (button_pressed > 0)\r
+ {\r
+ LEDsoff();\r
+ LED(selected + 1, 0);\r
+ LED(LED_RED2, 0);\r
+\r
+ // record\r
+ DbpString("Starting recording");\r
+\r
+ // wait for button to be released\r
+ while(BUTTON_PRESS())\r
+ WDT_HIT();\r
+\r
+ /* need this delay to prevent catching some weird data */\r
+ SpinDelay(500);\r
+\r
+ CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);\r
+ Dbprintf("Recorded %x %x %x", selected, high[selected], low[selected]);\r
+\r
+ LEDsoff();\r
+ LED(selected + 1, 0);\r
+ // Finished recording\r
+\r
+ // If we were previously playing, set playing off\r
+ // so next button push begins playing what we recorded\r
+ playing = 0;\r
+ }\r
+\r
+ // Change where to record (or begin playing)\r
+ else if (button_pressed)\r
+ {\r
+ // Next option if we were previously playing\r
+ if (playing)\r
+ selected = (selected + 1) % OPTS;\r
+ playing = !playing;\r
+\r
+ LEDsoff();\r
+ LED(selected + 1, 0);\r
+\r
+ // Begin transmitting\r
+ if (playing)\r
+ {\r
+ LED(LED_GREEN, 0);\r
+ DbpString("Playing");\r
+ // wait for button to be released\r
+ while(BUTTON_PRESS())\r
+ WDT_HIT();\r
+ Dbprintf("%x %x %x", selected, high[selected], low[selected]);\r
+ CmdHIDsimTAG(high[selected], low[selected], 0);\r
+ DbpString("Done playing");\r
+ if (BUTTON_HELD(1000) > 0)\r
+ {\r
+ DbpString("Exiting");\r
+ LEDsoff();\r
+ return;\r
+ }\r
+\r
+ /* We pressed a button so ignore it here with a delay */\r
+ SpinDelay(300);\r
+\r
+ // when done, we're done playing, move to next option\r
+ selected = (selected + 1) % OPTS;\r
+ playing = !playing;\r
+ LEDsoff();\r
+ LED(selected + 1, 0);\r
+ }\r
+ else\r
+ while(BUTTON_PRESS())\r
+ WDT_HIT();\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+/*\r
OBJECTIVE\r
Listen and detect an external reader. Determine the best location\r
for the antenna.\r
\r
INSTRUCTIONS:\r
-Inside the ListenReaderField() function, there is two mode. \r
+Inside the ListenReaderField() function, there is two mode.\r
By default, when you call the function, you will enter mode 1.\r
If you press the PM3 button one time, you will enter mode 2.\r
If you press the PM3 button a second time, you will exit the function.\r
\r
DESCRIPTION OF MODE 1:\r
-This mode just listens for an external reader field and lights up green \r
+This mode just listens for an external reader field and lights up green\r
for HF and/or red for LF. This is the original mode of the detectreader\r
function.\r
\r
DESCRIPTION OF MODE 2:\r
This mode will visually represent, using the LEDs, the actual strength of the\r
-current compared to the maximum current detected. Basically, once you know \r
+current compared to the maximum current detected. Basically, once you know\r
what kind of external reader is present, it will help you spot the best location to place\r
your antenna. You will probably not get some good results if there is a LF and a HF reader\r
at the same place! :-)\r
\r
LIGHT SCHEME USED:\r
-\r
-Light scheme | Descriptiong\r
-----------------------------------------------------\r
- ---- | No field detected\r
- X--- | 14% of maximum current detected\r
- -X-- | 29% of maximum current detected\r
- --X- | 43% of maximum current detected\r
- ---X | 57% of maximum current detected\r
- --XX | 71% of maximum current detected\r
- -XXX | 86% of maximum current detected\r
- XXXX | 100% of maximum current detected\r
-\r
-TODO:\r
-Add the LF part for MODE 2\r
-\r
*/\r
+static const char LIGHT_SCHEME[] = {\r
+ 0x0, /* ---- | No field detected */\r
+ 0x1, /* X--- | 14% of maximum current detected */\r
+ 0x2, /* -X-- | 29% of maximum current detected */\r
+ 0x4, /* --X- | 43% of maximum current detected */\r
+ 0x8, /* ---X | 57% of maximum current detected */\r
+ 0xC, /* --XX | 71% of maximum current detected */\r
+ 0xE, /* -XXX | 86% of maximum current detected */\r
+ 0xF, /* XXXX | 100% of maximum current detected */\r
+};\r
+static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);\r
+\r
void ListenReaderField(int limit)\r
{\r
- int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0;\r
+ int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;\r
int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;\r
- int mode=1;\r
+ int mode=1, display_val, display_max, i;\r
\r
#define LF_ONLY 1\r
#define HF_ONLY 2\r
\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
+ LEDsoff();\r
\r
- lf_av= ReadAdc(ADC_CHAN_LF);\r
+ lf_av=lf_max=ReadAdc(ADC_CHAN_LF);\r
\r
- if(limit != HF_ONLY) \r
- {\r
- DbpString("LF 125/134 Baseline:");\r
- DbpIntegers(lf_av,0,0);\r
- lf_baseline= lf_av;\r
- }\r
+ if(limit != HF_ONLY) {\r
+ Dbprintf("LF 125/134 Baseline: %d", lf_av);\r
+ lf_baseline = lf_av;\r
+ }\r
\r
hf_av=hf_max=ReadAdc(ADC_CHAN_HF);\r
\r
- if (limit != LF_ONLY) \r
- {\r
- DbpString("HF 13.56 Baseline:");\r
- DbpIntegers(hf_av,0,0);\r
- hf_baseline= hf_av;\r
- }\r
+ if (limit != LF_ONLY) {\r
+ Dbprintf("HF 13.56 Baseline: %d", hf_av);\r
+ hf_baseline = hf_av;\r
+ }\r
\r
- for(;;) \r
- {\r
+ for(;;) {\r
if (BUTTON_PRESS()) {\r
SpinDelay(500);\r
switch (mode) {\r
case 1:\r
mode=2;\r
- DbpString("Signal Strength Mode");
+ DbpString("Signal Strength Mode");\r
break;\r
case 2:\r
default:\r
DbpString("Stopped");\r
- LED_A_OFF();\r
- LED_B_OFF();\r
- LED_C_OFF();\r
- LED_D_OFF();\r
+ LEDsoff();\r
return;\r
break;\r
}\r
}\r
WDT_HIT();\r
\r
- if (limit != HF_ONLY) \r
- {\r
- if (abs(lf_av - lf_baseline) > 10)\r
- LED_D_ON();\r
- else\r
- LED_D_OFF();\r
+ if (limit != HF_ONLY) {\r
+ if(mode==1) {\r
+ if (abs(lf_av - lf_baseline) > 10) LED_D_ON();\r
+ else LED_D_OFF();\r
+ }\r
+ \r
++lf_count;\r
lf_av_new= ReadAdc(ADC_CHAN_LF);\r
// see if there's a significant change\r
- if(abs(lf_av - lf_av_new) > 10) \r
- {\r
- DbpString("LF 125/134 Field Change:");\r
- DbpIntegers(lf_av,lf_av_new,lf_count);\r
- lf_av= lf_av_new;\r
+ if(abs(lf_av - lf_av_new) > 10) {\r
+ Dbprintf("LF 125/134 Field Change: %x %x %x", lf_av, lf_av_new, lf_count);\r
+ lf_av = lf_av_new;\r
+ if (lf_av > lf_max)\r
+ lf_max = lf_av;\r
lf_count= 0;\r
- }\r
}\r
+ }\r
\r
- if (limit != LF_ONLY) \r
- {\r
- if (abs(hf_av - hf_baseline) > 10) {\r
- if (mode == 1)\r
- LED_B_ON();\r
- if (mode == 2) {\r
- if ( hf_av>(hf_max/7)*6) {\r
- LED_A_ON(); LED_B_ON(); LED_C_ON(); LED_D_ON();\r
- }\r
- if ( (hf_av>(hf_max/7)*5) && (hf_av<=(hf_max/7)*6) ) {\r
- LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_ON();\r
- }\r
- if ( (hf_av>(hf_max/7)*4) && (hf_av<=(hf_max/7)*5) ) {\r
- LED_A_OFF(); LED_B_ON(); LED_C_OFF(); LED_D_ON();\r
- }\r
- if ( (hf_av>(hf_max/7)*3) && (hf_av<=(hf_max/7)*4) ) {\r
- LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); LED_D_ON();\r
- }\r
- if ( (hf_av>(hf_max/7)*2) && (hf_av<=(hf_max/7)*3) ) {\r
- LED_A_OFF(); LED_B_ON(); LED_C_OFF(); LED_D_OFF();\r
- }\r
- if ( (hf_av>(hf_max/7)*1) && (hf_av<=(hf_max/7)*2) ) {\r
- LED_A_ON(); LED_B_OFF(); LED_C_OFF(); LED_D_OFF();\r
- }\r
- if ( (hf_av>(hf_max/7)*0) && (hf_av<=(hf_max/7)*1) ) {\r
- LED_A_OFF(); LED_B_OFF(); LED_C_ON(); LED_D_OFF();\r
- }\r
- } \r
- } else {\r
- if (mode == 1) {\r
- LED_B_OFF();\r
- }\r
- if (mode == 2) {\r
- LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); LED_D_OFF();\r
- }\r
+ if (limit != LF_ONLY) {\r
+ if (mode == 1){\r
+ if (abs(hf_av - hf_baseline) > 10) LED_B_ON();\r
+ else LED_B_OFF();\r
}\r
-\r
+ \r
++hf_count;\r
hf_av_new= ReadAdc(ADC_CHAN_HF);\r
// see if there's a significant change\r
- if(abs(hf_av - hf_av_new) > 10) \r
- {\r
- DbpString("HF 13.56 Field Change:");\r
- DbpIntegers(hf_av,hf_av_new,hf_count);\r
- hf_av= hf_av_new;\r
+ if(abs(hf_av - hf_av_new) > 10) {\r
+ Dbprintf("HF 13.56 Field Change: %x %x %x", hf_av, hf_av_new, hf_count);\r
+ hf_av = hf_av_new;\r
if (hf_av > hf_max)\r
hf_max = hf_av;\r
hf_count= 0;\r
+ }\r
+ }\r
+ \r
+ if(mode == 2) {\r
+ if (limit == LF_ONLY) {\r
+ display_val = lf_av;\r
+ display_max = lf_max;\r
+ } else if (limit == HF_ONLY) {\r
+ display_val = hf_av;\r
+ display_max = hf_max;\r
+ } else { /* Pick one at random */\r
+ if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {\r
+ display_val = hf_av;\r
+ display_max = hf_max;\r
+ } else {\r
+ display_val = lf_av;\r
+ display_max = lf_max;\r
+ }\r
+ }\r
+ for (i=0; i<LIGHT_LEN; i++) {\r
+ if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {\r
+ if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();\r
+ if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();\r
+ if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();\r
+ if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();\r
+ break;\r
}\r
}\r
}\r
+ }\r
}\r
\r
+void UsbPacketReceived(BYTE *packet, int len)\r
+{\r
+ UsbCommand *c = (UsbCommand *)packet;\r
+ UsbCommand ack;\r
+ ack.cmd = CMD_ACK;\r
+\r
+ switch(c->cmd) {\r
+#ifdef WITH_LF\r
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:\r
+ AcquireRawAdcSamples125k(c->arg[0]);\r
+ UsbSendPacket((BYTE*)&ack, sizeof(ack));\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_LF\r
+ case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:\r
+ ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO15693\r
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:\r
+ AcquireRawAdcSamplesIso15693();\r
+ break;\r
+#endif\r
+\r
+ case CMD_BUFF_CLEAR:\r
+ BufferClear();\r
+ break;\r
+\r
+#ifdef WITH_ISO15693\r
+ case CMD_READER_ISO_15693:\r
+ ReaderIso15693(c->arg[0]);\r
+ break;\r
+#endif\r
+\r
+ case CMD_READER_LEGIC_RF:\r
+ LegicRfReader();\r
+ break;\r
+\r
+#ifdef WITH_ISO15693\r
+ case CMD_SIMTAG_ISO_15693:\r
+ SimTagIso15693(c->arg[0]);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO14443b\r
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:\r
+ AcquireRawAdcSamplesIso14443(c->arg[0]);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO14443b\r
+ case CMD_READ_SRI512_TAG:\r
+ ReadSRI512Iso14443(c->arg[0]);\r
+ break;\r
+ case CMD_READ_SRIX4K_TAG:\r
+ ReadSRIX4KIso14443(c->arg[0]);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO14443a\r
+ case CMD_READER_ISO_14443a:\r
+ ReaderIso14443a(c->arg[0]);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO14443a\r
+ case CMD_READER_MIFARE:\r
+ ReaderMifare(c->arg[0]);\r
+ break;\r
+#endif\r
+ \r
+#ifdef WITH_ISO14443b\r
+ case CMD_SNOOP_ISO_14443:\r
+ SnoopIso14443();\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_ISO14443a\r
+ case CMD_SNOOP_ISO_14443a:\r
+ SnoopIso14443a();\r
+ break;\r
+#endif\r
+\r
+ case CMD_SIMULATE_TAG_HF_LISTEN:\r
+ SimulateTagHfListen();\r
+ break;\r
+\r
+#ifdef WITH_ISO14443b\r
+ case CMD_SIMULATE_TAG_ISO_14443:\r
+ SimulateIso14443Tag();\r
+ break;\r
+#endif\r
+ \r
+#ifdef WITH_ISO14443a\r
+ case CMD_SIMULATE_TAG_ISO_14443a:\r
+ SimulateIso14443aTag(c->arg[0], c->arg[1]); // ## Simulate iso14443a tag - pass tag type & UID\r
+ break;\r
+#endif\r
+\r
+ case CMD_MEASURE_ANTENNA_TUNING:\r
+ MeasureAntennaTuning();\r
+ break;\r
+\r
+ case CMD_MEASURE_ANTENNA_TUNING_HF:\r
+ MeasureAntennaTuningHf();\r
+ break;\r
+\r
+ case CMD_LISTEN_READER_FIELD:\r
+ ListenReaderField(c->arg[0]);\r
+ break;\r
+\r
+#ifdef WITH_LF\r
+ case CMD_HID_DEMOD_FSK:\r
+ CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_LF\r
+ case CMD_HID_SIM_TAG:\r
+ CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID\r
+ break;\r
+#endif\r
+\r
+ case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+ SpinDelay(200);\r
+ LED_D_OFF(); // LED D indicates field ON or OFF\r
+ break;\r
+\r
+#ifdef WITH_LF\r
+ case CMD_READ_TI_TYPE:\r
+ ReadTItag();\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_LF\r
+ case CMD_WRITE_TI_TYPE:\r
+ WriteTItag(c->arg[0],c->arg[1],c->arg[2]);\r
+ break;\r
+#endif\r
+\r
+ case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {\r
+ UsbCommand n;\r
+ if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {\r
+ n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;\r
+ } else {\r
+ n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;\r
+ }\r
+ n.arg[0] = c->arg[0];\r
+ memcpy(n.d.asDwords, BigBuf+c->arg[0], 12*sizeof(DWORD));\r
+ UsbSendPacket((BYTE *)&n, sizeof(n));\r
+ break;\r
+ }\r
+\r
+ case CMD_DOWNLOADED_SIM_SAMPLES_125K: {\r
+ BYTE *b = (BYTE *)BigBuf;\r
+ memcpy(b+c->arg[0], c->d.asBytes, 48);\r
+ //Dbprintf("copied 48 bytes to %i",b+c->arg[0]);\r
+ UsbSendPacket((BYTE*)&ack, sizeof(ack));\r
+ break;\r
+ }\r
+\r
+#ifdef WITH_LF\r
+ case CMD_SIMULATE_TAG_125K:\r
+ LED_A_ON();\r
+ SimulateTagLowFrequency(c->arg[0], c->arg[1], 1);\r
+ LED_A_OFF();\r
+ break;\r
+#endif\r
+\r
+ case CMD_READ_MEM:\r
+ ReadMem(c->arg[0]);\r
+ break;\r
+\r
+ case CMD_SET_LF_DIVISOR:\r
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);\r
+ break;\r
+\r
+ case CMD_SET_ADC_MUX:\r
+ switch(c->arg[0]) {\r
+ case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break;\r
+ case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break;\r
+ case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break;\r
+ case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break;\r
+ }\r
+ break;\r
+\r
+ case CMD_VERSION:\r
+ SendVersion();\r
+ break;\r
+\r
+#ifdef WITH_LF\r
+ case CMD_LF_SIMULATE_BIDIR:\r
+ SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);\r
+ break;\r
+#endif\r
+\r
+#ifdef WITH_LCD\r
+ case CMD_LCD_RESET:\r
+ LCDReset();\r
+ break;\r
+ case CMD_LCD:\r
+ LCDSend(c->arg[0]);\r
+ break;\r
+#endif\r
+ case CMD_SETUP_WRITE:\r
+ case CMD_FINISH_WRITE:\r
+ case CMD_HARDWARE_RESET:\r
+ USB_D_PLUS_PULLUP_OFF();\r
+ SpinDelay(1000);\r
+ SpinDelay(1000);\r
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
+ for(;;) {\r
+ // We're going to reset, and the bootrom will take control.\r
+ }\r
+ break;\r
+\r
+ case CMD_START_FLASH:\r
+ if(common_area.flags.bootrom_present) {\r
+ common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;\r
+ }\r
+ USB_D_PLUS_PULLUP_OFF();\r
+ AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;\r
+ for(;;);\r
+ break;\r
+ \r
+ case CMD_DEVICE_INFO: {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DEVICE_INFO;\r
+ c.arg[0] = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;\r
+ if(common_area.flags.bootrom_present) c.arg[0] |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;\r
+ UsbSendPacket((BYTE*)&c, sizeof(c));\r
+ }\r
+ break;\r
+ default:\r
+ Dbprintf("%s: 0x%04x","unknown command:",c->cmd);\r
+ break;\r
+ }\r
+}\r
+\r
+void __attribute__((noreturn)) AppMain(void)\r
+{\r
+ SpinDelay(100);\r
+ \r
+ if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {\r
+ /* Initialize common area */\r
+ memset(&common_area, 0, sizeof(common_area));\r
+ common_area.magic = COMMON_AREA_MAGIC;\r
+ common_area.version = 1;\r
+ }\r
+ common_area.flags.osimage_present = 1;\r
+\r
+ LED_D_OFF();\r
+ LED_C_OFF();\r
+ LED_B_OFF();\r
+ LED_A_OFF();\r
+\r
+ UsbStart();\r
+\r
+ // The FPGA gets its clock from us from PCK0 output, so set that up.\r
+ AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;\r
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0;\r
+ AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0;\r
+ // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz\r
+ AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK |\r
+ AT91C_PMC_PRES_CLK_4;\r
+ AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0;\r
+\r
+ // Reset SPI\r
+ AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;\r
+ // Reset SSC\r
+ AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;\r
+\r
+ // Load the FPGA image, which we have stored in our flash.\r
+ FpgaDownloadAndGo();\r
+\r
+#ifdef WITH_LCD\r
+\r
+ LCDInit();\r
+\r
+ // test text on different colored backgrounds\r
+ LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK );\r
+ LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE );\r
+ LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED );\r
+ LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN );\r
+ LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE );\r
+ LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW);\r
+ LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN );\r
+ LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA);\r
+\r
+ // color bands\r
+ LCDFill(0, 1+8* 8, 132, 8, BLACK);\r
+ LCDFill(0, 1+8* 9, 132, 8, WHITE);\r
+ LCDFill(0, 1+8*10, 132, 8, RED);\r
+ LCDFill(0, 1+8*11, 132, 8, GREEN);\r
+ LCDFill(0, 1+8*12, 132, 8, BLUE);\r
+ LCDFill(0, 1+8*13, 132, 8, YELLOW);\r
+ LCDFill(0, 1+8*14, 132, 8, CYAN);\r
+ LCDFill(0, 1+8*15, 132, 8, MAGENTA);\r
+\r
+#endif\r
+\r
+ for(;;) {\r
+ UsbPoll(FALSE);\r
+ WDT_HIT();\r
+\r
+#ifdef WITH_LF\r
+ if (BUTTON_HELD(1000) > 0)\r
+ SamyRun();\r
+#endif\r
+ }\r
+}\r