Skip to content

Commit

Permalink
Merge pull request #318 from cacke-r/master
Browse files Browse the repository at this point in the history
AUTOCALIBRATE command for Sniff-ISO15693 application
  • Loading branch information
fptrs authored Mar 1, 2022
2 parents 94aeb3c + 14537ac commit 371eaca
Show file tree
Hide file tree
Showing 9 changed files with 403 additions and 12 deletions.
222 changes: 221 additions & 1 deletion Firmware/Chameleon-Mini/Application/Sniff15693.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,77 @@
#include "../Codec/SniffISO15693.h"
#include "Sniff15693.h"

/* Incrementing in steps of 50 was considered as sufficiently */
/* accurate during tests */
#define ISO15693_TH_CALIBRATE_STEPS 50
//#define ISO15693_DEBUG_LOG
typedef enum {
AUTOCALIB_INIT,
AUTOCALIB_READER_DATA,
AUTOCALIB_CARD_DATA,
} Sniff15693State;

Sniff15693Command Sniff15693CurrentCommand;
static Sniff15693State autocalib_state = AUTOCALIB_INIT;

/* The Autocalib shall work as following: */
/* Calls to AppProcess shall always alternate b/w ReaderData and CardData */
/* If there are 2 successive calls to to AppProcess with ReaderData, it means */
/* we have not received card data -> bad case */
/* So, we need always two calls to AppProcess to evaluate b/w good & bad case */
/* two calls are called a cycle further on */
/* we do increment the threshold after each cycle */
/* We store the first successfull card data as min_succ_th (means the threshold when we have received */
/* card data the first time */
/* And now we increment the threshold further, until we dont get card data anymore */
/* This will be stored in 'max_succ_th */
/* We do assume now, that the optimal threshold is between min_succ_th and max_succ_th */
/* With this approach we do avoid, to maintain a large array of possible thresholds */
/* The serach range is defined by the DemodFloorNoiseLevel */
/* We search b/w: */
/* 0.5 * DemodFloorNoiseLevel --> 1.5 * DemodFloorNoiseLevel */


/*
_________________________ scanning range ______________________________________
/ \
-|---------|-----------------------------------------threshold-----------------------------|------------>
| |
typical pattern| |
- bad case |------------------------+-++++-+-+---------------------------------------------|
+ good case | | | |
| min_succ_th | |
| max_succ_th |
min_th max_th
And finally the desired threshold is: (min_succ_th + max_succ_th) >> 1
*/
static uint16_t curr_th = 0;
static uint16_t min_th = 0;
static uint16_t max_th = 0xFFF;
static uint16_t min_succ_th = 0;
static uint16_t max_succ_th = 0xFFF;

/* to store the threshold which was used before we started AUTOCALIBRATION */
static uint16_t recent_th = 0;

static bool last_cycle_successful = false;

void SniffISO15693AppTimeout(void)
{
CodecThresholdSet(recent_th);
SniffISO15693AppReset();
}

void SniffISO15693AppInit(void)
{
Sniff15693CurrentCommand = Sniff15693_Do_Nothing;
autocalib_state = AUTOCALIB_INIT;
}

void SniffISO15693AppReset(void)
{
SniffISO15693AppInit();
}


Expand All @@ -27,11 +92,166 @@ void SniffISO15693AppTask(void)
void SniffISO15693AppTick(void)
{


}

INLINE void SniffISO15693InitAutocalib(void){
uint16_t floor_noise = SniffISO15693GetFloorNoise();
/* We search b/w: */
/* 0.5 * DemodFloorNoiseLevel --> 1.5 * DemodFloorNoiseLevel */
min_th = floor_noise >> 1;
max_th = floor_noise + (floor_noise >> 1);
if(min_th >= max_th) {
min_th = 0;
max_th = 0xFFF;
}

min_succ_th = 0;
max_succ_th = 0xFFF;


/* store current threshold before we started AUTOCALIBRATION */
recent_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold;

last_cycle_successful = false;
#ifdef ISO15693_DEBUG_LOG
{
char str[64];
sprintf(str, "Sniff15693: Start Autocalibration %d - %d ", min_th, max_th);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
}
#endif /*#ifdef ISO15693_DEBUG_LOG*/
curr_th = min_th;
CodecThresholdSet(curr_th);
return;
}

INLINE void SniffISO15693FinishAutocalib(void){
uint16_t new_th;
CommandStatusIdType ReturnStatusID = COMMAND_ERR_INVALID_USAGE_ID;
if(min_succ_th > 0) {
/* In this case AUTOCALIBRATION was successfull */
new_th = (min_succ_th + max_succ_th) >> 1;
CodecThresholdSet(new_th);
#ifdef ISO15693_DEBUG_LOG
{
char str[64];
sprintf(str, "Sniff15693: Finished Autocalibration %d - %d --> % d", min_succ_th, max_succ_th, new_th);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
}
#endif /*#ifdef ISO15693_DEBUG_LOG*/
ReturnStatusID = COMMAND_INFO_OK_WITH_TEXT_ID;
}else{
/* This means we never received a valid frame - Error*/
CodecThresholdSet(recent_th);
/* ReturnStatusID already set to error code */
}
SniffISO15693AppInit();
CommandLinePendingTaskFinished(ReturnStatusID, NULL);
}

INLINE void SniffISO15693IncrementThreshold(void){

/* So increment the threshold */
/* Steps of 3*16=48 are sufficient for us */
curr_th += ISO15693_TH_CALIBRATE_STEPS;
CodecThresholdSet(curr_th);
#ifdef ISO15693_DEBUG_LOG
{
char str[64];
sprintf(str, "Sniff15693: Try next th=%d", curr_th);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
}
#endif /*#ifdef ISO15693_DEBUG_LOG*/
if(curr_th >= max_th) {
/* We are finished now */
/* Evaluate the results */
SniffISO15693FinishAutocalib();
}
}

uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes)
{

bool crc_chk = ISO15693CheckCRC(FrameBuf, FrameBytes-ISO15693_CRC16_SIZE);

#ifdef ISO15693_DEBUG_LOG
char str[64];
sprintf(str, "Sniff15693: CrcCheck result=%d", crc_chk);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
#endif /*#ifdef ISO15693_DEBUG_LOG*/

switch (Sniff15693CurrentCommand) {
case Sniff15693_Do_Nothing: {
return 0;
}
case Sniff15693_Autocalibrate: {
switch(autocalib_state){
case(AUTOCALIB_INIT):
SniffISO15693InitAutocalib();
if(SniffTrafficSource == TRAFFIC_CARD)
autocalib_state = AUTOCALIB_CARD_DATA;
else
autocalib_state = AUTOCALIB_READER_DATA;
break;
case(AUTOCALIB_READER_DATA): /* Means last time we have received reader data */
if(SniffTrafficSource == TRAFFIC_READER){
/* Second time Reader Data received */
/* This means no card data received */
/* If we had successful tries before */
/* we need to record it as threshold max here */
if(last_cycle_successful == true){
max_succ_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold -
CODEC_THRESHOLD_CALIBRATE_STEPS;
#ifdef ISO15693_DEBUG_LOG
sprintf(str, "Sniff15693: Updated max_succ_th (%d) ", max_succ_th);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
#endif /*#ifdef ISO15693_DEBUG_LOG*/
}
last_cycle_successful = false;
}else{
if (crc_chk){
/* We have received card data now */
/* Threshold is in a good range */
/* if min_succ_th was never set ( == 0) */
/* Set it now to the current threshold */
if (min_succ_th == 0)
min_succ_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold;
last_cycle_successful = true;
}
#ifdef ISO15693_DEBUG_LOG
sprintf(str, "Sniff15693: Found card data (%d) - crc=%d", min_succ_th, crc_chk);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
#endif /*#ifdef ISO15693_DEBUG_LOG*/
autocalib_state = AUTOCALIB_CARD_DATA;
}
SniffISO15693IncrementThreshold();
break;
case(AUTOCALIB_CARD_DATA): /* Means last time we have received card data */
if(SniffTrafficSource == TRAFFIC_CARD){
if (crc_chk){
/* We have received card data now */
/* Threshold is in a good range */
/* if min_succ_th was never set ( == 0) */
/* Set it now to the current threshold */
if (min_succ_th == 0)
min_succ_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold;
last_cycle_successful = true;
}
#ifdef ISO15693_DEBUG_LOG
sprintf(str, "Sniff15693: Found card data (%d) - crc=%d", min_succ_th, crc_chk);
LogEntry(LOG_INFO_GENERIC, str, strlen(str));
#endif /*#ifdef ISO15693_DEBUG_LOG*/
SniffISO15693IncrementThreshold();
}else{
autocalib_state = AUTOCALIB_READER_DATA;
}
break;
default:
break;
}
return 0;
}
}
return 0;
}

Expand Down
10 changes: 9 additions & 1 deletion Firmware/Chameleon-Mini/Application/Sniff15693.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SniffISO15693.h
* Sniff15693.h
*
* Created on: 05.11.2019
* Author: ceres-c
Expand All @@ -16,5 +16,13 @@ void SniffISO15693AppReset(void);
void SniffISO15693AppTask(void);
void SniffISO15693AppTick(void);
uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes);
void SniffISO15693AppTimeout(void);

typedef enum {
Sniff15693_Do_Nothing,
Sniff15693_Autocalibrate,
} Sniff15693Command;

extern Sniff15693Command Sniff15693CurrentCommand;

#endif /* SNIFF_15693_H_ */
62 changes: 52 additions & 10 deletions Firmware/Chameleon-Mini/Codec/SniffISO15693.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static volatile uint8_t ReaderByteCount;
static volatile uint8_t CardByteCount;
static volatile uint16_t SampleDataCount;
static volatile uint8_t bBrokenFrame;
static bool bAutoThreshold = true;

/////////////////////////////////////////////////
// VCD->VICC
Expand Down Expand Up @@ -272,6 +273,20 @@ INLINE void SNIFF_ISO15693_READER_EOC_VCD(void) {
// VICC->VCD
/////////////////////////////////////////////////


/* Inline function to set the threshold, if bAutoThreshold is enabled*/
INLINE void SetDacCh0Data(uint16_t ch0data){
/* TODO: Check if either of the branches can be avoided */
/* to optimize the performance */
if(bAutoThreshold){
if (ch0data < 0xFFF)
DACB.CH0DATA = ch0data;
else
DACB.CH0DATA = 0xFFF;
}
return;
}

/* Initialize card sniffing options
Note: Currently implemented only single subcarrier SOC detection
*/
Expand Down Expand Up @@ -394,8 +409,8 @@ INLINE void CardSniffInit(void) {
ADCA.EVCTRL = ADC_SWEEP_01_gc;

/* Write threshold to the DAC channel 0 (connected to Analog Comparator positive input) */
DACB.CH0DATA = DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3); /* Slightly increase DAC output to ease triggering */
DACB.CH0DATA |= -( (DACB.CH0DATA & 0xFFF) < DemodFloorNoiseLevel); /* Branchfree saturating addition */
SetDacCh0Data(DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3)); /* Slightly increase DAC output to ease triggering */


/**
* Finally, now that we have the DAC set up, configure analog comparator A (the only one in this MCU)
Expand Down Expand Up @@ -449,8 +464,8 @@ ISR_SHARED isr_SNIFF_ISO15693_ACA_AC0_VECT(void) {

ACA.AC0CTRL = AC_ENABLE_bm | AC_HSMODE_bm | AC_HYSMODE_LARGE_gc | AC_INTMODE_RISING_gc | AC_INTLVL_OFF_gc; /* Disable this interrupt */

DACB.CH0DATA = DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 2); /* Blindly increase threshold after 1 pulse */
DACB.CH0DATA |= -( (DACB.CH0DATA & 0xFFF) < DemodFloorNoiseLevel); /* Branchfree saturating addition */
SetDacCh0Data(DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 2)); /* Blindly increase threshold after 1 pulse */

