reader codec upgrade

This commit is contained in:
Georg
2018-01-22 08:47:59 +01:00
parent e53b0a067d
commit a5d0a8d216
7 changed files with 390 additions and 223 deletions
@@ -10,6 +10,13 @@
#define CHECK_BCC(B) ((B[0] ^ B[1] ^ B[2] ^ B[3]) == B[4])
#define IS_CASCADE_BIT_SET(buf) (buf[0] & 0x04)
#define IS_ISO14443A_4_COMPLIANT(buf) (buf[0] & 0x20)
#define MF_CLASSIC_READER_NONCE 0x00000000
#define TRYCOUNT_MAX 16
#define FLAGS_MASK 0x03
#define FLAGS_PARITY_OK 0x01
#define FLAGS_NO_DATA 0x02
// TODO replace remaining magic numbers
@@ -197,15 +204,13 @@ void Reader14443AAppTick(void)
INLINE uint16_t Reader14443A_Deselect(uint8_t* Buffer) // deselects the card because of an error, so we will continue to select the card afterwards
{
Buffer[0] = 0xC2;
uint16_t crc = ISO14443_CRCA(Buffer, 1);
Buffer[1] = crc;
Buffer[2] = crc >> 8;
ISO14443AAppendCRCA(Buffer, 1);
ReaderState = STATE_DESELECT;
Selected = false;
return addParityBits(Buffer, 24);
}
INLINE uint16_t Reader14443A_Select(uint8_t * Buffer, uint16_t BitCount)
static uint16_t Reader14443A_Select(uint8_t * Buffer, uint16_t BitCount)
{
if (Selected)
{
@@ -343,21 +348,17 @@ INLINE uint16_t Reader14443A_Halt(uint8_t* Buffer)
{
Buffer[0] = ISO14443A_CMD_HLTA;
Buffer[1] = 0x00;
uint16_t crc = ISO14443_CRCA(Buffer, 2);
Buffer[2] = crc;
Buffer[3] = crc >> 8;
ISO14443AAppendCRCA(Buffer, 2);
ReaderState = STATE_HALT;
Selected = false;
return addParityBits(Buffer, 32);
return addParityBits(Buffer, 4 * BITS_PER_BYTE);
}
INLINE uint16_t Reader14443A_RATS(uint8_t* Buffer)
{
Buffer[0] = 0xE0; // RATS command
Buffer[1] = 0x80;
uint16_t crc = ISO14443_CRCA(Buffer, 2);
Buffer[2] = crc;
Buffer[3] = crc >> 8;
ISO14443AAppendCRCA(Buffer, 2);
ReaderState = STATE_ATS;
return addParityBits(Buffer, 32);
}
@@ -457,77 +458,143 @@ uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount)
RT_STATE_IDLE,
RT_STATE_SEARCHING
} RTState = RT_STATE_IDLE;
static uint8_t ErrorCount = 0;
static uint8_t Thresholds[(CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = {0}; // todo this could be improved by using the bits and not the whole bytes
static uint8_t TryCount = 0;
static uint8_t Thresholds[(CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = {0};
if (RTState == RT_STATE_IDLE)
{
CodecThresholdSet(CODEC_THRESHOLD_CALIBRATE_MIN);
RTState = RT_STATE_SEARCHING;
ErrorCount = 0;
} else if (RTState == RT_STATE_SEARCHING && ReaderState <= STATE_HALT && ErrorCount++ == 8) {
if (CodecThresholdIncrement() >= CODEC_THRESHOLD_CALIBRATE_MAX)
TryCount = 0;
} else if (RTState == RT_STATE_SEARCHING && ReaderState <= STATE_HALT) {
if (++TryCount == TRYCOUNT_MAX)
{
RTState = RT_STATE_IDLE;
bool block = false;
uint16_t min = 0;
uint16_t max = 0;
uint16_t maxdiff = 0;
uint16_t maxdiffoffset = 0;
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, NULL);
uint16_t i;
for (i = 0; i < (CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS; i++)
uint16_t tmp_th = CodecThresholdIncrement();
if ((tmp_th >= CODEC_THRESHOLD_CALIBRATE_MID && (tmp_th - CODEC_THRESHOLD_CALIBRATE_STEPS) < CODEC_THRESHOLD_CALIBRATE_MID)
||
tmp_th >= CODEC_THRESHOLD_CALIBRATE_MAX)
{
char tmpBuf[10];
snprintf(tmpBuf, 10, "%4" PRIu16 ": ", i*CODEC_THRESHOLD_CALIBRATE_STEPS + CODEC_THRESHOLD_CALIBRATE_MIN);
TerminalSendString(tmpBuf);
if (Thresholds[i])
bool block = false, finished = false;
uint16_t min = 0;
uint16_t max = 0;
uint16_t maxdiff = 0;
uint16_t maxdiffoffset = 0;
uint16_t numworked;
uint16_t i;
// first, search inside the usual search space
if (tmp_th >= CODEC_THRESHOLD_CALIBRATE_MID && (tmp_th - CODEC_THRESHOLD_CALIBRATE_STEPS) < CODEC_THRESHOLD_CALIBRATE_MID)
{
TerminalSendStringP(PSTR("+\r\n"));
if (!block)
for (i = 0; i < (CODEC_THRESHOLD_CALIBRATE_MID - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS; i++)
{
block = true;
min = i;
}
} else {
TerminalSendStringP(PSTR("-\r\n"));
if (block)
{
block = false;
max = i;
if ((max - min) > maxdiff)
if (Thresholds[i] == TRYCOUNT_MAX)
{
maxdiff = max - min;
maxdiffoffset = min;
if (!block)
{
block = true;
min = i;
}
} else {
if (block)
{
block = false;
max = i;
if ((max - min) >= maxdiff)
{
maxdiff = max - min;
maxdiffoffset = min;
}
}
}
}
if (maxdiff >= 4) // if we have found something with at least 5 consecutive working thresholds (only if these thresholds have worked for evers attempt), we are done
{
finished = true;
}
} else { // we have searched the whole space
for (numworked = TRYCOUNT_MAX; numworked > 0; numworked--)
{
for (i = 0; i < (CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS; i++)
{
if (Thresholds[i] >= numworked)
{
if (!block)
{
block = true;
min = i;
}
} else {
if (block)
{
block = false;
max = i;
if ((max - min) >= maxdiff)
{
maxdiff = max - min;
maxdiffoffset = min;
}
}
}
}
if (maxdiff > 0)
{
break;
}
}
finished = true;
}
if (finished)
{
RTState = RT_STATE_IDLE;
if (maxdiff != 0)
CodecThresholdSet((maxdiffoffset + maxdiff / 2) * CODEC_THRESHOLD_CALIBRATE_STEPS + CODEC_THRESHOLD_CALIBRATE_MIN);
else
CodecThresholdReset();
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, NULL);
uint16_t i_max = (CODEC_THRESHOLD_CALIBRATE_MID - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS;
if (tmp_th >= CODEC_THRESHOLD_CALIBRATE_MAX)
i_max = (CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS;
for (i = 0; i < i_max; i++)
{
char tmpBuf[10];
snprintf(tmpBuf, 10, "%4" PRIu16 ": ", i*CODEC_THRESHOLD_CALIBRATE_STEPS + CODEC_THRESHOLD_CALIBRATE_MIN);
TerminalSendString(tmpBuf);
if (Thresholds[i])
{
snprintf(tmpBuf, 10, "%3" PRIu16, Thresholds[i]);
TerminalSendString(tmpBuf);
} else {
TerminalSendChar('-');
}
TerminalSendStringP(PSTR("\r\n"));
Thresholds[i] = 0; // reset the threshold so the next run won't show old results
}
Selected = false;
Reader14443CurrentCommand = Reader14443_Do_Nothing;
Reader14443ACodecReset();
return 0;
}
Thresholds[i] = 0; // reset the threshold so the next run won't show old results
}
if (maxdiff != 0)
CodecThresholdSet((maxdiffoffset + maxdiff / 2) * CODEC_THRESHOLD_CALIBRATE_STEPS + CODEC_THRESHOLD_CALIBRATE_MIN);
else
CodecThresholdReset();
Selected = false;
Reader14443CurrentCommand = Reader14443_Do_Nothing;
CodecReaderFieldStop();
return 0;
TryCount = 0;
}
Thresholds[(ReaderThreshold - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = 0;
CodecThresholdIncrement();
ErrorCount = 0;
}
uint16_t rVal = Reader14443A_Select(Buffer, BitCount);
if (Selected) // we are done finding the threshold
{
Thresholds[(ReaderThreshold - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = 1;
CodecThresholdIncrement();
Thresholds[(ReaderThreshold - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] += 1;
if (TryCount == TRYCOUNT_MAX)
{
CodecThresholdIncrement();
TryCount = 0;
}
ReaderState = STATE_IDLE;
Reader14443ACodecStart();
return Reader14443A_Halt(Buffer);
@@ -592,13 +659,11 @@ uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount)
}
Buffer[0] = 0x30; // MiFare Ultralight read command
Buffer[1] = MFURead_CurrentAdress;
uint16_t crc = ISO14443_CRCA(Buffer, 2);
Buffer[2] = crc;
Buffer[3] = crc >> 8;
ISO14443AAppendCRCA(Buffer, 2);
MFURead_CurrentAdress += 4;
return addParityBits(Buffer, 32);
return addParityBits(Buffer, 4 * BITS_PER_BYTE);
}
return rVal;
}
@@ -19,7 +19,6 @@ uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount);
uint16_t addParityBits(uint8_t * Buffer, uint16_t bits);
uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount);
uint16_t removeSOC(uint8_t * Buffer, uint16_t BitCount);
bool checkParityBits(uint8_t * Buffer, uint16_t BitCount);
uint16_t ISO14443_CRCA(uint8_t * Buffer, uint8_t ByteCount);
+3 -2
View File
@@ -74,8 +74,9 @@
#define CODEC_AC_DEMOD_SETTINGS AC_HSMODE_bm | AC_HYSMODE_NO_gc
#define CODEC_MAXIMUM_THRESHOLD 0xFFF // the maximum voltage can be calculated with ch0data * Vref / 0xFFF
#define CODEC_THRESHOLD_CALIBRATE_MIN 128
#define CODEC_THRESHOLD_CALIBRATE_MAX 1024
#define CODEC_THRESHOLD_CALIBRATE_STEPS 8
#define CODEC_THRESHOLD_CALIBRATE_MID 768
#define CODEC_THRESHOLD_CALIBRATE_MAX 2048
#define CODEC_THRESHOLD_CALIBRATE_STEPS 16
#define CODEC_TIMER_TIMESTAMPS TCD1
#define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect
+143 -153
View File
@@ -28,12 +28,8 @@ static volatile uint16_t RxPendingSince;
static volatile enum {
STATE_IDLE,
STATE_MILLER_SOF0,
STATE_MILLER_SOF1,
STATE_MILLER_TX0,
STATE_MILLER_TX1,
STATE_MILLER_EOF0,
STATE_MILLER_EOF1,
STATE_MILLER_SEND,
STATE_MILLER_EOF,
STATE_FDT
} State;
@@ -54,11 +50,13 @@ void Reader14443ACodecInit(void) {
CodecInitCommon();
CodecSetDemodPower(true);
CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES/2 - 1;
CODEC_TIMER_SAMPLING.CCB = 1;
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_HI_gc;
CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCBINTLVL_OFF_gc;
CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc;
CODEC_TIMER_LOADMOD.CTRLA = 0;
State = STATE_IDLE;
@@ -80,6 +78,22 @@ void Reader14443ACodecDeInit(void) {
Flags.Start = false;
}
INLINE void Insert0(void)
{
SampleRegister >>= 1;
if (++BitCount % 8)
return;
*CodecBufferPtr++ = SampleRegister;
}
INLINE void Insert1(void)
{
SampleRegister = (SampleRegister >> 1) | 0x80;
if (++BitCount % 8)
return;
*CodecBufferPtr++ = SampleRegister;
}
INLINE void Reader14443A_EOC(void)
{
CODEC_TIMER_LOADMOD.INTCTRLB = 0;
@@ -88,6 +102,14 @@ INLINE void Reader14443A_EOC(void)
CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_OFF_gc;
ACA.AC1CTRL &= ~AC_ENABLE_bm;
if (BitCount & 1)
{
if (SampleRegister & 0x80)
Insert0();
else
Insert1();
}
if (BitCount % 8) // copy the last byte, if there is an incomplete byte
CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8));
Flags.RxDone = true;
@@ -104,140 +126,96 @@ INLINE void Reader14443A_EOC(void)
State = STATE_FDT;
}
ISR(CODEC_TIMER_SAMPLING_CCB_VECT)
INLINE void BufferToSequence(void)
{
static void * JumpTable[] = {
[STATE_IDLE] = &&STATE_IDLE_LABEL,
[STATE_MILLER_SOF0] = &&STATE_MILLER_SOF0_LABEL,
[STATE_MILLER_SOF1] = &&STATE_MILLER_SOF1_LABEL,
[STATE_MILLER_TX0] = &&STATE_MILLER_TX0_LABEL,
[STATE_MILLER_TX1] = &&STATE_MILLER_TX1_LABEL,
[STATE_MILLER_EOF0] = &&STATE_MILLER_EOF0_LABEL,
[STATE_MILLER_EOF1] = &&STATE_MILLER_EOF1_LABEL,
[STATE_FDT] = &&STATE_FDT_LABEL
};
goto *JumpTable[State];
STATE_MILLER_SOF0_LABEL:
/* Output a SOF */
CodecSetReaderField(false);
_delay_us(2.5);
CodecSetReaderField(true);
CodecBufferIdx = 0;
SampleRegister = CodecBuffer[0];
BitCountUp = 0;
State = STATE_MILLER_SOF1;
uint16_t count = BitCount;
if (count > BITS_PER_BYTE * CODEC_BUFFER_SIZE / 2) // todo is this correct?
return;
STATE_MILLER_SOF1_LABEL:
State = STATE_MILLER_TX0;
return;
BitCount = 0;
STATE_MILLER_TX0_LABEL:
/* First half of bit-slot */
if (SampleRegister & 0x01) {
/* Do Nothing */
memcpy(CodecBuffer + CODEC_BUFFER_SIZE / 2, CodecBuffer, (count + 7) / 8);
uint8_t * Buffer = CodecBuffer + CODEC_BUFFER_SIZE / 2;
CodecBufferPtr = CodecBuffer;
Insert1(); // SOC
Insert0();
uint16_t i;
uint8_t last = 0;
for (i = 1; i <= count; i++)
{
if ((*Buffer) & 1)
{
Insert0();
Insert1();
last = 1;
} else {
if (LastBit == 0) {
CodecSetReaderField(false);
_delay_us(2.5);
CodecSetReaderField(true);
if (last)
{
Insert0();
Insert0();
} else {
/* Do Nothing */
Insert1();
Insert0();
}
last = 0;
}
State = STATE_MILLER_TX1;
return;
STATE_MILLER_TX1_LABEL:
/* Second half of bit-slot */
if (SampleRegister & 0x01) {
CodecSetReaderField(false);
_delay_us(2.5);
CodecSetReaderField(true);
LastBit = 1;
} else {
/* No modulation pauses */
LastBit = 0;
}
SampleRegister >>= 1;
if (--BitCount == 0) {
State = STATE_MILLER_EOF0;
} else {
State = STATE_MILLER_TX0;
}
if ((++BitCountUp % 8) == 0)
SampleRegister = CodecBuffer[++CodecBufferIdx];
return;
STATE_MILLER_EOF0_LABEL:
if (LastBit == 0) {
CodecSetReaderField(false);
_delay_us(2.5);
CodecSetReaderField(true);
} else {
/* Do Nothing */
}
State = STATE_MILLER_EOF1;
return;
STATE_MILLER_EOF1_LABEL:
CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc;
_delay_us(50); // wait for DEMOD signal to stabilize
/* 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.STATUS = AC_AC1IF_bm;
ACA.AC1CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_BOTHEDGES_gc | AC_INTLVL_HI_gc | AC_ENABLE_bm;
CodecBufferPtr = CodecBuffer; // use GPIOR for faster access
BitCount = 1; // the first modulation of the SOC is "found" implicitly
SampleRegister = 0x80;
RxPendingSince = SystemGetSysTick();
Flags.RxPending = true;
// reset for future use
CodecBufferIdx = 0;
BitCountUp = 0;
State = STATE_IDLE;
return;
STATE_IDLE_LABEL:
STATE_FDT_LABEL:
return;
*Buffer >>= 1;
if ((i % 8) == 0)
Buffer++;
}
if (last == 0) // EOC
{
Insert1();
Insert0();
}
if (BitCount % 8)
CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8));
}
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. */
ACA.STATUS = AC_AC1IF_bm;
ACA.AC1CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_FALLING_gc | AC_INTLVL_HI_gc | AC_ENABLE_bm;
CodecBufferPtr = CodecBuffer; // use GPIOR for faster access
BitCount = 1; // FALSCH todo the first modulation of the SOC is "found" implicitly
SampleRegister = 0x00;
RxPendingSince = SystemGetSysTick();
Flags.RxPending = true;
// reset for future use
CodecBufferIdx = 0;
BitCountUp = 0;
State = STATE_IDLE;
PORTE.OUTTGL = PIN3_bm;
}
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;
CODEC_TIMER_SAMPLING.PERBUF = SAMPLE_RATE_SYSTEM_CYCLES - 1;
PORTE.OUTTGL = PIN3_bm;
}
ISR(CODEC_TIMER_TIMESTAMPS_CCA_VECT) // EOC found
{
Reader14443A_EOC();
}
INLINE void Insert0(void)
{
SampleRegister >>= 1;
if (++BitCount % 8)
return;
*CodecBufferPtr++ = SampleRegister;
}
INLINE void Insert1(void)
{
SampleRegister = (SampleRegister >> 1) | 0x80;
if (++BitCount % 8)
return;
*CodecBufferPtr++ = SampleRegister;
}
ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered before
{
ACA.AC1CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt
@@ -253,27 +231,36 @@ ISR(CODEC_TIMER_LOADMOD_CCA_VECT) // pause found
/* 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_DIV2_gc;
CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_DIV4_gc;
switch (tmp) // decide how many half bit periods have been modulations
{
case 0 ... 96: // 64 ticks is one half of a bit period
Insert0();
// If one full bit period is over AND the last half bit period also was a pause,
// we have found the EOC.
if ((BitCount & 1) == 0 && (SampleRegister & 0x40) == 0)
Reader14443A_EOC();
case 0 ... 48: // 32 ticks is one half of a bit period
return;
case 97 ... 160: // 128 ticks is a full bit period
case 49 ... 80: // 64 ticks are a full bit period
Insert1();
Insert0();
return;
default: // every value over 128 + 32 (tolerance) is considered to be 3 half bit periods
case 81 ... 112: // 96 ticks are 3 half bit periods
if (BitCount & 1)
{
Insert1();
Insert1();
Insert0();
} else {
Insert1();
Insert0();
Insert0();
}
return;
default: // every value over 96 + 16 (tolerance) is considered to be 4 half bit periods
Insert1();
Insert1();
Insert0();
Insert0();
return;
}
return;
@@ -283,6 +270,7 @@ void Reader14443ACodecTask(void)
{
if (Flags.RxPending && SYSTICK_DIFF(RxPendingSince) > Reader_FWT + 1)
{
Reader14443A_EOC();
BitCount = 0;
Flags.RxDone = true;
Flags.RxPending = false;
@@ -307,7 +295,7 @@ void Reader14443ACodecTask(void)
BitCount = 0;
bool breakflag = false;
TmpCodecBuffer[0] >>= 2; // with this (and BitCountTmp = 2), the SOC is ignored and thus it's not neccessary to remove it later
TmpCodecBuffer[0] >>= 2; // with this (and BitCountTmp = 2), the SOC is ignored
while (!breakflag && BitCountTmp < TotalBitCount)
{
uint8_t Bit = TmpCodecBuffer[BitCountTmp / 8] & 0x03;
@@ -315,18 +303,14 @@ void Reader14443ACodecTask(void)
switch (Bit)
{
case 0b10:
Insert0();
break;
case 0b01:
Insert1();
break;
case 0b01:
Insert0();
break;
case 0b00: // EOC
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);
breakflag = true;
break;
@@ -336,6 +320,10 @@ void Reader14443ACodecTask(void)
}
BitCountTmp += 2;
}
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.Start = false;
@@ -357,12 +345,12 @@ void Reader14443ACodecTask(void)
*/
/* Configure and enable the analog comparator for finding pauses in the DEMOD signal. */
ACA.AC1CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_BOTHEDGES_gc | AC_ENABLE_bm;
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 = 127; // with 27.12 MHz this is exactly one half bit width
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;
@@ -371,7 +359,7 @@ void Reader14443ACodecTask(void)
/* 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 = 256;
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;
@@ -387,10 +375,12 @@ void Reader14443ACodecTask(void)
LogEntry(LOG_INFO_CODEC_TX_DATA_W_PARITY, CodecBuffer, (BitCount + 7) / 8);
/* Set state and start timer for Miller encoding. */
State = STATE_MILLER_SOF0;
LastBit = 0;
CODEC_TIMER_SAMPLING.CNT = 0;
CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc;
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);
}
}
}
@@ -19,5 +19,7 @@ void Reader14443ACodecTask(void);
/* Application Interface */
void Reader14443ACodecStart(void);
void Reader14443ACodecReset(void);
bool Reader14443ACodecSendingOrReceiving(void);
void Reader14443AMillerEOC(void);
#endif /* READER14443_2A_H_ */
@@ -0,0 +1,110 @@
#include <avr/io.h>
#define Zero R0
#define Tmp R16
#define BitCountL R18
#define BitCountH R19
#define NewLoad R20
#define SampleRegister R21
#define GPIORBitCountL 4
#define GPIORBitCountH 5
#define CodecBufferPtrL 10
#define CodecBufferPtrH 11
#define AWEXC__OUTOVEN 0x088C
#define CODEC_READER_TIMER__CTRLA 0x0800
.global TCD0_CCB_vect, Reader14443AMillerEOC
TCD0_CCB_vect:
push Zero ; 1
eor Zero, Zero ; 1
push Tmp ; 1
push BitCountL ; 1
push BitCountH ; 1
push NewLoad ; 1
push SampleRegister ; 1
in Tmp, 0x3f ; SREG ; 1
push Tmp ; 1
push ZL ; 1
push ZH ; 1
; SUM: 8
in ZL, CodecBufferPtrL
in ZH, CodecBufferPtrH
ld SampleRegister, Z+
clr NewLoad
in BitCountH, GPIORBitCountH
in BitCountL, GPIORBitCountL
LOOP:
; POINT ZERO
lsr SampleRegister ; 1
brcc NO_TURNOFF_COMPENSATION ; 1 / 2
sts AWEXC__OUTOVEN, Zero ; turn off field ; 2
sts CODEC_READER_TIMER__CTRLA, Zero ; 2
ldi Tmp, 0x16 ; 1
TURNOFF_LOOP:
dec Tmp ; 1
brne TURNOFF_LOOP ; 1 / 2 ; sums up to 21 * 3 + 2
rjmp .+0 ; double nop ; 2
ldi Tmp, 0x01 ; 1
sts CODEC_READER_TIMER__CTRLA, Tmp ; turn on field ; 2
ldi Tmp, 0x03 ; 1
sts AWEXC__OUTOVEN, Tmp ; 2
rjmp NO_TURNOFF ; 2
; SUM: 82 until now
NO_TURNOFF_COMPENSATION:
ldi Tmp, 26 ; 1
NO_TURNOFF_COMPENSATION_LOOP:
dec Tmp ; 1
brne NO_TURNOFF_COMPENSATION_LOOP ; 1 / 2 sums up to 25 * 3 + 2
nop ; 1
NO_TURNOFF: ; 82 at this point
subi BitCountL, 1 ; decrement BitCount ; 1
sbci BitCountH, 0 ; 1
brne NO_EOC ; 1 / 2
; EOC:
call Reader14443AMillerEOC
rjmp RETURN
NO_EOC: ; 86 at this point
subi NewLoad, 0xFF ; 1
andi NewLoad, 0x07 ; 1
brne LOAD_COMPENSATION ; 1 / 2
; SUM: 4
ld SampleRegister, Z+ ; 3
rjmp NOP_LOOP_INIT ; 2
LOAD_COMPENSATION: ; 90 at this point
rjmp .+0 ; double nop ; 2
rjmp .+0 ; double nop ; 2
NOP_LOOP_INIT:
ldi Tmp, 10 ; 1
NOP_LOOP:
dec Tmp ; 1
brne NOP_LOOP ; 1 / 2 sums up to 9 * 3 + 2
rjmp .+0 ; 2
rjmp LOOP ; 2
RETURN:
pop ZH
pop ZL
pop Tmp
out 0x3f, Tmp ; SREG
pop SampleRegister
pop NewLoad
pop BitCountH
pop BitCountL
pop Tmp
pop Zero
reti ; 2
+1 -1
View File
@@ -90,7 +90,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
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 += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
LUFA_PATH = ../LUFA