diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index 0b94960c..1002d319 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -16,6 +16,7 @@ #include "MifareUltralight.h" #include "MifareClassic.h" #include "Reader14443A.h" +#include "Sniff14443A.h" /* Function wrappers */ INLINE void ApplicationInit(void) { diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index b865df84..471dc30f 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -141,6 +141,7 @@ uint16_t addParityBits(uint8_t * Buffer, uint16_t BitCount) uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount) { + // Short frame, no parity bit is added if (BitCount == 7) return 7; diff --git a/Firmware/Chameleon-Mini/Application/Sniff14443A.c b/Firmware/Chameleon-Mini/Application/Sniff14443A.c new file mode 100644 index 00000000..bea898c5 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Sniff14443A.c @@ -0,0 +1,173 @@ +// +// Created by Zitai Chen on 25/07/2018. +// Application layer for sniffing +// Currently only support Autocalibrate +// + +#include +#include +#include "Sniff14443A.h" +#include "Codec/SniffISO14443-2A.h" +extern bool checkParityBits(uint8_t * Buffer, uint16_t BitCount); + +Sniff14443Command Sniff14443CurrentCommand = Sniff14443_Do_Nothing; +//bool selected = false; +static enum { + STATE_IDLE, + STATE_REQA, + STATE_ATQA, + STATE_ANTICOLLI, + STATE_SELECT, + STATE_UID, + STATE_SAK, +} SniffState = STATE_IDLE; + +static uint16_t tmp_th = CODEC_THRESHOLD_CALIBRATE_MIN; +static uint8_t Thresholds[(CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / + CODEC_THRESHOLD_CALIBRATE_STEPS] = {0}; + +void Sniff14443AAppInit(void){ + SniffState = STATE_REQA; + // Get current threshold and continue searching from here + tmp_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold; +} + +void Sniff14443AAppReset(void){ + SniffState = STATE_IDLE; + + Sniff14443CurrentCommand = Sniff14443_Do_Nothing; +} +// Currently APPTask and AppTick is not being used +void Sniff14443AAppTask(void){/* Empty */} +void Sniff14443AAppTick(void){/* Empty */} + +void Sniff14443AAppTimeout(void){ + Sniff14443AAppReset(); +} + +INLINE void reset2REQA(void){ + SniffState = STATE_REQA; + LED_PORT.OUTCLR = LED_RED; + + // Mark the current threshold as fail and continue + if(tmp_th < CODEC_THRESHOLD_CALIBRATE_MAX){ + Thresholds[(tmp_th - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = 0; + tmp_th = CodecThresholdIncrement(); + } else{ + // mark finish + CommandLinePendingTaskFinished(COMMAND_INFO_FALSE, NULL); + } +} +uint16_t Sniff14443AAppProcess(uint8_t* Buffer, uint16_t BitCount){ + switch (Sniff14443CurrentCommand){ + case Sniff14443_Do_Nothing: { + return 0; + } + case Sniff14443_Autocalibrate: { + + switch (SniffState) { + case STATE_REQA: + LED_PORT.OUTCLR = LED_RED; + // If received Reader REQA or WUPA + if (TrafficSource == TRAFFIC_READER && + (Buffer[0] == 0x26 || Buffer[0] == 0x52)) { + SniffState = STATE_ATQA; + } else { + // Stay in this state, do noting + } + break; + case STATE_ATQA: + // ATQA: P RRRR XXXX P XXRX XXXX + if (TrafficSource == TRAFFIC_CARD && + BitCount == 2 * 9 && + (Buffer[0] & 0x20) == 0x00 && // Bit6 RFU shall be 0 + (Buffer[1] & 0xE0) == 0x00 && // bit13-16 RFU shall be 0 + (Buffer[2] & 0x01) == 0x00 && + checkParityBits(Buffer, BitCount)) { + // Assume this is a good ATQA + SniffState = STATE_ANTICOLLI; + } else { + // If not ATQA, but REQA, then stay on this state, + // Reset to REQA, save the counter and reset the counter + if (TrafficSource == TRAFFIC_READER && + (Buffer[0] == 0x26 || Buffer[0] == 0x52)) { + } else { + // If not ATQA and not REQA then reset to REQA + reset2REQA(); + } + } + break; + case STATE_ANTICOLLI: + // SEL: 93/95/97 + if (TrafficSource == TRAFFIC_READER && + BitCount == 2 * 8 && + (Buffer[0] & 0xf0) == 0x90 && + (Buffer[0] & 0x09) == 0x01) { + SniffState = STATE_UID; + + } else { + reset2REQA(); + } + break; + case STATE_UID: + if (TrafficSource == TRAFFIC_CARD && + BitCount == 5 * 9 && + checkParityBits(Buffer, BitCount)) { + SniffState = STATE_SELECT; + } else { + reset2REQA(); + } + break; + case STATE_SELECT: + + // SELECT: 9 bytes, SEL = 93/95/97, NVB=70 + if (TrafficSource == TRAFFIC_READER && + BitCount == 9 * 8 && + (Buffer[0] & 0xf0) == 0x90 && + (Buffer[0] & 0x09) == 0x01 && + Buffer[1] == 0x70) { + SniffState = STATE_SAK; + } else { + // Not valid, reset + reset2REQA(); + } + break; + case STATE_SAK: + // SAK: 1Byte SAK + CRC + if (TrafficSource == TRAFFIC_CARD && + BitCount == 3 * 9 && + checkParityBits(Buffer, BitCount)) { + if ((Buffer[0] & 0x04) == 0x00) { + // UID complete, success SELECTED, + // Mark the current threshold as ok and finish + // reset + SniffState = STATE_REQA; + LED_PORT.OUTSET = LED_RED; + Thresholds[(tmp_th - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] += 1; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, NULL); + // Send this threshold to terminal + char tmpBuf[10]; + snprintf(tmpBuf, 10, "%4" PRIu16 ": ", tmp_th); + TerminalSendString(tmpBuf); + + // Save value to EEPROM + SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->ReaderThreshold); + + Sniff14443AAppReset(); + } else { + // UID not complete, goto ANTICOLLI + SniffState = STATE_ANTICOLLI; + } + } else { + reset2REQA(); + } + break; + default: + break; + } + break; + } + default: + return 0; + } +} \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Application/Sniff14443A.h b/Firmware/Chameleon-Mini/Application/Sniff14443A.h new file mode 100644 index 00000000..60f1c857 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Sniff14443A.h @@ -0,0 +1,24 @@ +// +// Created by Zitai Chen on 25/07/2018. +// + +#ifndef CHAMELEON_MINI_SNIFF14443A_H +#define CHAMELEON_MINI_SNIFF14443A_H + +#include + +void Sniff14443AAppInit(void); +void Sniff14443AAppReset(void); +void Sniff14443AAppTask(void); +void Sniff14443AAppTick(void); +void Sniff14443AAppTimeout(void); + +uint16_t Sniff14443AAppProcess(uint8_t* Buffer, uint16_t BitCount); + +typedef enum { + Sniff14443_Do_Nothing, + Sniff14443_Autocalibrate, +} Sniff14443Command; + +#endif //CHAMELEON_MINI_SNIFF14443A_H + diff --git a/Firmware/Chameleon-Mini/Codec/Codec.c b/Firmware/Chameleon-Mini/Codec/Codec.c index 56f2774e..adfb60dd 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.c +++ b/Firmware/Chameleon-Mini/Codec/Codec.c @@ -23,7 +23,7 @@ static volatile struct { } ReaderFieldFlags = { false }; uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; - +uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; // the following three functions prevent sending data directly after turning on the reader field void CodecReaderFieldStart(void) // DO NOT CALL THIS FUNCTION INSIDE APPLICATION! { diff --git a/Firmware/Chameleon-Mini/Codec/Codec.h b/Firmware/Chameleon-Mini/Codec/Codec.h index cf9d67d2..23e39e92 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.h +++ b/Firmware/Chameleon-Mini/Codec/Codec.h @@ -17,6 +17,7 @@ #include "ISO14443-2A.h" #include "Reader14443-2A.h" +#include "SniffISO14443-2A.h" /* Timing definitions for ISO14443A */ #define ISO14443A_SUBCARRIER_DIVIDER 16 @@ -24,7 +25,7 @@ #define ISO14443A_BIT_RATE_CYCLES 128 #define ISO14443A_FRAME_DELAY_PREV1 1236 #define ISO14443A_FRAME_DELAY_PREV0 1172 -#define ISO14443A_RX_PENDING_TIMEOUT 1 // ms +#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms /* Peripheral definitions */ #define CODEC_DEMOD_POWER_PORT PORTB @@ -38,6 +39,7 @@ #define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc #define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc #define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect +#define CODEC_DEMOD_IN_INT1_VECT PORTB_INT1_vect #define CODEC_LOADMOD_PORT PORTC #define CODEC_LOADMOD_MASK PIN6_bm #define CODEC_CARRIER_IN_PORT PORTC @@ -57,6 +59,8 @@ #define CODEC_TIMER_SAMPLING TCD0 #define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect #define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect +#define CODEC_TIMER_SAMPLING_CCC_VECT TCD0_CCC_vect +#define CODEC_TIMER_SAMPLING_CCD_VECT TCD0_CCD_vect #define CODEC_TIMER_LOADMOD TCE0 #define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect #define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect @@ -80,6 +84,8 @@ #define CODEC_THRESHOLD_CALIBRATE_STEPS 16 #define CODEC_TIMER_TIMESTAMPS TCD1 #define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect +#define CODEC_TIMER_TIMESTAMPS_CCB_VECT TCD1_CCB_vect + #define CODEC_BUFFER_SIZE 256 @@ -90,9 +96,11 @@ #define Codec8Reg2 GPIOR2 #define Codec8Reg3 GPIOR3 #define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */ -#define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */ +#define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR6 & GPIOR7 */ #define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8)) #define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA)) +#define CodecPtrRegister3 (*((volatile uint8_t**) &GPIORC)) + extern uint16_t Reader_FWT; @@ -104,6 +112,7 @@ typedef enum { } SubcarrierModType; extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; +extern uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; INLINE void CodecInit(void) { ActiveConfiguration.CodecInitFunc(); @@ -140,10 +149,14 @@ INLINE void CodecInitCommon(void) CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc; CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc; CODEC_DEMOD_IN_PORT.INT0MASK = 0; - CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc; + CODEC_DEMOD_IN_PORT.INT1MASK = 0; + CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc | PORT_INT1LVL_HI_gc; EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0; EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1; + EVSYS.CH2MUX = CODEC_DEMOD_IN_EVMUX0; + + /* Configure loadmod pin configuration and use a virtual port configuration * for single instruction cycle access */ CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK; @@ -231,6 +244,7 @@ INLINE void CodecSetLoadmodState(bool bOnOff) { } } +// Turn on and off the codec Reader field INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turning on/off the reader field dumbly; before using this function, please consider to use CodecReaderField{Start,Stop} if (bOnOff) { @@ -244,6 +258,7 @@ INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turni } } +// Get the status of the reader field INLINE bool CodecGetReaderField(void) { return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK); } diff --git a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c index e43ea615..1f9d9652 100644 --- a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c @@ -66,8 +66,8 @@ static void StartDemod(void) { StateRegister = DEMOD_DATA_BIT; /* Configure sampling-timer free running and sync to first modulation-pause. */ - CODEC_TIMER_SAMPLING.CNT = 0; - CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; + CODEC_TIMER_SAMPLING.CNT = 0; // Reset the timer count + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; // Set Period regisiter CODEC_TIMER_SAMPLING.CCA = 0xFFFF; /* CCA Interrupt is not active! */ CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc; CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; @@ -75,10 +75,11 @@ static void StartDemod(void) { CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCAINTLVL_HI_gc; /* Start looking out for modulation pause via interrupt. */ - CODEC_DEMOD_IN_PORT.INTFLAGS = 0x03; + CODEC_DEMOD_IN_PORT.INTFLAGS = PORT_INT0IF_bm; CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; } +// Find first pause and start sampling ISR(CODEC_DEMOD_IN_INT0_VECT) { /* This is the first edge of the first modulation-pause after StartDemod. * Now we have time to start @@ -112,6 +113,7 @@ ISR(CODEC_DEMOD_IN_INT0_VECT) { CODEC_DEMOD_IN_PORT.INT0MASK = 0; } +// Sampling with timer and demod ISR(CODEC_TIMER_SAMPLING_CCA_VECT) { /* This interrupt gets called twice for every bit to sample it. */ uint8_t SamplePin = CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK; @@ -220,6 +222,7 @@ ISR(CODEC_TIMER_SAMPLING_CCA_VECT) { CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; } +// Enumulate as a card to send card responds ISR(CODEC_TIMER_LOADMOD_OVF_VECT) { /* Bit rate timer. Output a half bit on the output. */ @@ -418,6 +421,7 @@ void ISO14443ACodecTask(void) { uint16_t AnswerBitCount = ISO14443A_APP_NO_RESPONSE; if (DemodBitCount >= ISO14443A_MIN_BITS_PER_FRAME) { + // For logging data LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, (DemodBitCount+7)/8); LEDHook(LED_CODEC_RX, LED_PULSE); diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c index 6a709680..1bea53b7 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c @@ -94,6 +94,8 @@ INLINE void Insert1(void) *CodecBufferPtr++ = SampleRegister; } + +// End of Card-> reader communication and enter frame delay time INLINE void Reader14443A_EOC(void) { CODEC_TIMER_LOADMOD.INTCTRLB = 0; @@ -138,6 +140,7 @@ INLINE void BufferToSequence(void) uint8_t * Buffer = CodecBuffer + CODEC_BUFFER_SIZE / 2; CodecBufferPtr = CodecBuffer; + // Modified Miller Coding ISO14443-2 8.1.3 Insert1(); // SOC Insert0(); @@ -175,8 +178,8 @@ INLINE void BufferToSequence(void) if (BitCount % 8) CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); } - -ISR (TCD0_CCC_vect) +// Frame Delay Time PCD to PICC ends +ISR (CODEC_TIMER_SAMPLING_CCC_VECT) { CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; @@ -202,6 +205,8 @@ ISR (TCD0_CCC_vect) PORTE.OUTTGL = PIN3_bm; } +// Reader -> card send bits finished +// Start Frame delay time PCD to PICC void Reader14443AMillerEOC(void) { CODEC_TIMER_SAMPLING.PER = 5*SAMPLE_RATE_SYSTEM_CYCLES - 1; @@ -211,11 +216,13 @@ void Reader14443AMillerEOC(void) PORTE.OUTTGL = PIN3_bm; } +// EOC of Card->Reader found ISR(CODEC_TIMER_TIMESTAMPS_CCA_VECT) // EOC found { Reader14443A_EOC(); } +// This interrupt find Card -> Reader SOC ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered before { ACA.AC1CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt @@ -224,6 +231,10 @@ ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered befor CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_DIV1_gc; } +// Decode the Card -> Reader signal +// according to the pause and modulated period +// if the half bit duration is modulated, then add 1 to buffer +// if the half bit duration is not modulated, then add 0 to buffer ISR(CODEC_TIMER_LOADMOD_CCA_VECT) // pause found { uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; @@ -296,6 +307,8 @@ void Reader14443ACodecTask(void) bool breakflag = false; TmpCodecBuffer[0] >>= 2; // with this (and BitCountTmp = 2), the SOC is ignored + + // Manchester Code ISO14443-2 8.2.5 while (!breakflag && BitCountTmp < TotalBitCount) { uint8_t Bit = TmpCodecBuffer[BitCountTmp / 8] & 0x03; @@ -375,6 +388,7 @@ void Reader14443ACodecTask(void) LogEntry(LOG_INFO_CODEC_TX_DATA_W_PARITY, CodecBuffer, (BitCount + 7) / 8); /* Set state and start timer for Miller encoding. */ + // Send bits to card using TCD0_CCB interrupt (See Reader14443-ISR.S) BufferToSequence(); State = STATE_MILLER_SEND; CodecBufferPtr = CodecBuffer; diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-ISR.S b/Firmware/Chameleon-Mini/Codec/Reader14443-ISR.S index f41b045d..82ba110d 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-ISR.S +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-ISR.S @@ -15,6 +15,7 @@ #define AWEXC__OUTOVEN 0x088C #define CODEC_READER_TIMER__CTRLA 0x0800 +; For sending reader bits to cards .global TCD0_CCB_vect, Reader14443AMillerEOC TCD0_CCB_vect: push Zero ; 1 diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c new file mode 100644 index 00000000..628eeadd --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -0,0 +1,544 @@ +// +// Created by Zitai Chen on 05/07/2018. +// Sniffing Function of ISO14443-2A cards +// Wors in both direction: PCD->PICC, PICC->PCD, +// modified from ISO14443-2A.c and Reader14443-2A.c +// + +#include "SniffISO14443-2A.h" + +#include "Reader14443-2A.h" +#include "Codec.h" +#include "../System.h" +#include "../Application/Application.h" +#include "LEDHook.h" +#include "Terminal/Terminal.h" +#include + +/* Sampling is done using internal clock, synchronized to the field modulation. + * For that we need to convert the bit rate for the internal clock. */ +#define SAMPLE_RATE_SYSTEM_CYCLES ((uint16_t) (((uint64_t) F_CPU * ISO14443A_BIT_RATE_CYCLES) / CODEC_CARRIER_FREQ) ) +#define ISO14443A_MIN_BITS_PER_FRAME 7 + +// Card to reader +#define ISO14443A_PICC_TO_PCD_FDT_PRESCALER TC_CLKSEL_DIV8_gc // please change ISO14443A_PICC_TO_PCD_MIN_FDT when changing this +#define ISO14443A_RX_MINIMUM_BITCOUNT 4 + +/* Define pseudo variables to use fast register access. This is useful for global vars */ +#define DataRegister Codec8Reg0 +#define StateRegister Codec8Reg1 +#define ParityRegister Codec8Reg2 + +#define SampleIdxRegister Codec8Reg3 +#define ReaderSampleR GPIOR4 +#define CardSampleR GPIOR5 +#define BitCount CodecCount16Register2 +#define ReaderBufferPtr CodecPtrRegister1 +#define ParityBufferPtr CodecPtrRegister2 +#define CardBufferPtr CodecPtrRegister3 + +static volatile struct { + volatile bool ReaderDataAvaliable; + volatile bool CardDataAvaliable; + +} Flags = { 0 }; +static volatile uint16_t RxPendingSince; + +typedef enum { + DEMOD_DATA_BIT, /* Demod */ + DEMOD_PARITY_BIT, + PCD_PICC_FDT, + PICC_FRAME, + +} StateType; + +static volatile uint16_t ReaderBitCount; +static volatile uint16_t CardBitCount; +static volatile uint16_t rawBitCount; + +INLINE void CardSniffInit(void); +INLINE void CardSniffDeinit(void); + +///////////////////////////////////////////////// +// Reader->Card Direction Traffic +///////////////////////////////////////////////// + +INLINE void ReaderSniffInit(void) +{ +// PORTE.OUTSET = PIN3_bm; + + // Configure interrupt for demod + CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT1LVL_HI_gc; + + /* Initialize some global vars and start looking out for reader commands */ + + ReaderBufferPtr = CodecBuffer; + ParityBufferPtr = &CodecBuffer[ISO14443A_BUFFER_PARITY_OFFSET]; + DataRegister = 0; + ReaderSampleR = 0; + SampleIdxRegister = 0; + BitCount = 0; + StateRegister = DEMOD_DATA_BIT; + + + /* Configure sampling-timer free running and sync to first modulation-pause. */ + CODEC_TIMER_SAMPLING.CNT = 0; // Reset the timer count + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; // Set Period regisiter + CODEC_TIMER_SAMPLING.CCD = 0xFFFF; /* CCD Interrupt is not active! */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc; + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCDIF_bm; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCDINTLVL_HI_gc; + + /* Start looking out for modulation pause via interrupt. */ + CODEC_DEMOD_IN_PORT.INTFLAGS = PORT_INT1IF_bm; + CODEC_DEMOD_IN_PORT.INT1MASK = CODEC_DEMOD_IN_MASK0; +} +INLINE void ReaderSniffDeInit(void) +{ +// PORTE.OUTCLR = PIN3_bm; + + /* Gracefully shutdown codec */ + CODEC_DEMOD_IN_PORT.INT1MASK = 0; + CODEC_DEMOD_IN_PORT.INTCTRL = 0; + + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCDINTLVL_OFF_gc; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCDIF_bm; +} + + +// Find first pause and start sampling +ISR(CODEC_DEMOD_IN_INT1_VECT) { + PORTE.OUTSET = PIN2_bm; + + /* This is the first edge of the first modulation-pause after StartDemod. + * Now we have time to start + * demodulating beginning from one bit-width after this edge. */ + + /* Sampling timer has been preset to sample-rate and has automatically synced + * to THIS first modulation pause. Thus after exactly one bit-width from here, + * an OVF is generated. We want to start sampling with the next bit and use the + * XYZBUF mechanism of the xmega to automatically double the sampling rate on the + * next overflow. For this we have to temporarily deactivate the automatical alignment + * in order to catch next overflow event for updating the BUF registers. + * We want to sample the demodulated data stream in the first quarter of the half-bit + * where the pulsed miller encoded is located. */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + CODEC_TIMER_SAMPLING.PERBUF = SAMPLE_RATE_SYSTEM_CYCLES/2 - 1; /* Half bit width */ + CODEC_TIMER_SAMPLING.CCDBUF = SAMPLE_RATE_SYSTEM_CYCLES/8 - 14 - 1; /* Compensate for DIGFILT and ISR prolog */ + + /* Disable this interrupt */ + CODEC_DEMOD_IN_PORT.INT1MASK = 0; +} + +// Sampling with timer and demod +ISR(CODEC_TIMER_SAMPLING_CCD_VECT) { + /* This interrupt gets called twice for every bit to sample it. */ + uint8_t SamplePin = CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK; + + /* Shift sampled bit into sampling register */ + ReaderSampleR = (ReaderSampleR << 1) | (!SamplePin ? 0x01 : 0x00); + + if (SampleIdxRegister) { + SampleIdxRegister = 0; + /* Analyze the sampling register after 2 samples. */ + if ((ReaderSampleR & 0x07) == 0x07) { + /* No carrier modulation for 3 sample points. EOC! */ + + // Shutdown the Reader->Card Sniffing, + // disable the sampling timer + PORTE.OUTCLR = PIN2_bm; + + + + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCDIF_bm; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCDINTLVL_OFF_gc; + CODEC_DEMOD_IN_PORT.INTCTRL = 0; // Disable CODEC_DEMOD_IN_PORT interrupt + // CTRLD already disabled in CODEC_DEMOD_IN_INT1_VECT, + // so no need to disable it again it here + + /* Determine if we did not receive a multiple of 8 bits. + * If this is the case, right-align the remaining data and + * store it into the buffer. */ + uint8_t RemainingBits = BitCount % 8; + if (RemainingBits != 0) { + uint8_t NewDataRegister = DataRegister; + + while (RemainingBits++ < 8) { + /* Pad with zeroes to right-align. */ + NewDataRegister >>= 1; + } + + /* TODO: Prevent buffer overflow */ + *ReaderBufferPtr = NewDataRegister; + } + + /* Signal, that we have finished sampling */ + ReaderBitCount = BitCount; + + // If we are have got data + // Start Card->Reader Sniffing without waiting for the complete of CodecTask + // Otherwise some bit will not be captured + if (ReaderBitCount >= ISO14443A_MIN_BITS_PER_FRAME) { + Flags.ReaderDataAvaliable = true; + CardSniffInit(); + } else{ + ReaderSniffInit(); + } + + return; + + } + else { + /* Otherwise, we check the two sample bits from the bit before. */ + uint8_t BitSample = ReaderSampleR & 0xC; + uint8_t Bit = 0; + + if (BitSample != (0x0 << 2)) { + /* We have a valid bit. decode and process it. */ + if (BitSample & (0x1 << 2)) { + /* 01 sequence or 11 sequence -> This is a zero bit */ + Bit = 0; + } + else { + /* 10 sequence -> This is a one bit */ + Bit = 1; + } + + if (StateRegister == DEMOD_DATA_BIT) { + /* This is a data bit, so shift it into the data register and + * hold a local copy of it. */ + uint8_t NewDataRegister = DataRegister >> 1; + NewDataRegister |= (Bit ? 0x80 : 0x00); + DataRegister = NewDataRegister; + + /* Update bitcount */ + uint16_t NewBitCount = ++BitCount; + if ((NewBitCount & 0x07) == 0) { + /* We have reached a byte boundary! Store the data register. */ + /* TODO: Prevent buffer overflow */ + *ReaderBufferPtr++ = NewDataRegister; + + /* Store bit for determining FDT at EOC and enable parity + * handling on next bit. */ + StateRegister = DEMOD_PARITY_BIT; + } + + } + else if (StateRegister == DEMOD_PARITY_BIT) { + /* This is a parity bit. Store it */ +// *ParityBufferPtr++ = Bit; + StateRegister = DEMOD_DATA_BIT; + } + else { + /* Should never Happen (TM) */ + } + } + else { + /* 00 sequence. -> No valid data yet. This also occurs if we just started + * sampling and have sampled less than 2 bits yet. Thus ignore. */ + } + } + } + else { + /* On odd sample position just sample. */ + SampleIdxRegister = ~SampleIdxRegister; + } + + /* Make sure the sampling timer gets automatically aligned to the + * modulation pauses by using the RESTART event. + * This can be understood as a "poor mans PLL" and makes sure that we are + * never too far out the bit-grid while sampling. */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; +} + +///////////////////////////////////////////////// +// Card->Reader Direction Traffic +///////////////////////////////////////////////// + +INLINE void CardSniffInit(void) +{ + + /* Initialize common peripherals and start listening + * for incoming data. */ + + CardBufferPtr = CodecBuffer2; // use GPIOR for faster access + rawBitCount = 1; // FALSCH todo the first modulation of the SOC is "found" implicitly + BitCount = 0; + CardSampleR = 0x00; + + + /* + * Prepare for Manchester decoding. + * The basic idea is to use two timers. The first one will be reset everytime the DEMOD signal + * passes a (configurable) threshold. This is realized with the event system and an analog + * comparator. + * Once this timer reaches 3/4 of a bit half (this means it has not been reset this long), we + * assume there is a pause. Now we read the second timers count value and can decide how many + * bit halves had modulations since the last pause. + */ + + // Comparator ADC + /* Configure and enable the analog comparator for finding pauses in the DEMOD signal. */ + ACA.AC0CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_FALLING_gc | AC_ENABLE_bm; + + /* This timer will be used to detect the pauses between the modulation sequences. */ + CODEC_TIMER_LOADMOD.CTRLA = 0; + CODEC_TIMER_LOADMOD.CNT = 0; + CODEC_TIMER_LOADMOD.PER = 0xFFFF; // with 27.12 MHz this is exactly one half bit width + CODEC_TIMER_LOADMOD.CCB = 95; // with 27.12 MHz this is 3/4 of a half bit width + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + CODEC_TIMER_LOADMOD.INTFLAGS = TC1_CCBIF_bm; + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_HI_gc; + + /* This timer will be used to find out how many bit halfs since the last pause have been passed. */ + CODEC_TIMER_TIMESTAMPS.CNT = 0; // Reset timer + CODEC_TIMER_TIMESTAMPS.PER = 0xFFFF; + CODEC_TIMER_TIMESTAMPS.CCB = 160; + CODEC_TIMER_TIMESTAMPS.INTCTRLA = 0; + CODEC_TIMER_TIMESTAMPS.INTFLAGS = TC1_CCBIF_bm; // Clear interrupt flag +// CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCBINTLVL_LO_gc; + CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCBINTLVL_HI_gc; + + /* Use the event system for resetting the pause-detecting timer. */ + EVSYS.CH2MUX = EVSYS_CHMUX_ACA_CH0_gc; // on every ACA_AC0 INT + EVSYS.CH2CTRL = EVSYS_DIGFILT_1SAMPLE_gc; + + /* Enable the AC interrupt, which either finds the SOC and then starts the pause-finding timer, + * or it is triggered before the SOC, which mostly isn't bad at all, since the first pause + * needs to be found. */ + ACA.AC1CTRL = 0; + ACA.STATUS = AC_AC0IF_bm; + ACA.AC0CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_FALLING_gc | AC_INTLVL_HI_gc | AC_ENABLE_bm; + + RxPendingSince = SystemGetSysTick(); + StateRegister = PCD_PICC_FDT; + + +} + +INLINE void CardSniffDeinit(void) +{ + + CODEC_TIMER_LOADMOD.CTRLA = 0; + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + + // Disable event system CH2 + EVSYS.CH2MUX = 0; + EVSYS.CH2CTRL = 0; + // Reset ACA AC0 to default setting + ACA.AC0MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc; + ACA.AC0CTRL = CODEC_AC_DEMOD_SETTINGS; + +} + + + +INLINE void Insert0(void) +{ + CardSampleR >>= 1; + if (++BitCount % 8) + return; + *CardBufferPtr++ = CardSampleR; +} + +INLINE void Insert1(void) +{ + CardSampleR = (CardSampleR >> 1) | 0x80; + if (++BitCount % 8) + return; + *CardBufferPtr++ = CardSampleR; +} + +// This interrupt find Card -> Reader SOC +ISR(ACA_AC0_vect) // this interrupt either finds the SOC or gets triggered before +{ + + ACA.AC0CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt + // enable the pause-finding timer + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | TC_EVSEL_CH2_gc; + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_DIV1_gc; + StateRegister = PICC_FRAME; +} +// Decode the Card -> Reader signal +// according to the pause and modulated period +// if the half bit duration is modulated, then add 1 to buffer +// if the half bit duration is not modulated, then add 0 to buffer +ISR(CODEC_TIMER_LOADMOD_CCB_VECT) // pause found +{ + uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; + CODEC_TIMER_TIMESTAMPS.CNT = 0; + + /* This needs to be done only on the first call, + * but doing this only on a condition means wasting time, so we do it every time. */ + CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_DIV4_gc; + + // Remember, LSB is send first + // If current raw bit count is odd, then the previous raw bit must be 0 + switch (tmp) // decide how many half bit periods have been modulations + { + case 0 ... 48: // 32 ticks is one half of a bit period + return; + + case 49 ... 80: // 64 ticks are a full bit period + // Got 01 + if(rawBitCount & 1){ + // 01 + 0 -> 0 10 + // 10 -> 1, last 0 is ignored + if(rawBitCount > 1) { + // Ignore SOC + Insert1(); + } + } else{ + // Current sampled bit count is even, decode directly + // 01 -> 0 + Insert0(); + } + rawBitCount += 2; + return; + + case 81 ... 112: // 96 ticks are 3 half bit periods + if (rawBitCount & 1) { + // Current sampled bit count is odd + // Got 011 + // 011 + 0 -> 01 10 -> 01 + if(rawBitCount > 1) { + // Ignore SOC + Insert1(); + } + Insert0(); + } else { + // Even bit count + // Got 001 + // 001 -> 0 01, The last 0 is ignored + // 01 -> 0 + Insert0(); + } + rawBitCount += 3; + + return; + + default: // every value over 96 + 16 (tolerance) is considered to be 4 half bit periods + // Got 00 11 + if(rawBitCount & 1){ + // 00 11 + 0 -> 0 01 10 + // 01 -> 0, 10 -> 1, Ignore last 0 + if(rawBitCount > 1) { + // Ignore SOC + Insert1(); + } + Insert0(); + } else { + // Should not happen + // If modulation is correct, + // there should not be a full bit period modulation in even bit count + } + rawBitCount += 4; + + return; + } +} +// EOC of Card->Reader found +ISR(CODEC_TIMER_TIMESTAMPS_CCB_VECT) // EOC found +{ + + // Disable LOADMOD Timer + CODEC_TIMER_LOADMOD.INTCTRLB = 0; // Disable Interrupt + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; // Disable Clock + CODEC_TIMER_LOADMOD.CTRLD = 0; // Disable connection to event channel + + CODEC_TIMER_TIMESTAMPS.INTCTRLB = 0; + CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_OFF_gc; + ACA.AC0CTRL &= ~AC_ENABLE_bm; + + // If finished in odd sample count + // There must been an incomplete decoded bit + // Since only EOC is no modulation in full bit period, and previous raw bit must be 0 + // so the last not modulated bit must be 1 + if (rawBitCount & 1) { + // The previous raw bit must be 0 + // 1 + 0 -> 10 -> 1 + Insert1(); + } + + if (BitCount % 8) // copy the last byte, if there is an incomplete byte + CodecBuffer2[BitCount / 8] = CardSampleR >> (8 - (BitCount % 8)); + + CardBitCount = BitCount; + if (BitCount >= ISO14443A_RX_MINIMUM_BITCOUNT) { + Flags.CardDataAvaliable = true; + } + + CardSniffDeinit(); + ReaderSniffInit(); + +} + +///////////////////////////////////////////////// +// Init and deInit, task, functions for this codec +///////////////////////////////////////////////// + +void Sniff14443ACodecInit(void) +{ + + PORTE.DIRSET= PIN3_bm | PIN2_bm; + // Common Codec Register settings + CodecInitCommon(); + // Enable demodulator power + CodecSetDemodPower(true); + + // Start with sniffing Reader->Card direction traffic + Flags.ReaderDataAvaliable = false; + Flags.CardDataAvaliable = false; + + ReaderSniffInit(); +} + +void Sniff14443ACodecDeInit(void) +{ +// SniffEnable = false; + CardSniffDeinit(); + ReaderSniffDeInit(); + CodecSetDemodPower(false); +} + + +void Sniff14443ACodecTask(void) +{ + PORTE.OUTSET = PIN3_bm; + if(Flags.ReaderDataAvaliable){ + Flags.ReaderDataAvaliable = false; + + LogEntry(LOG_INFO_CODEC_SNI_READER_DATA, CodecBuffer, (ReaderBitCount+7)/8); + // Let the Application layer know where this data comes from + LEDHook(LED_CODEC_RX, LED_PULSE); + + TrafficSource = TRAFFIC_READER; + ApplicationProcess(CodecBuffer, ReaderBitCount); + } + + + if (Flags.CardDataAvaliable){ + Flags.CardDataAvaliable = false; + +// CardBitCount = removeParityBits(CodecBuffer2,CardBitCount ); + LogEntry(LOG_INFO_CODEC_SNI_CARD_DATA_W_PARITY, CodecBuffer2, (CardBitCount + 7) / 8); + LEDHook(LED_CODEC_RX, LED_PULSE); + + // Let the Application layer know where this data comes from + TrafficSource = TRAFFIC_CARD; + ApplicationProcess(CodecBuffer2, CardBitCount); + } + + + if(StateRegister == PCD_PICC_FDT && (SYSTICK_DIFF(RxPendingSince) > Reader_FWT)){ + CardSniffDeinit(); + ReaderSniffInit(); + } + PORTE.OUTCLR = PIN3_bm; + + +} diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h new file mode 100644 index 00000000..0e22d464 --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h @@ -0,0 +1,20 @@ +// +// Created by Zitai Chen on 05/07/2018. +// + +#ifndef CHAMELEON_MINI_SNIFFISO14443_2A_H +#define CHAMELEON_MINI_SNIFFISO14443_2A_H + + +#include "Codec.h" +#include "Terminal/CommandLine.h" + +enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource; +/* Codec Interface */ +void Sniff14443ACodecInit(void); +void Sniff14443ACodecDeInit(void); +void Sniff14443ACodecTask(void); + + + +#endif //CHAMELEON_MINI_SNIFFISO14443_2A_H diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 72ffce14..1fffdd0a 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -188,14 +188,14 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { #endif #ifdef CONFIG_ISO14443A_SNIFF_SUPPORT [CONFIG_ISO14443A_SNIFF] = { - .CodecInitFunc = ISO14443ACodecInit, - .CodecDeInitFunc = ISO14443ACodecDeInit, - .CodecTaskFunc = ISO14443ACodecTask, - .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, - .ApplicationTaskFunc = ApplicationTaskDummy, - .ApplicationTickFunc = ApplicationTickDummy, - .ApplicationProcessFunc = ApplicationProcessDummy, + .CodecInitFunc = Sniff14443ACodecInit, + .CodecDeInitFunc = Sniff14443ACodecDeInit, + .CodecTaskFunc = Sniff14443ACodecTask, + .ApplicationInitFunc = Sniff14443AAppInit, + .ApplicationResetFunc = Sniff14443AAppReset, + .ApplicationTaskFunc = Sniff14443AAppTask, + .ApplicationTickFunc = Sniff14443AAppTick, + .ApplicationProcessFunc = Sniff14443AAppProcess, .ApplicationGetUidFunc = ApplicationGetUidDummy, .ApplicationSetUidFunc = ApplicationSetUidDummy, .UidSize = 0, diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index ce0bbfd6..3fd3a310 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -23,6 +23,14 @@ typedef enum { LOG_INFO_CODEC_RX_DATA_W_PARITY = 0x42, ///< Currently active codec received data. LOG_INFO_CODEC_TX_DATA_W_PARITY = 0x43, ///< Currently active codec sent data. + LOG_INFO_CODEC_SNI_READER_DATA = 0x44, //< Sniffing codec receive data from reader + LOG_INFO_CODEC_SNI_READER_DATA_W_PARITY = 0x45, //< Sniffing codec receive data from reader + + LOG_INFO_CODEC_SNI_CARD_DATA = 0x46, //< Sniffing codec receive data from card + LOG_INFO_CODEC_SNI_CARD_DATA_W_PARITY = 0x47, //< Sniffing codec receive data from card + + + /* App */ LOG_INFO_APP_CMD_READ = 0x80, ///< Application processed read command. LOG_INFO_APP_CMD_WRITE = 0x81, ///< Application processed write command. diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 9d3175f3..38246335 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -92,8 +92,8 @@ TARGET = Chameleon-Mini OPTIMIZATION = s SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c -SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/Reader14443-ISR.S -SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c +SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S +SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -DFLASH_DATA_SIZE=$(FLASH_DATA_SIZE) -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" $(SETTINGS) diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index d4b26e92..c6307a8a 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -2,6 +2,7 @@ #include "Commands.h" #include #include +#include #include "XModem.h" #include "../Settings.h" #include "../Chameleon-Mini.h" @@ -16,6 +17,7 @@ #include "../Codec/Codec.h" extern Reader14443Command Reader14443CurrentCommand; +extern Sniff14443Command Sniff14443CurrentCommand; extern const PROGMEM CommandEntryType CommandTable[]; @@ -629,15 +631,27 @@ CommandStatusIdType CommandGetField(char* OutMessage) CommandStatusIdType CommandExecAutocalibrate(char* OutMessage) { - if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + if (GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_ISO14443A_READER){ + ApplicationReset(); + + Reader14443CurrentCommand = Reader14443_Autocalibrate; + Reader14443AAppInit(); + Reader14443ACodecStart(); + CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; + return TIMEOUT_COMMAND; + } + else if (GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_ISO14443A_SNIFF){ + ApplicationReset(); + + Sniff14443CurrentCommand = Sniff14443_Autocalibrate; + Sniff14443AAppInit(); + CommandLinePendingTaskTimeout = &Sniff14443AAppTimeout; + return TIMEOUT_COMMAND; + } + else { return COMMAND_ERR_INVALID_USAGE_ID; - ApplicationReset(); + } - Reader14443CurrentCommand = Reader14443_Autocalibrate; - Reader14443AAppInit(); - Reader14443ACodecStart(); - CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; - return TIMEOUT_COMMAND; } CommandStatusIdType CommandExecClone(char *OutMessage)