+//=============================================================================
+// An ISO 15693 decoder for tag responses (one subcarrier only).
+// Uses cross correlation to identify each bit and EOF.
+// This function is called 8 times per bit (every 2 subcarrier cycles).
+// Subcarrier frequency fs is 424kHz, 1/fs = 2,36us,
+// i.e. function is called every 4,72us
+// LED handling:
+// LED C -> ON once we have received the SOF and are expecting the rest.
+// LED C -> OFF once we have received EOF or are unsynced
+//
+// Returns: true if we received a EOF
+// false if we are still waiting for some more
+//=============================================================================
+
+#define NOISE_THRESHOLD 160 // don't try to correlate noise
+#define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD)
+
+typedef struct DecodeTag {
+ enum {
+ STATE_TAG_SOF_LOW,
+ STATE_TAG_SOF_RISING_EDGE,
+ STATE_TAG_SOF_HIGH,
+ STATE_TAG_SOF_HIGH_END,
+ STATE_TAG_RECEIVING_DATA,
+ STATE_TAG_EOF,
+ STATE_TAG_EOF_TAIL
+ } state;
+ int bitCount;
+ int posCount;
+ enum {
+ LOGIC0,
+ LOGIC1,
+ SOF_PART1,
+ SOF_PART2
+ } lastBit;
+ uint16_t shiftReg;
+ uint16_t max_len;
+ uint8_t *output;
+ int len;
+ int sum1, sum2;
+ int threshold_sof;
+ int threshold_half;
+ uint16_t previous_amplitude;
+} DecodeTag_t;
+
+
+static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag)
+{
+ switch(DecodeTag->state) {
+ case STATE_TAG_SOF_LOW:
+ // waiting for a rising edge
+ if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) {
+ if (DecodeTag->posCount > 10) {
+ DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude;
+ DecodeTag->threshold_half = 0;
+ DecodeTag->state = STATE_TAG_SOF_RISING_EDGE;
+ } else {
+ DecodeTag->posCount = 0;
+ }
+ } else {
+ DecodeTag->posCount++;
+ DecodeTag->previous_amplitude = amplitude;
+ }
+ break;
+
+ case STATE_TAG_SOF_RISING_EDGE:
+ if (amplitude - DecodeTag->previous_amplitude > DecodeTag->threshold_sof) { // edge still rising
+ if (amplitude - DecodeTag->threshold_sof > DecodeTag->threshold_sof) { // steeper edge, take this as time reference
+ DecodeTag->posCount = 1;
+ } else {
+ DecodeTag->posCount = 2;
+ }
+ DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2;
+ } else {
+ DecodeTag->posCount = 2;
+ DecodeTag->threshold_sof = DecodeTag->threshold_sof/2;
+ }
+ // DecodeTag->posCount = 2;
+ DecodeTag->state = STATE_TAG_SOF_HIGH;
+ break;
+
+ case STATE_TAG_SOF_HIGH:
+ // waiting for 10 times high. Take average over the last 8
+ if (amplitude > DecodeTag->threshold_sof) {
+ DecodeTag->posCount++;
+ if (DecodeTag->posCount > 2) {
+ DecodeTag->threshold_half += amplitude; // keep track of average high value
+ }
+ if (DecodeTag->posCount == 10) {
+ DecodeTag->threshold_half >>= 2; // (4 times 1/2 average)
+ DecodeTag->state = STATE_TAG_SOF_HIGH_END;
+ }
+ } else { // high phase was too short
+ DecodeTag->posCount = 1;
+ DecodeTag->previous_amplitude = amplitude;
+ DecodeTag->state = STATE_TAG_SOF_LOW;
+ }
+ break;
+
+ case STATE_TAG_SOF_HIGH_END:
+ // check for falling edge
+ if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) {
+ DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high)
+ DecodeTag->shiftReg = 0;
+ DecodeTag->bitCount = 0;
+ DecodeTag->len = 0;
+ DecodeTag->sum1 = amplitude;
+ DecodeTag->sum2 = 0;
+ DecodeTag->posCount = 2;
+ DecodeTag->state = STATE_TAG_RECEIVING_DATA;
+ FpgaDisableTracing(); // DEBUGGING
+ Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d",
+ amplitude,
+ DecodeTag->threshold_sof,
+ DecodeTag->threshold_half/4,
+ DecodeTag->previous_amplitude); // DEBUGGING
+ LED_C_ON();
+ } else {
+ DecodeTag->posCount++;
+ if (DecodeTag->posCount > 13) { // high phase too long
+ DecodeTag->posCount = 0;
+ DecodeTag->previous_amplitude = amplitude;
+ DecodeTag->state = STATE_TAG_SOF_LOW;
+ LED_C_OFF();
+ }
+ }
+ break;