/* Note: by the time the DAC has changed its output, we're already after the 2nd pulse */
}

Expand All @@ -460,9 +475,8 @@ ISR_SHARED isr_SNIFF_ISO15693_ACA_AC0_VECT(void) {
ISR_SHARED isr_SNIFF_ISO15693_CODEC_TIMER_TIMESTAMPS_CCA_VECT(void) {

uint16_t TempRead = ADCA.CH1RES; /* Can't possibly be greater than 0xFFF since the dac has 12 bit res */
DACB.CH0DATA = TempRead - ANTENNA_LEVEL_OFFSET; /* Further increase DAC output after 3 pulses with value from PORTA Pin 2 (DEMOD-READER/2.3) */
DACB.CH0DATA &= -(DACB.CH0DATA <= TempRead); /* Branchfree saturating subtraction */

SetDacCh0Data(TempRead - ANTENNA_LEVEL_OFFSET); /* Further increase DAC output after 3 pulses with value from PORTA Pin 2 (DEMOD-READER/2.3) */
CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCAINTLVL_OFF_gc; /* Disable this interrupt */
}

Expand All @@ -480,8 +494,8 @@ ISR_SHARED isr_SNIFF_ISO15693_CODEC_TIMER_LOADMOD_CCA_VECT(void) {

CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCAINTLVL_OFF_gc; /* Disable all compare interrupts, including this one */

DACB.CH0DATA = DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3); /* Restore DAC output (AC negative comparation threshold) to pre-AC0 interrupt update value */
DACB.CH0DATA |= -( (DACB.CH0DATA & 0xFFF) < DemodFloorNoiseLevel); /* Branchfree saturating addition */
SetDacCh0Data(DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3)); /* Restore DAC output (AC negative comparation threshold) to pre-AC0 interrupt update value */

ACA.AC0CTRL |= AC_INTLVL_HI_gc; /* Re-enable analog comparator interrupt to search for another pulse */

CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCAINTLVL_HI_gc; /* Re enable CCA interrupt in case it was triggered and then is now disabled */
Expand Down Expand Up @@ -564,8 +578,8 @@ ISR_SHARED isr_SNIFF_ISO15693_CODEC_TIMER_LOADMOD_OVF_VECT(void) {
/* No SOC. The train of pulses was actually garbage. */

/* Restore DAC output to intial value */
DACB.CH0DATA = DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3);
DACB.CH0DATA |= -( (DACB.CH0DATA & 0xFFF) < DemodFloorNoiseLevel); /* Branchfree saturating addition */
SetDacCh0Data(DemodFloorNoiseLevel + (DemodFloorNoiseLevel >> 3));


/* Re enable AC interrupt */
ACA.AC0CTRL = AC_ENABLE_bm | AC_HSMODE_bm | AC_HYSMODE_LARGE_gc | AC_INTMODE_RISING_gc | AC_INTLVL_HI_gc;
Expand Down Expand Up @@ -692,6 +706,34 @@ void SniffISO15693CodecInit(void) {
ReaderSniffInit();
}

/************************************************************
Function used by the Terminal command to display (GET)
the state of the Autothreshold Feature.
************************************************************/
bool SniffISO15693GetAutoThreshold(void){
return bAutoThreshold;
}

/************************************************************
Function used by the Application level to disable the
Autothreshold Feature.
If it is disabled: The threshold will be taken from
GlobalSettings.ActiveSettingPtr->ReaderThreshold
************************************************************/
void SniffISO15693CtrlAutoThreshold(bool enable){
bAutoThreshold = enable;
return;
}

/************************************************************
Function used by the Application level to get the FloorNoise
FloorNoise can be used to define the scanning range for the
Autocalibration.
************************************************************/
uint16_t SniffISO15693GetFloorNoise(void){
return DemodFloorNoiseLevel;
}

void SniffISO15693CodecDeInit(void) {
/* Gracefully shutdown codec */
CODEC_DEMOD_IN_PORT.INT0MASK = 0;
Expand Down
Loading

0 comments on commit 371eaca

Please sign in to comment.