diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c index 6a70968..9192c1f 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c @@ -50,6 +50,7 @@ void Reader14443ACodecInit(void) { CodecInitCommon(); CodecSetDemodPower(true); + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; CODEC_TIMER_SAMPLING.CCB = 0; CODEC_TIMER_SAMPLING.CCC = 0; @@ -66,9 +67,11 @@ void Reader14443ACodecInit(void) { Flags.RxDone = false; } + + void Reader14443ACodecDeInit(void) { CodecSetDemodPower(false); - CodecReaderFieldStop(); + // CodecReaderFieldStop(); CODEC_TIMER_SAMPLING.CTRLA = 0; CODEC_TIMER_SAMPLING.INTCTRLB = 0; CODEC_TIMER_LOADMOD.CTRLA = 0; @@ -94,8 +97,11 @@ 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; CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; CODEC_TIMER_TIMESTAMPS.INTCTRLB = 0; @@ -128,6 +134,7 @@ INLINE void Reader14443A_EOC(void) INLINE void BufferToSequence(void) { + uint16_t count = BitCount; if (count > BITS_PER_BYTE * CODEC_BUFFER_SIZE / 2) // todo is this correct? return; @@ -138,6 +145,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,12 +183,14 @@ INLINE void BufferToSequence(void) if (BitCount % 8) CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); } - +// Frame Delay Time PCD to PICC ends ISR (TCD0_CCC_vect) { + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_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. */ @@ -192,6 +202,7 @@ ISR (TCD0_CCC_vect) SampleRegister = 0x00; RxPendingSince = SystemGetSysTick(); + Flags.RxPending = true; // reset for future use @@ -202,8 +213,11 @@ 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; CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCBIF_bm | TC0_CCCIF_bm; CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCBINTLVL_OFF_gc | TC_CCCINTLVL_HI_gc; @@ -211,21 +225,32 @@ 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 { + LED_PORT.OUTSET=LED_RED; + ACA.AC1CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt // enable the pause-finding timer CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | TC_EVSEL_CH0_gc; 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; CODEC_TIMER_TIMESTAMPS.CNT = 0; @@ -266,23 +291,72 @@ ISR(CODEC_TIMER_LOADMOD_CCA_VECT) // pause found return; } +static void StartDemod(void){ + LED_PORT.OUTCLR = LED_RED; + + + /* + * 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.AC1CTRL = 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.CCA = 95; // with 27.12 MHz this is 3/4 of a half bit width + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + CODEC_TIMER_LOADMOD.INTFLAGS = TC1_CCAIF_bm; + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCAINTLVL_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.CCA = 160; + CODEC_TIMER_TIMESTAMPS.INTCTRLA = 0; + CODEC_TIMER_TIMESTAMPS.INTFLAGS = TC1_CCAIF_bm; // Clear interrupt flag + CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCAINTLVL_LO_gc; + + /* Use the event system for resetting the pause-detecting timer. */ + EVSYS.CH0MUX = EVSYS_CHMUX_ACA_CH1_gc; // on every ACA_AC1 INT + EVSYS.CH0CTRL = EVSYS_DIGFILT_1SAMPLE_gc; + + ACA.AC0CTRL = 0; + CODEC_DEMOD_IN_PORT.INTCTRL = 0; + +} void Reader14443ACodecTask(void) { - if (Flags.RxPending && SYSTICK_DIFF(RxPendingSince) > Reader_FWT + 1) - { - Reader14443A_EOC(); - BitCount = 0; - Flags.RxDone = true; - Flags.RxPending = false; - } - if (CodecIsReaderToBeRestarted() || !CodecIsReaderFieldReady()) - return; + + // Waiting for response time out +// if (Flags.RxPending && SYSTICK_DIFF(RxPendingSince) > Reader_FWT + 1) +// { +// Reader14443A_EOC(); +// BitCount = 0; +// Flags.RxDone = true; +// Flags.RxPending = false; +// } +// if (CodecIsReaderToBeRestarted() || !CodecIsReaderFieldReady()) +// return; if (!Flags.RxPending && (Flags.Start || Flags.RxDone)) { - if (State == STATE_FDT && CODEC_TIMER_LOADMOD.CNT < ISO14443A_PICC_TO_PCD_MIN_FDT) // we are in frame delay time, so we can return later - return; + +// if (State == STATE_FDT && CODEC_TIMER_LOADMOD.CNT < ISO14443A_PICC_TO_PCD_MIN_FDT) { // we are in frame delay time, so we can return later +// return; +// } + if (Flags.RxDone && BitCount > 0) // decode the raw received data { + if (BitCount < ISO14443A_RX_MINIMUM_BITCOUNT * 2) { BitCount = 0; @@ -296,6 +370,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; @@ -322,9 +398,11 @@ void Reader14443ACodecTask(void) } if (BitCount % 8) // copy the last byte, if there is an incomplete byte CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); - LEDHook(LED_CODEC_RX, LED_PULSE); LogEntry(LOG_INFO_CODEC_RX_DATA_W_PARITY, CodecBuffer, (BitCount + 7) / 8); + + Flags.RxPending=true; } + } Flags.Start = false; Flags.RxDone = false; @@ -332,55 +410,31 @@ void Reader14443ACodecTask(void) /* Call application with received data */ BitCount = ApplicationProcess(CodecBuffer, BitCount); - if (BitCount > 0) + // Application have data to be sent + if (false)//BitCount > 0) { - /* - * 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. - */ - /* Configure and enable the analog comparator for finding pauses in the DEMOD signal. */ - ACA.AC1CTRL = 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.CCA = 95; // with 27.12 MHz this is 3/4 of a half bit width - CODEC_TIMER_LOADMOD.INTCTRLA = 0; - CODEC_TIMER_LOADMOD.INTFLAGS = TC1_CCAIF_bm; - CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCAINTLVL_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; - CODEC_TIMER_TIMESTAMPS.PER = 0xFFFF; - CODEC_TIMER_TIMESTAMPS.CCA = 160; - CODEC_TIMER_TIMESTAMPS.INTCTRLA = 0; - CODEC_TIMER_TIMESTAMPS.INTFLAGS = TC1_CCAIF_bm; - CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCAINTLVL_LO_gc; - - /* Use the event system for resetting the pause-detecting timer. */ - EVSYS.CH0MUX = EVSYS_CHMUX_ACA_CH1_gc; // on every ACA_AC1 INT - EVSYS.CH0CTRL = EVSYS_DIGFILT_1SAMPLE_gc; - - ACA.AC0CTRL = 0; - CODEC_DEMOD_IN_PORT.INTCTRL = 0; + StartDemod(); LEDHook(LED_CODEC_TX, LED_PULSE); 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; CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCBIF_bm; CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCBINTLVL_HI_gc; - _delay_loop_1(85); + _delay_loop_1(85); // Wait for sending to finish + + + }else{ // No data need to be send or in SNIFFING mode + // TODO: add another sniff flag, in case of no Application data need to be send (Non sniffing mode) + StartDemod(); + Reader14443AMillerEOC(); + + // Sniffing mode, enable sampling interrupt only } } } @@ -391,7 +445,7 @@ void Reader14443ACodecStart(void) BitCount = 0; Flags.Start = true; - CodecReaderFieldStart(); +// CodecReaderFieldStart(); } void Reader14443ACodecReset(void) @@ -400,5 +454,43 @@ void Reader14443ACodecReset(void) State = STATE_IDLE; Flags.RxDone = false; Flags.Start = false; - CodecReaderFieldStop(); + //CodecReaderFieldStop(); } + +void TestSniff14443ACodecInit(void){ + + //////////////////////////// + // Same as reader init + /* Initialize common peripherals and start listening + * for incoming data. */ + + + CodecInitCommon(); + + CodecSetDemodPower(true); + + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; + CODEC_TIMER_SAMPLING.CCB = 0; + CODEC_TIMER_SAMPLING.CCC = 0; + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.INTCTRLA = 0; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCBINTLVL_OFF_gc; + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc; + + CODEC_TIMER_LOADMOD.CTRLA = 0; + State = STATE_IDLE; + + BitCount = 0; + Flags.Start = false; + Flags.RxPending = false; + Flags.RxDone = false; + /////////////////////////// + + Flags.Start = true; +// Flags.RxPending = true; + + //LogEntry(LOG_INFO_CODEC_TX_DATA_W_PARITY, "Codec Sniff Start", 18); + //Reader14443A_EOC(); + + +} \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h index e9a2c1e..a96fff2 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h @@ -15,6 +15,7 @@ void Reader14443ACodecInit(void); void Reader14443ACodecDeInit(void); void Reader14443ACodecTask(void); +void TestSniff14443ACodecInit(void); /* Application Interface */ void Reader14443ACodecStart(void); diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c index 9e98f0d..48f3ee8 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -13,13 +13,16 @@ #include -void Sniff14443ACodecInit(void){ +void Sniff14443ACodecInit(void) +{ } -void Sniff14443ACodecDeInit(void) { - +void Sniff14443ACodecDeInit(void) +{ + Reader14443ACodecDeInit(); } void Sniff14443ACodecTask(void) { + Reader14443ACodecTask(); } \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 72ffce1..22eaf3b 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -188,9 +188,9 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { #endif #ifdef CONFIG_ISO14443A_SNIFF_SUPPORT [CONFIG_ISO14443A_SNIFF] = { - .CodecInitFunc = ISO14443ACodecInit, - .CodecDeInitFunc = ISO14443ACodecDeInit, - .CodecTaskFunc = ISO14443ACodecTask, + .CodecInitFunc = TestSniff14443ACodecInit, + .CodecDeInitFunc = Reader14443ACodecDeInit, + .CodecTaskFunc = Reader14443ACodecTask, .ApplicationInitFunc = ApplicationInitDummy, .ApplicationResetFunc = ApplicationResetDummy, .ApplicationTaskFunc = ApplicationTaskDummy, diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 9d3175f..5870a2b 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -92,7 +92,7 @@ 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 += 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 SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA