Skip to content

Commit

Permalink
Merge branch 'master' into DecodeMFDPython-pr
Browse files Browse the repository at this point in the history
  • Loading branch information
geo-rg authored Sep 12, 2018
2 parents 2af62ab + 409b0e4 commit 1f435b8
Showing 15 changed files with 845 additions and 26 deletions.
1 change: 1 addition & 0 deletions Firmware/Chameleon-Mini/Application/Application.h
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
#include "MifareUltralight.h"
#include "MifareClassic.h"
#include "Reader14443A.h"
#include "Sniff14443A.h"

/* Function wrappers */
INLINE void ApplicationInit(void) {
1 change: 1 addition & 0 deletions Firmware/Chameleon-Mini/Application/Reader14443A.c
Original file line number Diff line number Diff line change
@@ -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;

173 changes: 173 additions & 0 deletions Firmware/Chameleon-Mini/Application/Sniff14443A.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
//
// Created by Zitai Chen on 25/07/2018.
// Application layer for sniffing
// Currently only support Autocalibrate
//

#include <stdbool.h>
#include <LED.h>
#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;
}
}
24 changes: 24 additions & 0 deletions Firmware/Chameleon-Mini/Application/Sniff14443A.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Created by Zitai Chen on 25/07/2018.
//

#ifndef CHAMELEON_MINI_SNIFF14443A_H
#define CHAMELEON_MINI_SNIFF14443A_H

#include <stdint.h>

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

2 changes: 1 addition & 1 deletion Firmware/Chameleon-Mini/Codec/Codec.c
Original file line number Diff line number Diff line change
@@ -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!
{
21 changes: 18 additions & 3 deletions Firmware/Chameleon-Mini/Codec/Codec.h
Original file line number Diff line number Diff line change
@@ -17,14 +17,15 @@

#include "ISO14443-2A.h"
#include "Reader14443-2A.h"
#include "SniffISO14443-2A.h"

/* Timing definitions for ISO14443A */
#define ISO14443A_SUBCARRIER_DIVIDER 16
#define ISO14443A_BIT_GRID_CYCLES 128
#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);
}
10 changes: 7 additions & 3 deletions Firmware/Chameleon-Mini/Codec/ISO14443-2A.c
Original file line number Diff line number Diff line change
@@ -66,19 +66,20 @@ 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;
CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCAIF_bm;
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);

Loading

0 comments on commit 1f435b8

Please sign in to comment.