2010-02-20 21:24:25 +00:00
//-----------------------------------------------------------------------------
2022-01-06 02:19:46 +01:00
// Copyright (C) Jonathan Westhues, Nov 2006
// Copyright (C) Greg Jones, Jan 2009
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
2010-02-21 00:12:52 +00:00
//
2022-01-06 02:19:46 +01:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
2010-02-21 00:12:52 +00:00
//-----------------------------------------------------------------------------
2010-02-20 21:24:25 +00:00
// Routines to support ISO 15693. This includes both the reader software and
2020-07-02 12:37:07 +02:00
// the `fake tag' modes.
2010-02-20 21:24:25 +00:00
//-----------------------------------------------------------------------------
2020-07-02 12:37:07 +02:00
// The ISO 15693 describes two transmission modes from reader to tag, and four
// transmission modes from tag to reader. As of Oct 2018 this code supports
// both reader modes and the high speed variant with one subcarrier from card to reader.
// As long as the card fully support ISO 15693 this is no problem, since the
// reader chooses both data rates, but some non-standard tags do not.
// For card simulation, the code supports both high and low speed modes with one subcarrier.
2010-10-19 14:25:17 +00:00
//
// VCD (reader) -> VICC (tag)
// 1 out of 256:
2019-03-09 20:34:41 +01:00
// data rate: 1,66 kbit/s (fc/8192)
// used for long range
2010-10-19 14:25:17 +00:00
// 1 out of 4:
2019-03-09 20:34:41 +01:00
// data rate: 26,48 kbit/s (fc/512)
// used for short range, high speed
2019-03-09 08:59:13 +01:00
//
2010-10-19 14:25:17 +00:00
// VICC (tag) -> VCD (reader)
// Modulation:
2019-08-06 13:51:10 +02:00
// ASK / one subcarrier (423,75 kHz)
// FSK / two subcarriers (423,75 kHz && 484,28 kHz)
2010-10-19 14:25:17 +00:00
// Data Rates / Modes:
2019-03-09 20:34:41 +01:00
// low ASK: 6,62 kbit/s
// low FSK: 6.67 kbit/s
// high ASK: 26,48 kbit/s
// high FSK: 26,69 kbit/s
2010-10-19 14:25:17 +00:00
//-----------------------------------------------------------------------------
// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911
// Random Remarks:
// *) UID is always used "transmission order" (LSB), which is reverse to display order
// TODO / BUGS / ISSUES:
2020-07-02 12:37:07 +02:00
// *) signal decoding is unable to detect collisions.
// *) add anti-collision support for inventory-commands
2012-06-20 17:20:21 +00:00
// *) read security status of a block
2022-03-16 15:33:44 +01:00
// *) simulation do not support two subcarrier modes.
2020-07-02 12:37:07 +02:00
// *) remove or refactor code under "deprecated"
2010-10-19 14:25:17 +00:00
// *) document all the functions
2019-08-08 16:57:33 +02:00
# include "iso15693.h"
# include "proxmark3_arm.h"
2010-02-20 22:51:00 +00:00
# include "util.h"
2010-02-21 00:10:28 +00:00
# include "string.h"
2010-10-19 14:25:17 +00:00
# include "iso15693tools.h"
2021-05-03 09:35:38 +02:00
# include "protocols.h"
2012-12-04 23:39:18 +00:00
# include "cmd.h"
2019-08-08 16:57:33 +02:00
# include "appmain.h"
# include "dbprint.h"
# include "fpgaloader.h"
# include "commonutil.h"
# include "ticks.h"
# include "BigBuf.h"
# include "crc16.h"
2020-08-13 12:25:04 +02:00
2020-07-02 12:37:07 +02:00
// Delays in SSP_CLK ticks.
// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag
# define DELAY_READER_TO_ARM 8
# define DELAY_ARM_TO_READER 0
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16
# define DELAY_ARM_TO_TAG 16
# define DELAY_TAG_TO_ARM 32
2020-07-03 21:33:17 +02:00
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when sniffing. All values should be multiples of 16
2020-07-02 12:37:07 +02:00
# define DELAY_TAG_TO_ARM_SNIFF 32
# define DELAY_READER_TO_ARM_SNIFF 32
// times in samples @ 212kHz when acting as reader
2020-08-17 08:52:24 +02:00
# define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us
2020-07-02 12:37:07 +02:00
# define ISO15693_READER_TIMEOUT_WRITE 4700 // 4700/212kHz = 22ms, nominal 20ms
2020-09-07 10:39:15 +02:00
// iceman: This defines below exists in the header file, just here for my easy reading
2020-08-17 08:52:24 +02:00
// Delays in SSP_CLK ticks.
// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag
//#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16
//#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response
//#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command
2010-02-20 21:24:25 +00:00
2010-10-19 14:25:17 +00:00
///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 2 - Air Interface
2020-07-02 12:37:07 +02:00
// This section basically contains transmission and receiving of bits
2010-10-19 14:25:17 +00:00
///////////////////////////////////////////////////////////////////////
2020-07-02 12:37:07 +02:00
// buffers
# define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet
# define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet
2019-03-09 08:59:13 +01:00
// 32 + 2 crc + 1
2020-12-01 21:28:37 +00:00
# define ISO15_MAX_FRAME 35
# define CMD_ID_RESP 5
# define CMD_READ_RESP 13
# define CMD_INV_RESP 12
# define CMD_SYSINFO_RESP 17
2017-09-04 22:48:35 +02:00
2019-04-07 12:07:50 +02:00
//#define Crc(data, len) Crc(CRC_15693, (data), (len))
# define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
# define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
2018-02-01 15:19:47 +01:00
2020-07-02 12:37:07 +02:00
static void BuildIdentifyRequest ( uint8_t * cmd ) ;
2017-09-04 13:56:57 +02:00
2020-08-13 12:25:04 +02:00
// ---------------------------
2020-07-21 10:51:48 +02:00
2019-03-09 08:59:13 +01:00
// Signal Processing
2010-10-19 14:25:17 +00:00
// ---------------------------
// prepare data using "1 out of 4" code for later transmission
2020-07-02 12:37:07 +02:00
// resulting data rate is 26.48 kbit/s (fc/512)
2010-10-19 14:25:17 +00:00
// cmd ... data
2020-08-13 12:25:04 +02:00
// n ... length of data
static uint8_t encode15_lut [ ] = {
0x40 , // 01000000
0x10 , // 00010000
0x04 , // 00000100
0x01 // 00000001
2020-07-21 10:51:48 +02:00
} ;
2022-01-06 15:40:11 +01:00
void CodeIso15693AsReader ( const uint8_t * cmd , int n ) {
2020-07-02 12:37:07 +02:00
2020-07-13 17:56:19 +02:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-07-09 19:41:57 +02:00
// SOF for 1of4
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0x84 ; //10000100
2020-07-09 19:41:57 +02:00
// data
for ( int i = 0 ; i < n ; i + + ) {
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
volatile uint8_t b = ( cmd [ i ] > > 0 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
b = ( cmd [ i ] > > 2 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
b = ( cmd [ i ] > > 4 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
b = ( cmd [ i ] > > 6 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
2020-07-09 19:41:57 +02:00
}
// EOF
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0x20 ; //0010 + 0000 padding
ts - > max + + ;
2010-02-20 21:24:25 +00:00
}
2020-07-02 12:37:07 +02:00
// Encode EOF only
static void CodeIso15693AsReaderEOF ( void ) {
2020-07-13 17:56:19 +02:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
ts - > buf [ + + ts - > max ] = 0x20 ;
ts - > max + + ;
2020-07-02 12:37:07 +02:00
}
// encode data using "1 out of 256" scheme
2019-03-09 08:59:13 +01:00
// data rate is 1,66 kbit/s (fc/8192)
2010-10-19 14:25:17 +00:00
// is designed for more robust communication over longer distances
2022-01-06 15:40:11 +01:00
static void CodeIso15693AsReader256 ( const uint8_t * cmd , int n ) {
2010-02-20 21:24:25 +00:00
2020-07-13 17:56:19 +02:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
// SOF for 1of256
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0x81 ; //10000001
2019-03-09 20:34:41 +01:00
2020-07-09 19:41:57 +02:00
// data
2020-08-13 12:25:04 +02:00
for ( int i = 0 ; i < n ; i + + ) {
2020-07-09 19:41:57 +02:00
for ( int j = 0 ; j < = 255 ; j + + ) {
if ( cmd [ i ] = = j ) {
2020-07-13 17:56:19 +02:00
tosend_stuffbit ( 0 ) ;
tosend_stuffbit ( 1 ) ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-13 17:56:19 +02:00
tosend_stuffbit ( 0 ) ;
tosend_stuffbit ( 0 ) ;
2020-07-09 19:41:57 +02:00
}
}
}
2010-02-20 21:24:25 +00:00
2020-07-09 19:41:57 +02:00
// EOF
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0x20 ; //0010 + 0000 padding
ts - > max + + ;
2010-02-20 21:24:25 +00:00
}
2020-08-13 12:25:04 +02:00
static const uint8_t encode_4bits [ 16 ] = {
2020-08-03 17:42:05 +02:00
// 0 1 2 3
2020-07-13 12:28:01 +02:00
0xaa , 0x6a , 0x9a , 0x5a ,
2020-08-03 17:42:05 +02:00
// 4 5 6 7
2020-07-13 12:28:01 +02:00
0xa6 , 0x66 , 0x96 , 0x56 ,
2020-08-03 17:42:05 +02:00
// 8 9 A B
2020-07-13 12:28:01 +02:00
0xa9 , 0x69 , 0x99 , 0x59 ,
2020-08-03 17:42:05 +02:00
// C D E F
2020-07-13 12:28:01 +02:00
0xa5 , 0x65 , 0x95 , 0x55
} ;
2020-07-02 12:37:07 +02:00
2022-01-06 15:40:11 +01:00
void CodeIso15693AsTag ( const uint8_t * cmd , size_t len ) {
2020-07-09 19:41:57 +02:00
/*
* SOF comprises 3 parts ;
* * An unmodulated time of 56.64 us
* * 24 pulses of 423.75 kHz ( fc / 32 )
* * A logic 1 , which starts with an unmodulated time of 18.88 us
* followed by 8 pulses of 423.75 kHz ( fc / 32 )
*
* EOF comprises 3 parts :
* - A logic 0 ( which starts with 8 pulses of fc / 32 followed by an unmodulated
* time of 18.88 us .
* - 24 pulses of fc / 32
* - An unmodulated time of 56.64 us
*
* A logic 0 starts with 8 pulses of fc / 32
* followed by an unmodulated time of 256 / fc ( ~ 18 , 88u s ) .
*
* A logic 0 starts with unmodulated time of 256 / fc ( ~ 18 , 88u s ) followed by
* 8 pulses of fc / 32 ( also 18.88 us )
*
* A bit here becomes 8 pulses of fc / 32. Therefore :
* The SOF can be written as 00011101 = 0x1D
* The EOF can be written as 10111000 = 0xb8
* A logic 1 is 01
* A logic 0 is 10
*
* */
2020-07-13 17:56:19 +02:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-07-09 19:41:57 +02:00
// SOF
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0x1D ; // 00011101
2020-07-09 19:41:57 +02:00
// data
2022-03-21 20:22:27 +02:00
for ( size_t i = 0 ; i < len ; i + + ) {
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i ] & 0xF ] ;
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i ] > > 4 ] ;
2020-07-09 19:41:57 +02:00
}
// EOF
2020-07-13 17:56:19 +02:00
ts - > buf [ + + ts - > max ] = 0xB8 ; // 10111000
ts - > max + + ;
2010-02-20 21:24:25 +00:00
}
2020-07-02 12:37:07 +02:00
// Transmit the command (to the tag) that was placed in cmd[].
2020-07-03 21:33:17 +02:00
void TransmitTo15693Tag ( const uint8_t * cmd , int len , uint32_t * start_time ) {
2019-03-09 08:59:13 +01:00
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD ) ;
if ( * start_time < DELAY_ARM_TO_TAG ) {
* start_time = DELAY_ARM_TO_TAG ;
}
* start_time = ( * start_time - DELAY_ARM_TO_TAG ) & 0xfffffff0 ;
if ( GetCountSspClk ( ) > * start_time ) { // we may miss the intended time
* start_time = ( GetCountSspClk ( ) + 16 ) & 0xfffffff0 ; // next possible time
}
2020-07-19 20:45:47 +02:00
// wait
while ( GetCountSspClk ( ) < * start_time ) ;
2020-07-09 19:41:57 +02:00
LED_B_ON ( ) ;
for ( int c = 0 ; c < len ; c + + ) {
2020-07-13 12:28:01 +02:00
volatile uint8_t data = cmd [ c ] ;
2020-07-19 20:45:47 +02:00
2020-07-13 12:28:01 +02:00
for ( uint8_t i = 0 ; i < 8 ; i + + ) {
2020-07-09 19:41:57 +02:00
uint16_t send_word = ( data & 0x80 ) ? 0xffff : 0x0000 ;
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
AT91C_BASE_SSC - > SSC_THR = send_word ;
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
AT91C_BASE_SSC - > SSC_THR = send_word ;
data < < = 1 ;
}
WDT_HIT ( ) ;
}
LED_B_OFF ( ) ;
* start_time = * start_time + DELAY_ARM_TO_TAG ;
2020-10-13 22:43:28 +02:00
FpgaDisableTracing ( ) ;
2017-09-04 13:56:57 +02:00
}
2020-07-02 12:37:07 +02:00
//-----------------------------------------------------------------------------
2020-07-09 19:41:57 +02:00
// Transmit the tag response (to the reader) that was placed in cmd[].
2020-07-02 12:37:07 +02:00
//-----------------------------------------------------------------------------
2020-07-03 21:33:17 +02:00
void TransmitTo15693Reader ( const uint8_t * cmd , size_t len , uint32_t * start_time , uint32_t slot_time , bool slow ) {
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
// don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk()
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K ) ;
uint32_t modulation_start_time = * start_time - DELAY_ARM_TO_READER + 3 * 8 ; // no need to transfer the unmodulated start of SOF
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
while ( GetCountSspClk ( ) > ( modulation_start_time & 0xfffffff8 ) + 3 ) { // we will miss the intended time
if ( slot_time ) {
modulation_start_time + = slot_time ; // use next available slot
} else {
modulation_start_time = ( modulation_start_time & 0xfffffff8 ) + 8 ; // next possible time
}
}
2020-07-19 20:45:47 +02:00
// wait
while ( GetCountSspClk ( ) < ( modulation_start_time & 0xfffffff8 ) ) ;
2020-07-09 19:41:57 +02:00
uint8_t shift_delay = modulation_start_time & 0x00000007 ;
* start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8 ;
LED_C_ON ( ) ;
uint8_t bits_to_shift = 0x00 ;
2020-08-13 12:25:04 +02:00
uint8_t bits_to_send = 0x00 ;
2020-07-09 19:41:57 +02:00
for ( size_t c = 0 ; c < len ; c + + ) {
2020-07-15 15:16:35 +02:00
for ( int i = ( c = = 0 ? 4 : 7 ) ; i > = 0 ; i - - ) {
2020-07-19 20:45:47 +02:00
2020-07-09 19:41:57 +02:00
uint8_t cmd_bits = ( ( cmd [ c ] > > i ) & 0x01 ) ? 0xff : 0x00 ;
2020-07-19 20:45:47 +02:00
2020-08-13 12:25:04 +02:00
for ( int j = 0 ; j < ( slow ? 4 : 1 ) ; ) {
2020-07-09 19:41:57 +02:00
if ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXRDY ) {
bits_to_send = bits_to_shift < < ( 8 - shift_delay ) | cmd_bits > > shift_delay ;
AT91C_BASE_SSC - > SSC_THR = bits_to_send ;
bits_to_shift = cmd_bits ;
j + + ;
}
}
}
WDT_HIT ( ) ;
}
2020-08-03 17:42:05 +02:00
2020-07-09 19:41:57 +02:00
// send the remaining bits, padded with 0:
bits_to_send = bits_to_shift < < ( 8 - shift_delay ) ;
2020-08-03 17:42:05 +02:00
if ( bits_to_send ) {
2020-08-13 12:25:04 +02:00
for ( ; ; ) {
2020-08-03 17:42:05 +02:00
if ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXRDY ) {
AT91C_BASE_SSC - > SSC_THR = bits_to_send ;
break ;
}
2020-07-09 19:41:57 +02:00
}
}
LED_C_OFF ( ) ;
2010-02-20 21:24:25 +00:00
}
2020-07-02 12:37:07 +02:00
//=============================================================================
// 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 80 // don't try to correlate noise
# define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD)
2020-07-21 10:51:48 +02:00
typedef struct {
2020-07-09 19:41:57 +02:00
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 ;
2022-03-23 17:37:40 +01:00
uint16_t len ;
2020-07-09 19:41:57 +02:00
int sum1 ;
int sum2 ;
int threshold_sof ;
int threshold_half ;
2022-03-23 17:37:40 +01:00
uint16_t previous_amplitude ;
uint8_t * output ;
2020-07-02 12:37:07 +02:00
} DecodeTag_t ;
2010-10-19 14:25:17 +00:00
2020-07-02 12:37:07 +02:00
//-----------------------------------------------------------------------------
// DEMODULATE tag answer
//-----------------------------------------------------------------------------
2022-03-16 15:21:28 +01:00
static RAMFUNC int Handle15693SamplesFromTag ( uint16_t amplitude , DecodeTag_t * tag , bool recv_speed ) {
2020-07-21 10:51:48 +02:00
switch ( tag - > state ) {
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_SOF_LOW : {
2020-07-09 19:41:57 +02:00
// waiting for a rising edge
2020-07-21 10:51:48 +02:00
if ( amplitude > NOISE_THRESHOLD + tag - > previous_amplitude ) {
if ( tag - > posCount > 10 ) {
tag - > threshold_sof = amplitude - tag - > previous_amplitude ; // to be divided by 2
tag - > threshold_half = 0 ;
tag - > state = STATE_TAG_SOF_RISING_EDGE ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
2020-07-09 19:41:57 +02:00
}
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount + + ;
tag - > previous_amplitude = amplitude ;
2020-07-09 19:41:57 +02:00
}
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_SOF_RISING_EDGE : {
2020-07-21 10:51:48 +02:00
if ( amplitude > tag - > threshold_sof + tag - > previous_amplitude ) { // edge still rising
if ( amplitude > tag - > threshold_sof + tag - > threshold_sof ) { // steeper edge, take this as time reference
tag - > posCount = 1 ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 2 ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
tag - > threshold_sof = ( amplitude - tag - > previous_amplitude ) / 2 ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 2 ;
tag - > threshold_sof = tag - > threshold_sof / 2 ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
tag - > state = STATE_TAG_SOF_HIGH ;
2020-07-09 19:41:57 +02:00
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_SOF_HIGH : {
2020-07-09 19:41:57 +02:00
// waiting for 10 times high. Take average over the last 8
2020-07-21 10:51:48 +02:00
if ( amplitude > tag - > threshold_sof ) {
tag - > posCount + + ;
if ( tag - > posCount > 2 ) {
tag - > threshold_half + = amplitude ; // keep track of average high value
2020-07-09 19:41:57 +02:00
}
2022-03-23 18:22:03 +01:00
if ( tag - > posCount = = ( recv_speed ? 10 : 40 ) ) {
2020-07-21 10:51:48 +02:00
tag - > threshold_half > > = 2 ; // (4 times 1/2 average)
tag - > state = STATE_TAG_SOF_HIGH_END ;
2020-07-09 19:41:57 +02:00
}
} else { // high phase was too short
2020-07-21 10:51:48 +02:00
tag - > posCount = 1 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
}
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_SOF_HIGH_END : {
2020-07-09 19:41:57 +02:00
// check for falling edge
2022-03-23 18:22:03 +01:00
if ( tag - > posCount = = ( recv_speed ? 13 : 52 ) & & amplitude < tag - > threshold_sof ) {
2020-07-21 10:51:48 +02:00
tag - > lastBit = SOF_PART1 ; // detected 1st part of SOF (12 samples low and 12 samples high)
tag - > shiftReg = 0 ;
tag - > bitCount = 0 ;
tag - > len = 0 ;
tag - > sum1 = amplitude ;
tag - > sum2 = 0 ;
tag - > posCount = 2 ;
tag - > state = STATE_TAG_RECEIVING_DATA ;
2020-07-09 19:41:57 +02:00
LED_C_ON ( ) ;
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount + + ;
2022-03-23 18:22:03 +01:00
if ( tag - > posCount > ( recv_speed ? 13 : 52 ) ) { // high phase too long
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
}
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_RECEIVING_DATA : {
2020-07-21 10:51:48 +02:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 10:51:48 +02:00
tag - > sum1 + = amplitude ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > sum2 + = amplitude ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 10:51:48 +02:00
if ( tag - > sum1 > tag - > threshold_half & & tag - > sum2 > tag - > threshold_half ) { // modulation in both halves
if ( tag - > lastBit = = LOGIC0 ) { // this was already part of EOF
tag - > state = STATE_TAG_EOF ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
2020-07-21 10:51:48 +02:00
} else if ( tag - > sum1 < tag - > threshold_half & & tag - > sum2 > tag - > threshold_half ) { // modulation in second half
2020-07-09 19:41:57 +02:00
// logic 1
2020-07-21 10:51:48 +02:00
if ( tag - > lastBit = = SOF_PART1 ) { // still part of SOF
tag - > lastBit = SOF_PART2 ; // SOF completed
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > lastBit = LOGIC1 ;
tag - > shiftReg > > = 1 ;
tag - > shiftReg | = 0x80 ;
tag - > bitCount + + ;
if ( tag - > bitCount = = 8 ) {
2021-04-16 22:14:14 +02:00
tag - > output [ tag - > len ] = tag - > shiftReg & 0xFF ;
2020-07-21 10:51:48 +02:00
tag - > len + + ;
2020-08-19 16:26:26 +02:00
if ( tag - > len > tag - > max_len ) {
2020-07-09 19:41:57 +02:00
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
2020-07-21 10:51:48 +02:00
tag - > bitCount = 0 ;
tag - > shiftReg = 0 ;
2020-07-09 19:41:57 +02:00
}
}
2020-07-21 10:51:48 +02:00
} else if ( tag - > sum1 > tag - > threshold_half & & tag - > sum2 < tag - > threshold_half ) { // modulation in first half
2020-07-09 19:41:57 +02:00
// logic 0
2020-07-21 10:51:48 +02:00
if ( tag - > lastBit = = SOF_PART1 ) { // incomplete SOF
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
} else {
2020-07-21 10:51:48 +02:00
tag - > lastBit = LOGIC0 ;
tag - > shiftReg > > = 1 ;
tag - > bitCount + + ;
if ( tag - > bitCount = = 8 ) {
2021-04-16 22:14:14 +02:00
tag - > output [ tag - > len ] = ( tag - > shiftReg & 0xFF ) ;
2020-07-21 10:51:48 +02:00
tag - > len + + ;
2020-08-19 16:26:26 +02:00
if ( tag - > len > tag - > max_len ) {
2020-07-09 19:41:57 +02:00
// buffer overflow, give up
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
2020-07-21 10:51:48 +02:00
tag - > bitCount = 0 ;
tag - > shiftReg = 0 ;
2020-07-09 19:41:57 +02:00
}
}
} else { // no modulation
2020-07-21 10:51:48 +02:00
if ( tag - > lastBit = = SOF_PART2 ) { // only SOF (this is OK for iClass)
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
return true ;
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
}
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
tag - > posCount + + ;
2020-07-09 19:41:57 +02:00
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_EOF : {
2020-07-21 10:51:48 +02:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 10:51:48 +02:00
tag - > sum1 + = amplitude ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > sum2 + = amplitude ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 10:51:48 +02:00
if ( tag - > sum1 > tag - > threshold_half & & tag - > sum2 < tag - > threshold_half ) { // modulation in first half
tag - > posCount = 0 ;
tag - > state = STATE_TAG_EOF_TAIL ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
}
2020-07-21 10:51:48 +02:00
tag - > posCount + + ;
2020-07-09 19:41:57 +02:00
break ;
2020-07-19 20:45:47 +02:00
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
case STATE_TAG_EOF_TAIL : {
2020-07-21 10:51:48 +02:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 10:51:48 +02:00
tag - > sum1 + = amplitude ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
tag - > sum2 + = amplitude ;
2020-07-09 19:41:57 +02:00
}
2020-08-11 21:40:22 +02:00
2022-03-23 18:22:03 +01:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 10:51:48 +02:00
if ( tag - > sum1 < tag - > threshold_half & & tag - > sum2 < tag - > threshold_half ) { // no modulation in both halves
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
return true ;
} else {
2020-07-21 10:51:48 +02:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-09 19:41:57 +02:00
LED_C_OFF ( ) ;
}
}
2020-07-21 10:51:48 +02:00
tag - > posCount + + ;
2020-07-09 19:41:57 +02:00
break ;
2020-07-19 20:45:47 +02:00
}
2020-07-09 19:41:57 +02:00
}
return false ;
2020-07-02 12:37:07 +02:00
}
2010-02-20 21:24:25 +00:00
2020-07-21 10:51:48 +02:00
static void DecodeTagReset ( DecodeTag_t * tag ) {
tag - > posCount = 0 ;
tag - > state = STATE_TAG_SOF_LOW ;
tag - > previous_amplitude = MAX_PREVIOUS_AMPLITUDE ;
2020-07-02 12:37:07 +02:00
}
2017-09-04 13:56:57 +02:00
2020-07-21 10:51:48 +02:00
static void DecodeTagInit ( DecodeTag_t * tag , uint8_t * data , uint16_t max_len ) {
tag - > output = data ;
tag - > max_len = max_len ;
DecodeTagReset ( tag ) ;
2020-07-02 12:37:07 +02:00
}
2019-03-09 08:59:13 +01:00
2022-03-16 13:58:04 +01:00
//=============================================================================
// An ISO 15693 decoder for tag responses in FSK (two subcarriers) mode.
// Subcarriers frequencies are 424kHz and 484kHz (fc/32 and fc/28),
// 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 DEBUG 1
# define FREQ_IS_484(f) ((f & 1) == 1) //(f >= 26 && f <= 30)
# define FREQ_IS_424(f) ((f & 2) == 2) //(f >= 30 && f <= 34)
# define FREQ_IS_0(f) ((f & 3) == 0) // (f <= 24 || f >= 36)
2022-03-16 17:36:37 +01:00
# define SEOF_COUNT(c, s) ((s) ? (c >= 11 && c <= 13) : (c >= 45 && c <= 51))
# define LOGIC_COUNT(c, s) ((s) ? (c >= 3 && c <= 6) : (c >= 14 && c <= 20))
2022-03-16 13:58:04 +01:00
# define MAX_COUNT(c, s) ((s) ? (c >= 13) : (c >= 52))
2020-07-02 12:37:07 +02:00
2022-03-16 13:58:04 +01:00
typedef struct DecodeTagFSK {
2022-03-23 18:22:03 +01:00
enum {
2022-03-16 13:58:04 +01:00
STATE_FSK_ERROR ,
2022-03-23 18:22:03 +01:00
STATE_FSK_BEFORE_SOF ,
STATE_FSK_SOF_484 ,
STATE_FSK_SOF_424 ,
STATE_FSK_SOF_END_484 ,
2022-03-16 13:58:04 +01:00
STATE_FSK_SOF_END_424 ,
2022-03-23 18:22:03 +01:00
STATE_FSK_RECEIVING_DATA_484 ,
STATE_FSK_RECEIVING_DATA_424 ,
STATE_FSK_EOF
} state ;
enum {
LOGIC0_PART1 ,
LOGIC1_PART1 ,
LOGIC0_PART2 ,
LOGIC1_PART2 ,
2022-03-16 13:58:04 +01:00
SOF
2022-03-23 18:22:03 +01:00
} lastBit ;
uint8_t count ;
uint8_t bitCount ;
uint8_t shiftReg ;
uint16_t len ;
uint16_t max_len ;
uint8_t * output ;
2022-03-16 13:58:04 +01:00
} DecodeTagFSK_t ;
2020-07-02 12:37:07 +02:00
2022-03-16 13:58:04 +01:00
static void DecodeTagFSKReset ( DecodeTagFSK_t * DecodeTag ) {
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
DecodeTag - > bitCount = 0 ;
DecodeTag - > len = 0 ;
DecodeTag - > shiftReg = 0 ;
2022-03-16 13:58:04 +01:00
}
2020-08-14 14:56:20 +02:00
2022-03-16 13:58:04 +01:00
static void DecodeTagFSKInit ( DecodeTagFSK_t * DecodeTag , uint8_t * data , uint16_t max_len ) {
2022-03-23 18:22:03 +01:00
DecodeTag - > output = data ;
DecodeTag - > max_len = max_len ;
DecodeTagFSKReset ( DecodeTag ) ;
2022-03-16 13:58:04 +01:00
}
2020-08-14 14:56:20 +02:00
2022-03-16 13:58:04 +01:00
// Performances of this function are crutial for stability
// as it is called in real time for every samples
2022-03-23 18:22:03 +01:00
static int RAMFUNC Handle15693FSKSamplesFromTag ( uint8_t freq , DecodeTagFSK_t * DecodeTag , bool recv_speed ) {
switch ( DecodeTag - > state ) {
case STATE_FSK_BEFORE_SOF :
if ( FREQ_IS_484 ( freq ) ) {
// possible SOF starting
DecodeTag - > state = STATE_FSK_SOF_484 ;
DecodeTag - > lastBit = LOGIC0_PART1 ;
DecodeTag - > count = 1 ;
2020-07-09 19:41:57 +02:00
}
2022-03-23 18:22:03 +01:00
break ;
case STATE_FSK_SOF_484 :
//DbpString("STATE_FSK_SOF_484");
if ( FREQ_IS_424 ( freq ) & & SEOF_COUNT ( DecodeTag - > count , recv_speed ) ) {
// SOF part1 continue at 424
DecodeTag - > state = STATE_FSK_SOF_424 ;
DecodeTag - > count = 1 ;
} else if ( FREQ_IS_484 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) { // still in SOF at 484
DecodeTag - > count + + ;
} else { // SOF failed, roll back
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2022-03-16 13:58:04 +01:00
}
2022-03-23 18:22:03 +01:00
break ;
2020-08-14 14:56:20 +02:00
2022-03-23 18:22:03 +01:00
case STATE_FSK_SOF_424 :
2022-03-16 13:58:04 +01:00
//DbpString("STATE_FSK_SOF_424");
2022-03-23 18:22:03 +01:00
if ( FREQ_IS_484 ( freq ) & & SEOF_COUNT ( DecodeTag - > count , recv_speed ) ) {
// SOF part 1 finished
DecodeTag - > state = STATE_FSK_SOF_END_484 ;
DecodeTag - > count = 1 ;
} else if ( FREQ_IS_424 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still in SOF at 424
DecodeTag - > count + + ;
else { // SOF failed, roll back
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " SOF_424 failed: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2022-03-16 13:58:04 +01:00
}
2022-03-23 18:22:03 +01:00
break ;
2020-08-14 14:56:20 +02:00
2022-03-23 18:22:03 +01:00
case STATE_FSK_SOF_END_484 :
if ( FREQ_IS_424 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
2022-03-16 13:58:04 +01:00
DecodeTag - > state = STATE_FSK_SOF_END_424 ;
2022-03-23 18:22:03 +01:00
DecodeTag - > count = 1 ;
} else if ( FREQ_IS_484 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still in SOF_END_484
DecodeTag - > count + + ;
else { // SOF failed, roll back
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " SOF_END_484 failed: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2020-07-09 19:41:57 +02:00
}
2022-03-23 18:22:03 +01:00
break ;
2022-03-16 13:58:04 +01:00
case STATE_FSK_SOF_END_424 :
2022-03-23 18:22:03 +01:00
if ( FREQ_IS_484 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
// SOF finished at 484
DecodeTag - > count = 1 ;
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = SOF ;
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_484 ;
2022-03-16 13:58:04 +01:00
LED_C_ON ( ) ;
2022-03-23 18:22:03 +01:00
} else if ( FREQ_IS_424 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count - 2 , recv_speed ) ) {
// SOF finished at 424 (wait count+2 to be sure that next freq is 424)
DecodeTag - > count = 2 ;
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = SOF ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_424 ;
LED_C_ON ( ) ;
2022-03-23 18:22:03 +01:00
} else if ( FREQ_IS_424 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still in SOF_END_424
2022-03-16 13:58:04 +01:00
DecodeTag - > count + + ;
2022-03-23 18:22:03 +01:00
else { // SOF failed, roll back
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " SOF_END_424 failed: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2020-07-09 19:41:57 +02:00
}
break ;
2020-07-02 12:37:07 +02:00
2022-03-23 18:22:03 +01:00
case STATE_FSK_RECEIVING_DATA_424 :
if ( FREQ_IS_484 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
if ( DecodeTag - > lastBit = = LOGIC1_PART1 ) {
// logic 1 finished, goto 484
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC1_PART2 ;
2020-07-02 12:37:07 +02:00
2022-03-16 13:58:04 +01:00
DecodeTag - > shiftReg > > = 1 ;
DecodeTag - > shiftReg | = 0x80 ;
DecodeTag - > bitCount + + ;
if ( DecodeTag - > bitCount = = 8 ) {
DecodeTag - > output [ DecodeTag - > len + + ] = DecodeTag - > shiftReg ;
if ( DecodeTag - > len > DecodeTag - > max_len ) {
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
DecodeTag - > bitCount = 0 ;
DecodeTag - > shiftReg = 0 ;
}
2022-03-23 18:22:03 +01:00
} else {
// end of LOGIC0_PART1
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC0_PART1 ;
}
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_484 ;
2022-03-23 18:22:03 +01:00
} else if ( FREQ_IS_424 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count - 2 , recv_speed ) & &
DecodeTag - > lastBit = = LOGIC1_PART1 ) {
// logic 1 finished, stay in 484
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC1_PART2 ;
2020-07-02 12:37:07 +02:00
2022-03-16 13:58:04 +01:00
DecodeTag - > shiftReg > > = 1 ;
DecodeTag - > shiftReg | = 0x80 ;
DecodeTag - > bitCount + + ;
if ( DecodeTag - > bitCount = = 8 ) {
DecodeTag - > output [ DecodeTag - > len + + ] = DecodeTag - > shiftReg ;
if ( DecodeTag - > len > DecodeTag - > max_len ) {
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
DecodeTag - > bitCount = 0 ;
DecodeTag - > shiftReg = 0 ;
}
2022-03-23 18:22:03 +01:00
DecodeTag - > count = 2 ;
} else if ( FREQ_IS_424 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still at 424
DecodeTag - > count + + ;
else if ( FREQ_IS_484 ( freq ) & & DecodeTag - > lastBit = = LOGIC0_PART2 & &
SEOF_COUNT ( DecodeTag - > count , recv_speed ) ) {
// EOF has started
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " RECEIVING_DATA_424->EOF: freq=%d, count=%d, recv_speed=%d, lastbit=%d, state=%d " , freq , DecodeTag - > count , recv_speed , DecodeTag - > lastBit , DecodeTag - > state ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_EOF ;
LED_C_OFF ( ) ;
} else { // error
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " RECEIVING_DATA_424 error: freq=%d, count=%d, recv_speed=%d, lastbit=%d, state=%d " , freq , DecodeTag - > count , recv_speed , DecodeTag - > lastBit , DecodeTag - > state ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_ERROR ;
LED_C_OFF ( ) ;
return true ;
}
break ;
case STATE_FSK_RECEIVING_DATA_484 :
if ( FREQ_IS_424 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
if ( DecodeTag - > lastBit = = LOGIC0_PART1 ) {
// logic 0 finished, goto 424
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC0_PART2 ;
DecodeTag - > shiftReg > > = 1 ;
DecodeTag - > bitCount + + ;
if ( DecodeTag - > bitCount = = 8 ) {
DecodeTag - > output [ DecodeTag - > len + + ] = DecodeTag - > shiftReg ;
if ( DecodeTag - > len > DecodeTag - > max_len ) {
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
DecodeTag - > bitCount = 0 ;
DecodeTag - > shiftReg = 0 ;
}
2022-03-23 18:22:03 +01:00
} else {
// end of LOGIC1_PART1
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC1_PART1 ;
}
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_424 ;
2022-03-23 18:22:03 +01:00
} else if ( FREQ_IS_484 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count - 2 , recv_speed ) & &
DecodeTag - > lastBit = = LOGIC0_PART1 ) {
// logic 0 finished, stay in 424
2022-03-16 13:58:04 +01:00
DecodeTag - > lastBit = LOGIC0_PART2 ;
DecodeTag - > shiftReg > > = 1 ;
DecodeTag - > bitCount + + ;
if ( DecodeTag - > bitCount = = 8 ) {
DecodeTag - > output [ DecodeTag - > len + + ] = DecodeTag - > shiftReg ;
if ( DecodeTag - > len > DecodeTag - > max_len ) {
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
DecodeTag - > bitCount = 0 ;
DecodeTag - > shiftReg = 0 ;
}
2022-03-23 18:22:03 +01:00
DecodeTag - > count = 2 ;
} else if ( FREQ_IS_484 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still at 484
DecodeTag - > count + + ;
else { // error
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " RECEIVING_DATA_484 error: freq=%d, count=%d, recv_speed=%d, lastbit=%d, state=%d " , freq , DecodeTag - > count , recv_speed , DecodeTag - > lastBit , DecodeTag - > state ) ;
# endif
2022-03-23 18:22:03 +01:00
LED_C_OFF ( ) ;
DecodeTag - > state = STATE_FSK_ERROR ;
return true ;
}
break ;
case STATE_FSK_EOF :
if ( FREQ_IS_484 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) { // still at 484
DecodeTag - > count + + ;
if ( SEOF_COUNT ( DecodeTag - > count , recv_speed ) )
return true ; // end of the transmission
} else { // error
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " EOF error: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-23 18:22:03 +01:00
DecodeTag - > state = STATE_FSK_ERROR ;
return true ;
}
break ;
case STATE_FSK_ERROR :
LED_C_OFF ( ) ;
2022-03-16 13:58:04 +01:00
# ifdef DEBUG
if ( DEBUG )
2022-03-23 18:22:03 +01:00
Dbprintf ( " FSK error: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
2022-03-16 13:58:04 +01:00
# endif
2022-03-23 18:22:03 +01:00
return true ; // error
break ;
}
return false ;
2022-03-16 13:58:04 +01:00
}
/*
* Receive and decode the tag response , also log to tracebuffer
*/
2022-03-23 17:37:40 +01:00
int GetIso15693AnswerFromTag ( uint8_t * response , uint16_t max_len , uint16_t timeout , uint32_t * eof_time , bool fsk , bool recv_speed , uint16_t * resp_len ) {
2022-03-16 13:58:04 +01:00
2022-03-23 17:37:40 +01:00
int samples = 0 , ret = PM3_SUCCESS ;
if ( resp_len ) {
* resp_len = 0 ;
}
2022-03-16 13:58:04 +01:00
// the Decoder data structure
DecodeTag_t dtm = { 0 } ;
DecodeTag_t * dt = & dtm ;
2022-03-16 15:45:18 +01:00
DecodeTagFSK_t dtfm = { 0 } ;
DecodeTagFSK_t * dtf = & dtfm ;
2022-03-23 17:37:40 +01:00
if ( fsk )
2022-03-16 15:45:18 +01:00
DecodeTagFSKInit ( dtf , response , max_len ) ;
2022-03-23 17:37:40 +01:00
else
DecodeTagInit ( dt , response , max_len ) ;
2022-03-16 13:58:04 +01:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) ;
// And put the FPGA in the appropriate mode
2022-03-16 15:45:18 +01:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_2SUBCARRIERS_424_484_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ) ;
2022-03-16 13:58:04 +01:00
// Setup and start DMA.
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
// Setup and start DMA.
if ( FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
2022-03-23 17:37:40 +01:00
return PM3_EINIT ;
2022-03-16 13:58:04 +01:00
}
uint32_t dma_start_time = 0 ;
uint16_t * upTo = dma - > buf ;
for ( ; ; ) {
volatile uint16_t behindBy = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
if ( behindBy = = 0 )
continue ;
samples + + ;
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
volatile uint16_t tagdata = * upTo + + ;
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) { // we have read all of the DMA buffer content.
upTo = dma - > buf ; // start reading the circular buffer from the beginning
// DMA Counter Register had reached 0, already rotated.
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_ENDRX ) ) {
// primary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RNCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
break ;
}
}
}
2022-03-23 17:37:40 +01:00
if ( fsk ) {
if ( Handle15693FSKSamplesFromTag ( tagdata > > 14 , dtf , recv_speed ) ) {
2022-03-16 13:58:04 +01:00
2022-03-16 15:45:18 +01:00
* eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM ; // end of EOF
2022-03-16 13:58:04 +01:00
2022-03-23 17:37:40 +01:00
if ( dtf - > lastBit = = SOF ) {
2022-03-16 15:45:18 +01:00
* eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2022-03-23 17:37:40 +01:00
if ( dtf - > len > dtf - > max_len ) {
ret = PM3_EOVFLOW ;
Dbprintf ( " overflow (%d > %d " , dtf - > len , dtf - > max_len ) ;
2022-03-16 15:45:18 +01:00
}
break ;
2022-03-16 13:58:04 +01:00
}
2022-03-16 15:45:18 +01:00
// timeout
2022-03-23 17:37:40 +01:00
if ( samples > timeout & & dtf - > state < STATE_FSK_RECEIVING_DATA_484 ) {
ret = PM3_ETIMEOUT ;
2022-03-16 15:45:18 +01:00
break ;
2022-03-16 13:58:04 +01:00
}
2022-03-23 17:37:40 +01:00
} else {
if ( Handle15693SamplesFromTag ( tagdata & 0x3FFF , dt , recv_speed ) ) {
2022-03-16 13:58:04 +01:00
2022-03-16 15:45:18 +01:00
* eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM ; // end of EOF
2022-03-23 17:37:40 +01:00
if ( dt - > lastBit = = SOF_PART2 ) {
2022-03-16 15:45:18 +01:00
* eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2022-03-23 17:37:40 +01:00
if ( dt - > len > dt - > max_len ) {
ret = PM3_EOVFLOW ;
Dbprintf ( " overflow (%d > %d " , dt - > len , dt - > max_len ) ;
2022-03-16 15:45:18 +01:00
}
break ;
}
2022-03-16 13:58:04 +01:00
2022-03-16 15:45:18 +01:00
// timeout
2022-03-23 17:37:40 +01:00
if ( samples > timeout & & dt - > state < STATE_TAG_RECEIVING_DATA ) {
ret = PM3_ETIMEOUT ;
2022-03-16 15:45:18 +01:00
break ;
}
}
2022-03-16 13:58:04 +01:00
}
FpgaDisableSscDma ( ) ;
FpgaDisableTracing ( ) ;
2022-03-16 15:45:18 +01:00
uint32_t sof_time = * eof_time - ( 32 * 16 ) ; // time for SOF transfer
2022-03-23 17:37:40 +01:00
if ( fsk ) {
2022-03-16 15:45:18 +01:00
sof_time - = ( dtf - > len * 8 * 8 * 16 ) // time for byte transfers
+ ( dtf - > lastBit ! = SOF ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
if ( g_dbglevel > = DBG_EXTENDED ) {
Dbprintf ( " samples = %d, ret = %d, FSK Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, count = %d, maxlen = %u " ,
samples ,
ret ,
dtf - > state ,
dtf - > lastBit ,
dtf - > len ,
dtf - > bitCount ,
dtf - > count ,
dtf - > max_len
2022-03-23 18:22:03 +01:00
) ;
2022-03-16 15:45:18 +01:00
Dbprintf ( " timing: sof_time = %d, eof_time = %d " , ( sof_time * 4 ) , ( * eof_time * 4 ) ) ;
}
2022-03-23 17:37:40 +01:00
} else {
sof_time - = ( dt - > len * 8 * 8 * 16 ) // time for byte transfers
+ ( dt - > lastBit ! = SOF_PART2 ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
if ( g_dbglevel > = DBG_EXTENDED ) {
Dbprintf ( " samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d, maxlen = %u " ,
samples ,
ret ,
dt - > state ,
dt - > lastBit ,
dt - > len ,
dt - > bitCount ,
dt - > posCount ,
dt - > max_len
2022-03-23 18:22:03 +01:00
) ;
2022-03-23 17:37:40 +01:00
Dbprintf ( " timing: sof_time = %d, eof_time = %d " , ( sof_time * 4 ) , ( * eof_time * 4 ) ) ;
}
2020-07-09 19:41:57 +02:00
}
2020-07-02 12:37:07 +02:00
2022-03-23 17:37:40 +01:00
if ( ret ! = PM3_SUCCESS ) {
* resp_len = 0 ;
2020-07-09 19:41:57 +02:00
return ret ;
}
2020-08-19 16:22:56 +02:00
2022-03-23 17:37:40 +01:00
if ( fsk ) {
LogTrace_ISO15693 ( dtf - > output , dtf - > len , ( sof_time * 4 ) , ( * eof_time * 4 ) , NULL , false ) ;
* resp_len = dtf - > len ;
} else {
2022-03-16 15:45:18 +01:00
LogTrace_ISO15693 ( dt - > output , dt - > len , ( sof_time * 4 ) , ( * eof_time * 4 ) , NULL , false ) ;
2022-03-23 17:37:40 +01:00
* resp_len = dt - > len ;
2022-03-16 15:45:18 +01:00
}
2022-03-23 17:37:40 +01:00
return PM3_SUCCESS ;
2020-07-02 12:37:07 +02:00
}
2017-08-21 17:17:43 +02:00
2010-02-20 21:24:25 +00:00
2020-07-02 12:37:07 +02:00
//=============================================================================
// An ISO15693 decoder for reader commands.
//
// This function is called 4 times per bit (every 2 subcarrier cycles).
// Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us
// LED handling:
// LED B -> ON once we have received the SOF and are expecting the rest.
// LED B -> OFF once we have received EOF or are in error state or unsynced
//
// Returns: true if we received a EOF
// false if we are still waiting for some more
//=============================================================================
2020-07-21 10:51:48 +02:00
typedef struct {
2020-07-09 19:41:57 +02:00
enum {
STATE_READER_UNSYNCD ,
STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ,
STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF ,
STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF ,
STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF ,
STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 ,
STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ,
STATE_READER_RECEIVE_DATA_1_OUT_OF_256 ,
STATE_READER_RECEIVE_JAMMING
} state ;
enum {
CODING_1_OUT_OF_4 ,
CODING_1_OUT_OF_256
} Coding ;
uint8_t shiftReg ;
uint8_t bitCount ;
int byteCount ;
int byteCountMax ;
int posCount ;
int sum1 , sum2 ;
uint8_t * output ;
uint8_t jam_search_len ;
uint8_t * jam_search_string ;
2020-07-02 12:37:07 +02:00
} DecodeReader_t ;
2020-08-13 12:25:04 +02:00
static void DecodeReaderInit ( DecodeReader_t * reader , uint8_t * data , uint16_t max_len , uint8_t jam_search_len , uint8_t * jam_search_string ) {
2020-07-21 10:51:48 +02:00
reader - > output = data ;
reader - > byteCountMax = max_len ;
reader - > state = STATE_READER_UNSYNCD ;
reader - > byteCount = 0 ;
reader - > bitCount = 0 ;
reader - > posCount = 1 ;
reader - > shiftReg = 0 ;
reader - > jam_search_len = jam_search_len ;
reader - > jam_search_string = jam_search_string ;
2020-07-02 12:37:07 +02:00
}
2019-03-09 08:59:13 +01:00
2020-08-13 12:25:04 +02:00
static void DecodeReaderReset ( DecodeReader_t * reader ) {
2020-07-21 10:51:48 +02:00
reader - > state = STATE_READER_UNSYNCD ;
2020-07-02 12:37:07 +02:00
}
2010-02-20 21:24:25 +00:00
2020-08-11 21:40:22 +02:00
//static inline __attribute__((always_inline))
2020-08-13 12:25:04 +02:00
static int RAMFUNC Handle15693SampleFromReader ( bool bit , DecodeReader_t * reader ) {
2020-07-21 10:51:48 +02:00
switch ( reader - > state ) {
2020-07-09 19:41:57 +02:00
case STATE_READER_UNSYNCD :
// wait for unmodulated carrier
if ( bit ) {
2020-07-21 10:51:48 +02:00
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
}
break ;
case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF :
if ( ! bit ) {
// we went low, so this could be the beginning of a SOF
2020-07-21 10:51:48 +02:00
reader - > posCount = 1 ;
reader - > state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
}
break ;
case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
2020-07-09 19:41:57 +02:00
if ( bit ) { // detected rising edge
2020-07-21 10:51:48 +02:00
if ( reader - > posCount < 4 ) { // rising edge too early (nominally expected at 5)
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
} else { // SOF
2020-07-21 10:51:48 +02:00
reader - > state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
}
} else {
2020-07-21 10:51:48 +02:00
if ( reader - > posCount > 5 ) { // stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
} else {
// do nothing, keep waiting
}
}
break ;
case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
if ( bit = = false ) { // detected a falling edge
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
if ( reader - > posCount < 20 ) { // falling edge too early (nominally expected at 21 earliest)
DecodeReaderReset ( reader ) ;
} else if ( reader - > posCount < 23 ) { // SOF for 1 out of 4 coding
reader - > Coding = CODING_1_OUT_OF_4 ;
reader - > state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF ;
} else if ( reader - > posCount < 28 ) { // falling edge too early (nominally expected at 29 latest)
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
} else { // SOF for 1 out of 256 coding
2020-07-21 10:51:48 +02:00
reader - > Coding = CODING_1_OUT_OF_256 ;
reader - > state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
if ( reader - > posCount > 29 ) { // stayed high for too long
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
} else {
// do nothing, keep waiting
}
}
break ;
case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
2020-07-09 19:41:57 +02:00
if ( bit ) { // detected rising edge
2020-07-21 10:51:48 +02:00
if ( reader - > Coding = = CODING_1_OUT_OF_256 ) {
if ( reader - > posCount < 32 ) { // rising edge too early (nominally expected at 33)
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
reader - > posCount = 1 ;
reader - > bitCount = 0 ;
reader - > byteCount = 0 ;
reader - > sum1 = 1 ;
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256 ;
2020-07-09 19:41:57 +02:00
LED_B_ON ( ) ;
}
} else { // CODING_1_OUT_OF_4
2020-07-21 10:51:48 +02:00
if ( reader - > posCount < 24 ) { // rising edge too early (nominally expected at 25)
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
reader - > posCount = 1 ;
reader - > state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 ;
2020-07-09 19:41:57 +02:00
}
}
} else {
2020-07-21 10:51:48 +02:00
if ( reader - > Coding = = CODING_1_OUT_OF_256 ) {
if ( reader - > posCount > 34 ) { // signal stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
} else {
// do nothing, keep waiting
}
} else { // CODING_1_OUT_OF_4
2020-07-21 10:51:48 +02:00
if ( reader - > posCount > 26 ) { // signal stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
} else {
// do nothing, keep waiting
}
}
}
break ;
case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
2020-07-09 19:41:57 +02:00
if ( bit ) {
2020-07-21 10:51:48 +02:00
if ( reader - > posCount = = 9 ) {
reader - > posCount = 1 ;
reader - > bitCount = 0 ;
reader - > byteCount = 0 ;
reader - > sum1 = 1 ;
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ;
2020-07-09 19:41:57 +02:00
LED_B_ON ( ) ;
} else {
// do nothing, keep waiting
}
} else { // unexpected falling edge
2020-08-13 12:25:04 +02:00
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
}
break ;
case STATE_READER_RECEIVE_DATA_1_OUT_OF_4 :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
if ( reader - > posCount = = 1 ) {
reader - > sum1 = bit ? 1 : 0 ;
} else if ( reader - > posCount < = 4 ) {
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
if ( bit )
reader - > sum1 + + ;
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
} else if ( reader - > posCount = = 5 ) {
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
reader - > sum2 = bit ? 1 : 0 ;
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
if ( bit )
reader - > sum2 + + ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
if ( reader - > posCount = = 8 ) {
reader - > posCount = 0 ;
if ( reader - > sum1 < = 1 & & reader - > sum2 > = 3 ) { // EOF
2020-07-09 19:41:57 +02:00
LED_B_OFF ( ) ; // Finished receiving
2020-07-21 10:51:48 +02:00
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount ! = 0 ) {
2020-07-09 19:41:57 +02:00
return true ;
}
2020-07-21 10:51:48 +02:00
} else if ( reader - > sum1 > = 3 & & reader - > sum2 < = 1 ) { // detected a 2bit position
reader - > shiftReg > > = 2 ;
reader - > shiftReg | = ( reader - > bitCount < < 6 ) ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
if ( reader - > bitCount = = 15 ) { // we have a full byte
reader - > output [ reader - > byteCount + + ] = reader - > shiftReg ;
if ( reader - > byteCount > reader - > byteCountMax ) {
2020-07-09 19:41:57 +02:00
// buffer overflow, give up
LED_B_OFF ( ) ;
2020-07-21 10:51:48 +02:00
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
reader - > bitCount = 0 ;
reader - > shiftReg = 0 ;
if ( reader - > byteCount = = reader - > jam_search_len ) {
if ( ! memcmp ( reader - > output , reader - > jam_search_string , reader - > jam_search_len ) ) {
2020-07-09 19:41:57 +02:00
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM ) ;
2020-07-21 10:51:48 +02:00
reader - > state = STATE_READER_RECEIVE_JAMMING ;
2020-07-09 19:41:57 +02:00
}
}
2020-07-21 10:51:48 +02:00
2020-07-09 19:41:57 +02:00
} else {
2020-07-21 10:51:48 +02:00
reader - > bitCount + + ;
2020-07-09 19:41:57 +02:00
}
}
break ;
case STATE_READER_RECEIVE_DATA_1_OUT_OF_256 :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
if ( reader - > posCount = = 1 ) {
reader - > sum1 = bit ? 1 : 0 ;
} else if ( reader - > posCount < = 4 ) {
if ( bit ) reader - > sum1 + + ;
} else if ( reader - > posCount = = 5 ) {
reader - > sum2 = bit ? 1 : 0 ;
2020-07-09 19:41:57 +02:00
} else if ( bit ) {
2020-07-21 10:51:48 +02:00
reader - > sum2 + + ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
if ( reader - > posCount = = 8 ) {
reader - > posCount = 0 ;
if ( reader - > sum1 < = 1 & & reader - > sum2 > = 3 ) { // EOF
2020-07-09 19:41:57 +02:00
LED_B_OFF ( ) ; // Finished receiving
2020-07-21 10:51:48 +02:00
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount ! = 0 ) {
2020-07-09 19:41:57 +02:00
return true ;
}
2020-07-21 10:51:48 +02:00
} else if ( reader - > sum1 > = 3 & & reader - > sum2 < = 1 ) { // detected the bit position
reader - > shiftReg = reader - > bitCount ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
if ( reader - > bitCount = = 255 ) { // we have a full byte
reader - > output [ reader - > byteCount + + ] = reader - > shiftReg ;
if ( reader - > byteCount > reader - > byteCountMax ) {
2020-07-09 19:41:57 +02:00
// buffer overflow, give up
LED_B_OFF ( ) ;
2020-07-21 10:51:48 +02:00
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
}
2020-07-21 10:51:48 +02:00
if ( reader - > byteCount = = reader - > jam_search_len ) {
if ( ! memcmp ( reader - > output , reader - > jam_search_string , reader - > jam_search_len ) ) {
2020-07-09 19:41:57 +02:00
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM ) ;
2020-07-21 10:51:48 +02:00
reader - > state = STATE_READER_RECEIVE_JAMMING ;
2020-07-09 19:41:57 +02:00
}
}
}
2020-07-21 10:51:48 +02:00
reader - > bitCount + + ;
2020-07-09 19:41:57 +02:00
}
break ;
case STATE_READER_RECEIVE_JAMMING :
2020-07-21 10:51:48 +02:00
reader - > posCount + + ;
if ( reader - > Coding = = CODING_1_OUT_OF_4 ) {
if ( reader - > posCount = = 7 * 16 ) { // 7 bits jammed
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ) ; // stop jamming
// FpgaDisableTracing();
LED_D_OFF ( ) ;
2020-07-21 10:51:48 +02:00
} else if ( reader - > posCount = = 8 * 16 ) {
reader - > posCount = 0 ;
reader - > output [ reader - > byteCount + + ] = 0x00 ;
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ;
2020-07-09 19:41:57 +02:00
}
} else {
2020-07-21 10:51:48 +02:00
if ( reader - > posCount = = 7 * 256 ) { // 7 bits jammend
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ) ; // stop jamming
LED_D_OFF ( ) ;
2020-07-21 10:51:48 +02:00
} else if ( reader - > posCount = = 8 * 256 ) {
reader - > posCount = 0 ;
reader - > output [ reader - > byteCount + + ] = 0x00 ;
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256 ;
2020-07-09 19:41:57 +02:00
}
}
break ;
default :
LED_B_OFF ( ) ;
2020-07-21 10:51:48 +02:00
DecodeReaderReset ( reader ) ;
2020-07-09 19:41:57 +02:00
break ;
}
return false ;
2020-07-02 12:37:07 +02:00
}
2017-09-04 13:56:57 +02:00
2020-07-02 12:37:07 +02:00
//-----------------------------------------------------------------------------
// Receive a command (from the reader to us, where we are the simulated tag),
// and store it in the given buffer, up to the given maximum length. Keeps
// spinning, waiting for a well-framed command, until either we get one
// (returns len) or someone presses the pushbutton on the board (returns -1).
//
// Assume that we're called with the SSC (to the FPGA) and ADC path set
// correctly.
//-----------------------------------------------------------------------------
2019-03-09 08:59:13 +01:00
2020-07-03 21:33:17 +02:00
int GetIso15693CommandFromReader ( uint8_t * received , size_t max_len , uint32_t * eof_time ) {
2020-07-09 19:41:57 +02:00
int samples = 0 ;
bool gotFrame = false ;
// the decoder data structure
2020-08-03 17:42:05 +02:00
DecodeReader_t * dr = ( DecodeReader_t * ) BigBuf_malloc ( sizeof ( DecodeReader_t ) ) ;
DecodeReaderInit ( dr , received , max_len , 0 , NULL ) ;
2020-07-09 19:41:57 +02:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) ;
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION ) ;
// clear receive register and wait for next transfer
uint32_t temp = AT91C_BASE_SSC - > SSC_RHR ;
( void ) temp ;
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_RXRDY ) ) ;
// Setup and start DMA.
2020-07-15 15:16:35 +02:00
dmabuf8_t * dma = get_dma8 ( ) ;
2020-07-21 10:51:48 +02:00
if ( FpgaSetupSscDma ( dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-07-21 10:51:48 +02:00
return - 4 ;
}
2020-07-15 15:16:35 +02:00
uint8_t * upTo = dma - > buf ;
2020-07-09 19:41:57 +02:00
2020-08-06 16:17:08 +02:00
uint32_t dma_start_time = GetCountSspClk ( ) & 0xfffffff8 ;
2020-07-09 19:41:57 +02:00
2020-07-21 10:51:48 +02:00
for ( ; ; ) {
2020-08-13 12:25:04 +02:00
volatile uint16_t behindBy = ( ( uint8_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
2020-07-09 19:41:57 +02:00
if ( behindBy = = 0 ) continue ;
2020-08-13 12:25:04 +02:00
2020-07-21 10:51:48 +02:00
if ( samples = = 0 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
2020-07-09 19:41:57 +02:00
2020-07-13 12:28:01 +02:00
volatile uint8_t b = * upTo + + ;
2020-07-15 15:16:35 +02:00
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) { // we have read all of the DMA buffer content.
2020-08-06 16:17:08 +02:00
upTo = dma - > buf ; // start reading the circular buffer from the beginning
2020-07-15 15:16:35 +02:00
if ( behindBy > ( 9 * DMA_BUFFER_SIZE / 10 ) ) {
2020-07-13 12:28:01 +02:00
Dbprintf ( " About to blow circular buffer - aborted! behindBy %d " , behindBy ) ;
2020-07-09 19:41:57 +02:00
break ;
}
}
2020-08-06 16:17:08 +02:00
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_ENDRX ) ) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dma - > buf ; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ; // DMA Next Counter registers
2020-07-09 19:41:57 +02:00
}
for ( int i = 7 ; i > = 0 ; i - - ) {
2020-08-03 17:42:05 +02:00
if ( Handle15693SampleFromReader ( ( b > > i ) & 0x01 , dr ) ) {
2020-07-09 19:41:57 +02:00
* eof_time = dma_start_time + samples - DELAY_READER_TO_ARM ; // end of EOF
gotFrame = true ;
break ;
}
samples + + ;
}
2020-07-21 10:51:48 +02:00
if ( gotFrame ) {
break ;
}
2020-07-09 19:41:57 +02:00
if ( BUTTON_PRESS ( ) ) {
2020-08-03 17:42:05 +02:00
dr - > byteCount = - 1 ;
2020-07-09 19:41:57 +02:00
break ;
}
WDT_HIT ( ) ;
}
FpgaDisableSscDma ( ) ;
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > = DBG_EXTENDED ) {
2020-07-19 20:45:47 +02:00
Dbprintf ( " samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d " ,
2020-08-13 12:25:04 +02:00
samples , gotFrame , dr - > state , dr - > byteCount ,
dr - > bitCount , dr - > posCount ) ;
2020-07-19 20:45:47 +02:00
}
2020-07-09 19:41:57 +02:00
2020-08-03 17:42:05 +02:00
if ( dr - > byteCount > = 0 ) {
2020-07-09 19:41:57 +02:00
uint32_t sof_time = * eof_time
2020-08-13 12:25:04 +02:00
- dr - > byteCount * ( dr - > Coding = = CODING_1_OUT_OF_4 ? 128 : 2048 ) // time for byte transfers
- 32 // time for SOF transfer
- 16 ; // time for EOF transfer
2020-08-03 17:42:05 +02:00
LogTrace_ISO15693 ( dr - > output , dr - > byteCount , ( sof_time * 32 ) , ( * eof_time * 32 ) , NULL , true ) ;
2020-07-09 19:41:57 +02:00
}
2020-08-03 17:42:05 +02:00
return dr - > byteCount ;
2010-02-20 21:24:25 +00:00
}
//-----------------------------------------------------------------------------
// Start to read an ISO 15693 tag. We send an identify request, then wait
// for the response. The response is not demodulated, just left in the buffer
// so that it can be downloaded to a PC and processed there.
//-----------------------------------------------------------------------------
2019-03-10 11:20:22 +01:00
void AcquireRawAdcSamplesIso15693 ( void ) {
2021-07-27 19:16:28 +02:00
LEDsoff ( ) ;
DbpString ( " Starting to acquire data... " ) ;
2022-02-08 14:47:06 +01:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2021-07-27 19:16:28 +02:00
BigBuf_free ( ) ;
clear_trace ( ) ;
// Start from off (no field generated)
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
SpinDelay ( 10 ) ;
uint8_t cmd [ 5 ] ;
BuildIdentifyRequest ( cmd ) ;
CodeIso15693AsReader ( cmd , sizeof ( cmd ) ) ;
2020-07-09 19:41:57 +02:00
LED_A_ON ( ) ;
2021-07-27 19:16:28 +02:00
2020-07-09 19:41:57 +02:00
uint8_t * dest = BigBuf_malloc ( 4000 ) ;
2010-02-20 21:24:25 +00:00
2021-07-27 19:16:28 +02:00
// switch field on
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER ) ;
LED_D_ON ( ) ;
2021-07-27 19:16:28 +02:00
// initialize SSC and select proper AD input
2020-07-09 19:41:57 +02:00
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2019-03-09 08:59:13 +01:00
2021-07-27 19:16:28 +02:00
StartCountSspClk ( ) ;
2010-02-20 21:24:25 +00:00
2020-07-09 19:41:57 +02:00
// Give the tags time to energize
2021-07-27 19:16:28 +02:00
SpinDelay ( 250 ) ;
2016-08-04 21:37:43 +02:00
2020-07-09 19:41:57 +02:00
// Now send the command
2020-07-13 17:56:19 +02:00
tosend_t * ts = get_tosend ( ) ;
2020-07-09 19:41:57 +02:00
uint32_t start_time = 0 ;
2020-07-13 17:56:19 +02:00
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
2019-03-09 08:59:13 +01:00
2020-07-09 19:41:57 +02:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) ;
2019-03-09 08:59:13 +01:00
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ) ;
2019-03-09 08:59:13 +01:00
2020-08-13 12:25:04 +02:00
for ( int c = 0 ; c < 4000 ; ) {
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
2020-07-09 19:41:57 +02:00
uint16_t r = AT91C_BASE_SSC - > SSC_RHR ;
dest [ c + + ] = r > > 5 ;
}
}
2019-03-09 08:59:13 +01:00
2021-07-27 19:16:28 +02:00
FpgaDisableSscDma ( ) ;
2020-07-09 19:41:57 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2010-10-19 14:25:17 +00:00
}
2022-03-16 11:26:07 +01:00
void SniffIso15693 ( uint8_t jam_search_len , uint8_t * jam_search_string , bool iclass ) {
2020-07-02 12:37:07 +02:00
2020-08-14 14:56:20 +02:00
LEDsoff ( ) ;
2020-07-09 19:41:57 +02:00
LED_A_ON ( ) ;
2022-02-08 14:47:06 +01:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2020-07-09 19:41:57 +02:00
2022-03-23 17:37:40 +01:00
DbpString ( " Starting to sniff. Press <PM3 button> to stop " ) ;
2020-08-14 14:56:20 +02:00
2020-07-21 10:51:48 +02:00
BigBuf_free ( ) ;
2020-07-09 19:41:57 +02:00
clear_trace ( ) ;
set_tracing ( true ) ;
2020-08-13 12:25:04 +02:00
2020-08-03 17:42:05 +02:00
DecodeTag_t dtag = { 0 } ;
uint8_t response [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
DecodeTagInit ( & dtag , response , sizeof ( response ) ) ;
2020-07-09 19:41:57 +02:00
2022-02-08 14:47:06 +01:00
DecodeTagFSK_t dtagfsk = { 0 } ;
uint8_t response2 [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
2022-03-23 18:22:03 +01:00
DecodeTagFSKInit ( & dtagfsk , response2 , sizeof ( response2 ) ) ;
2022-02-08 14:47:06 +01:00
2020-08-03 17:42:05 +02:00
DecodeReader_t dreader = { 0 } ;
uint8_t cmd [ ISO15693_MAX_COMMAND_LENGTH ] = { 0 } ;
DecodeReaderInit ( & dreader , cmd , sizeof ( cmd ) , jam_search_len , jam_search_string ) ;
2020-07-09 19:41:57 +02:00
2022-03-04 09:45:12 +01:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE | FPGA_HF_READER_2SUBCARRIERS_424_484_KHZ ) ;
2022-03-16 11:26:07 +01:00
2020-07-09 19:41:57 +02:00
LED_D_OFF ( ) ;
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
2020-08-14 14:56:20 +02:00
2020-07-09 19:41:57 +02:00
StartCountSspClk ( ) ;
2020-08-14 14:56:20 +02:00
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
2020-07-21 10:51:48 +02:00
// Setup and start DMA.
2020-08-11 21:40:22 +02:00
if ( FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > DBG_ERROR ) DbpString ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-07-21 10:51:48 +02:00
switch_off ( ) ;
return ;
}
2020-08-11 21:40:22 +02:00
2020-07-19 20:45:47 +02:00
bool tag_is_active = false ;
bool reader_is_active = false ;
bool expect_tag_answer = false ;
2022-02-08 14:47:06 +01:00
bool expect_fsk_answer = false ;
2022-03-16 11:26:07 +01:00
bool expect_fast_answer = true ; // default to true is required for iClass
2020-07-21 10:51:48 +02:00
int dma_start_time = 0 ;
2020-08-11 21:40:22 +02:00
// Count of samples received so far, so that we can include timing
int samples = 0 ;
2020-08-13 12:25:04 +02:00
2020-08-11 21:40:22 +02:00
uint16_t * upTo = dma - > buf ;
2020-07-09 19:41:57 +02:00
2020-08-11 21:40:22 +02:00
for ( ; ; ) {
2020-08-08 11:41:26 +02:00
2020-08-13 12:25:04 +02:00
volatile int behind_by = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
2020-08-11 21:40:22 +02:00
if ( behind_by < 1 ) continue ;
2020-08-08 11:41:26 +02:00
2020-07-09 19:41:57 +02:00
samples + + ;
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
2020-07-21 10:51:48 +02:00
2022-07-06 13:50:15 +02:00
volatile uint16_t sniffdata = 0 ;
2022-03-04 12:32:08 +01:00
volatile uint16_t sniffdata_prev = sniffdata ;
sniffdata = * upTo + + ;
2020-07-21 10:51:48 +02:00
2020-08-11 21:40:22 +02:00
// we have read all of the DMA buffer content
2020-08-13 12:25:04 +02:00
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) {
2020-07-21 10:51:48 +02:00
2020-08-11 21:40:22 +02:00
// start reading the circular buffer from the beginning
2020-08-13 12:25:04 +02:00
upTo = dma - > buf ;
2020-08-11 21:40:22 +02:00
// DMA Counter Register had reached 0, already rotated.
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_ENDRX ) ) {
// primary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RNCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
break ;
}
}
}
2020-07-10 16:37:56 +02:00
// no need to try decoding reader data if the tag is sending
2022-03-04 12:32:08 +01:00
if ( ! tag_is_active ) {
2020-07-10 16:37:56 +02:00
2020-08-11 21:40:22 +02:00
if ( Handle15693SampleFromReader ( ( sniffdata & 0x02 ) > > 1 , & dreader ) ) {
2020-07-09 19:41:57 +02:00
2020-07-10 16:37:56 +02:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 8 - DELAY_READER_TO_ARM_SNIFF ; // end of EOF
2020-08-03 17:42:05 +02:00
if ( dreader . byteCount > 0 ) {
2020-07-09 19:41:57 +02:00
uint32_t sof_time = eof_time
2020-08-13 12:25:04 +02:00
- dreader . byteCount * ( dreader . Coding = = CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16 ) // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16 ; // time for EOF transfer
2020-08-03 17:42:05 +02:00
LogTrace_ISO15693 ( dreader . output , dreader . byteCount , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
2022-02-08 14:47:06 +01:00
2022-03-23 18:22:03 +01:00
if ( ! iclass ) { // Those flags don't exist in iClass
2022-03-16 11:26:07 +01:00
expect_fsk_answer = dreader . output [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ;
expect_fast_answer = dreader . output [ 0 ] & ISO15_REQ_DATARATE_HIGH ;
}
2020-07-09 19:41:57 +02:00
}
// And ready to receive another command.
2022-03-04 12:32:08 +01:00
//DecodeReaderReset(&dreader); // already reseted
2020-08-03 17:42:05 +02:00
DecodeTagReset ( & dtag ) ;
2022-02-08 14:47:06 +01:00
DecodeTagFSKReset ( & dtagfsk ) ;
2020-07-19 20:45:47 +02:00
reader_is_active = false ;
expect_tag_answer = true ;
2020-08-03 17:42:05 +02:00
} else if ( Handle15693SampleFromReader ( sniffdata & 0x01 , & dreader ) ) {
2020-07-09 19:41:57 +02:00
2020-07-10 16:37:56 +02:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 16 - DELAY_READER_TO_ARM_SNIFF ; // end of EOF
2020-08-03 17:42:05 +02:00
if ( dreader . byteCount > 0 ) {
2020-07-09 19:41:57 +02:00
uint32_t sof_time = eof_time
2020-08-13 12:25:04 +02:00
- dreader . byteCount * ( dreader . Coding = = CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16 ) // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16 ; // time for EOF transfer
2020-08-03 17:42:05 +02:00
LogTrace_ISO15693 ( dreader . output , dreader . byteCount , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
2022-03-23 18:22:03 +01:00
if ( ! iclass ) { // Those flags don't exist in iClass
2022-03-16 11:26:07 +01:00
expect_fsk_answer = dreader . output [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ;
expect_fast_answer = dreader . output [ 0 ] & ISO15_REQ_DATARATE_HIGH ;
}
2020-07-09 19:41:57 +02:00
}
// And ready to receive another command
2022-03-04 12:32:08 +01:00
//DecodeReaderReset(&dreader); // already reseted
2020-08-03 17:42:05 +02:00
DecodeTagReset ( & dtag ) ;
2022-02-08 14:47:06 +01:00
DecodeTagFSKReset ( & dtagfsk ) ;
2020-07-19 20:45:47 +02:00
reader_is_active = false ;
expect_tag_answer = true ;
2020-07-09 19:41:57 +02:00
} else {
2020-08-03 17:42:05 +02:00
reader_is_active = ( dreader . state > = STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ) ;
2020-07-09 19:41:57 +02:00
}
}
2022-03-04 12:32:08 +01:00
if ( ! reader_is_active & & expect_tag_answer ) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet
2020-07-21 10:51:48 +02:00
2022-03-23 18:22:03 +01:00
if ( ! expect_fsk_answer ) {
2022-03-16 15:21:28 +01:00
if ( Handle15693SamplesFromTag ( ( sniffdata > > 4 ) < < 2 , & dtag , expect_fast_answer ) ) {
2020-07-09 19:41:57 +02:00
2022-02-08 14:47:06 +01:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM_SNIFF ; // end of EOF
if ( dtag . lastBit = = SOF_PART2 ) {
eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
uint32_t sof_time = eof_time
- dtag . len * 8 * 8 * 16 // time for byte transfers
- ( 32 * 16 ) // time for SOF transfer
- ( dtag . lastBit ! = SOF_PART2 ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
LogTrace_ISO15693 ( dtag . output , dtag . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
// And ready to receive another response.
DecodeTagReset ( & dtag ) ;
DecodeTagFSKReset ( & dtagfsk ) ;
DecodeReaderReset ( & dreader ) ;
expect_tag_answer = false ;
tag_is_active = false ;
} else {
tag_is_active = ( dtag . state > = STATE_TAG_RECEIVING_DATA ) ;
}
2022-03-23 18:22:03 +01:00
} else {
2022-03-04 12:32:08 +01:00
if ( FREQ_IS_0 ( ( sniffdata > > 2 ) & 0x3 ) ) // tolerate 1 00
sniffdata = sniffdata_prev ;
2022-02-08 14:47:06 +01:00
2022-03-04 12:32:08 +01:00
if ( Handle15693FSKSamplesFromTag ( ( sniffdata > > 2 ) & 0x3 , & dtagfsk , expect_fast_answer ) ) {
2022-02-08 14:47:06 +01:00
expect_fsk_answer = false ;
2022-03-23 18:22:03 +01:00
} else {
2022-03-04 12:32:08 +01:00
tag_is_active = ( dtagfsk . state > = STATE_FSK_RECEIVING_DATA_484 ) ;
}
2022-03-23 18:22:03 +01:00
if ( ! expect_fsk_answer ) {
// FSK answer no more expected: switch back to ASK
if ( dtagfsk . len > 0 ) {
2022-03-04 12:32:08 +01:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM_SNIFF ; // end of EOF
if ( dtagfsk . lastBit = = SOF ) {
eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
uint32_t sof_time = eof_time
2022-03-23 18:22:03 +01:00
- dtagfsk . len * 8 * 8 * 16 // time for byte transfers
- ( 32 * 16 ) // time for SOF transfer
- ( dtagfsk . lastBit ! = SOF ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
2020-07-10 16:37:56 +02:00
2022-03-04 12:32:08 +01:00
LogTrace_ISO15693 ( dtagfsk . output , dtagfsk . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
2022-02-08 14:47:06 +01:00
}
DecodeTagFSKReset ( & dtagfsk ) ;
DecodeReaderReset ( & dreader ) ;
expect_tag_answer = false ;
tag_is_active = false ;
}
2020-07-09 19:41:57 +02:00
}
}
}
2020-07-21 10:51:48 +02:00
2020-08-08 11:41:26 +02:00
FpgaDisableTracing ( ) ;
2020-07-19 20:45:47 +02:00
switch_off ( ) ;
2020-07-09 19:41:57 +02:00
2020-08-11 21:40:22 +02:00
DbpString ( " " ) ;
2020-08-08 11:41:26 +02:00
DbpString ( _CYAN_ ( " Sniff statistics " ) ) ;
2020-08-11 21:40:22 +02:00
DbpString ( " ================================= " ) ;
2020-08-08 11:41:26 +02:00
Dbprintf ( " DecodeTag State........%d " , dtag . state ) ;
Dbprintf ( " DecodeTag byteCnt......%d " , dtag . len ) ;
Dbprintf ( " DecodeTag posCount.....%d " , dtag . posCount ) ;
2022-03-08 17:29:34 +01:00
Dbprintf ( " DecodeTagFSK State.....%d " , dtagfsk . state ) ;
Dbprintf ( " DecodeTagFSK byteCnt...%d " , dtagfsk . len ) ;
2022-02-08 14:47:06 +01:00
Dbprintf ( " DecodeTagFSK count.....%d " , dtagfsk . count ) ;
2020-08-08 11:41:26 +02:00
Dbprintf ( " DecodeReader State.....%d " , dreader . state ) ;
Dbprintf ( " DecodeReader byteCnt...%d " , dreader . byteCount ) ;
Dbprintf ( " DecodeReader posCount..%d " , dreader . posCount ) ;
2020-08-11 21:40:22 +02:00
Dbprintf ( " Trace length........... " _YELLOW_ ( " %d " ) , BigBuf_get_traceLen ( ) ) ;
2020-08-13 12:25:04 +02:00
DbpString ( " " ) ;
2020-08-08 11:41:26 +02:00
2010-10-19 14:25:17 +00:00
}
2020-07-09 19:41:57 +02:00
// Initialize Proxmark3 as ISO15693 reader
2019-03-10 11:20:22 +01:00
void Iso15693InitReader ( void ) {
2020-07-19 20:45:47 +02:00
2020-08-13 12:25:04 +02:00
LEDsoff ( ) ;
2022-02-08 14:47:06 +01:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2010-10-19 14:25:17 +00:00
2019-03-09 20:34:41 +01:00
// Start from off (no field generated)
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
2020-07-19 20:45:47 +02:00
SpinDelay ( 10 ) ;
2010-10-19 14:25:17 +00:00
2020-07-09 19:41:57 +02:00
// switch field on
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER ) ;
LED_D_ON ( ) ;
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
// initialize SSC and select proper AD input
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2020-07-13 17:56:19 +02:00
set_tracing ( true ) ;
2020-07-09 19:41:57 +02:00
// give tags some time to energize
2020-07-19 20:45:47 +02:00
SpinDelay ( 250 ) ;
2020-07-09 19:41:57 +02:00
StartCountSspClk ( ) ;
2010-10-19 14:25:17 +00:00
}
///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 3 - Air Interface
2021-10-10 01:35:38 +02:00
// This section basically contains transmission and receiving of bits
2010-10-19 14:25:17 +00:00
///////////////////////////////////////////////////////////////////////
2020-07-02 12:37:07 +02:00
// Encode an identify request, which is the first
2010-10-19 14:25:17 +00:00
// thing that you must send to a tag to get a response.
2019-04-06 20:21:03 +02:00
// It expects "cmdout" to be at least CMD_ID_RESP large
2020-07-02 12:37:07 +02:00
// When READER:
static void BuildIdentifyRequest ( uint8_t * cmd ) {
2019-03-09 20:34:41 +01:00
// flags
cmd [ 0 ] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1 ;
2020-07-09 19:41:57 +02:00
// inventory command code
2021-05-03 09:35:38 +02:00
cmd [ 1 ] = ISO15693_INVENTORY ;
2020-07-09 19:41:57 +02:00
// no mask
cmd [ 2 ] = 0x00 ;
2019-03-09 20:34:41 +01:00
// CRC
2019-04-07 12:07:50 +02:00
AddCrc15 ( cmd , 3 ) ;
2010-10-19 14:25:17 +00:00
}
2012-06-20 17:20:21 +00:00
// Universal Method for sending to and recv bytes from a tag
2019-03-09 20:34:41 +01:00
// init ... should we initialize the reader?
// speed ... 0 low speed, 1 hi speed
// **recv will return you a pointer to the received data
// If you do not need the answer use NULL for *recv[]
2019-07-23 21:40:01 +02:00
// return: length of received data
2017-09-04 13:56:57 +02:00
// logging enabled
2020-08-13 12:25:04 +02:00
int SendDataTag ( uint8_t * send , int sendlen , bool init , bool speed_fast , uint8_t * recv ,
2022-03-23 17:37:40 +01:00
uint16_t max_recv_len , uint32_t start_time , uint16_t timeout , uint32_t * eof_time , uint16_t * resp_len ) {
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
if ( init ) {
Iso15693InitReader ( ) ;
2020-08-14 14:56:20 +02:00
start_time = GetCountSspClk ( ) ;
2020-07-09 19:41:57 +02:00
}
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
if ( speed_fast ) {
// high speed (1 out of 4)
CodeIso15693AsReader ( send , sendlen ) ;
} else {
// low speed (1 out of 256)
CodeIso15693AsReader256 ( send , sendlen ) ;
}
2022-03-23 17:37:40 +01:00
2020-07-13 17:56:19 +02:00
tosend_t * ts = get_tosend ( ) ;
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
2020-10-20 01:00:23 +02:00
2021-03-07 23:43:53 +01:00
if ( tearoff_hook ( ) = = PM3_ETEAROFF ) { // tearoff occurred
2022-03-23 17:37:40 +01:00
* resp_len = 0 ;
return PM3_ETEAROFF ;
2020-10-13 22:43:28 +02:00
} else {
2020-10-20 01:00:23 +02:00
2022-03-23 17:37:40 +01:00
int res = PM3_SUCCESS ;
2021-10-10 01:35:38 +02:00
* eof_time = start_time + 32 * ( ( 8 * ts - > max ) - 4 ) ; // subtract the 4 padding bits after EOF
2020-10-13 22:43:28 +02:00
LogTrace_ISO15693 ( send , sendlen , ( start_time * 4 ) , ( * eof_time * 4 ) , NULL , true ) ;
if ( recv ! = NULL ) {
2022-03-23 17:37:40 +01:00
bool fsk = send [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ;
bool recv_speed = send [ 0 ] & ISO15_REQ_DATARATE_HIGH ;
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time , fsk , recv_speed , resp_len ) ;
2020-10-13 22:43:28 +02:00
}
2022-03-23 17:37:40 +01:00
return res ;
2020-07-09 19:41:57 +02:00
}
2020-07-02 12:37:07 +02:00
}
2019-03-09 08:59:13 +01:00
2022-03-23 17:37:40 +01:00
int SendDataTagEOF ( uint8_t * recv , uint16_t max_recv_len , uint32_t start_time , uint16_t timeout , uint32_t * eof_time , bool fsk , bool recv_speed , uint16_t * resp_len ) {
2015-06-29 22:36:55 +02:00
2020-07-09 19:41:57 +02:00
CodeIso15693AsReaderEOF ( ) ;
2020-07-13 17:56:19 +02:00
tosend_t * ts = get_tosend ( ) ;
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
2021-10-10 01:35:38 +02:00
uint32_t end_time = start_time + 32 * ( 8 * ts - > max - 4 ) ; // subtract the 4 padding bits after EOF
2020-07-21 10:51:48 +02:00
LogTrace_ISO15693 ( NULL , 0 , ( start_time * 4 ) , ( end_time * 4 ) , NULL , true ) ;
2017-09-04 13:56:57 +02:00
2022-03-23 17:37:40 +01:00
int res = PM3_SUCCESS ;
if ( recv ) {
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time , fsk , recv_speed , resp_len ) ;
2020-07-09 19:41:57 +02:00
}
return res ;
2010-10-19 14:25:17 +00:00
}
2010-02-20 21:24:25 +00:00
2010-10-19 14:25:17 +00:00
// --------------------------------------------------------------------
2019-03-09 08:59:13 +01:00
// Debug Functions
2010-10-19 14:25:17 +00:00
// --------------------------------------------------------------------
2010-02-20 21:24:25 +00:00
2010-10-19 14:25:17 +00:00
// Decodes a message from a tag and displays its metadata and content
# define DBD15STATLEN 48
2020-05-10 16:59:38 +02:00
static void DbdecodeIso15693Answer ( int len , uint8_t * d ) {
2019-03-09 20:34:41 +01:00
if ( len > 3 ) {
2020-07-02 12:37:07 +02:00
2019-06-07 18:41:39 +02:00
char status [ DBD15STATLEN + 1 ] = { 0 } ;
2020-07-02 12:37:07 +02:00
if ( d [ 0 ] & ISO15_RES_EXT )
2019-03-12 19:18:16 +01:00
strncat ( status , " ProtExt " , DBD15STATLEN - strlen ( status ) ) ;
2020-07-02 12:37:07 +02:00
if ( d [ 0 ] & ISO15_RES_ERROR ) {
2019-03-09 20:34:41 +01:00
// error
2019-03-12 19:18:16 +01:00
strncat ( status , " Error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
switch ( d [ 1 ] ) {
case 0x01 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 01: not supported " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x02 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 02: not recognized " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x03 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 03: opt not supported " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x0f :
2019-03-12 19:18:16 +01:00
strncat ( status , " 0F: no info " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x10 :
2019-09-14 17:50:58 +02:00
strncat ( status , " 10: don't exist " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x11 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 11: lock again " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x12 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 12: locked " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x13 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 13: program error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
case 0x14 :
2019-03-12 19:18:16 +01:00
strncat ( status , " 14: lock error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
break ;
default :
2019-03-12 19:18:16 +01:00
strncat ( status , " unknown error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
}
2019-03-12 19:18:16 +01:00
strncat ( status , " " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
} else {
2019-03-12 19:18:16 +01:00
strncat ( status , " No error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
}
2019-04-07 12:10:52 +02:00
if ( CheckCrc15 ( d , len ) )
2022-02-24 18:03:19 +01:00
strncat ( status , " [+] crc ( " _GREEN_ ( " ok " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
else
2022-02-24 18:03:19 +01:00
strncat ( status , " [!] crc ( " _RED_ ( " fail " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-09 20:34:41 +01:00
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > = DBG_ERROR ) Dbprintf ( " %s " , status ) ;
2019-03-09 20:34:41 +01:00
}
2010-02-20 21:24:25 +00:00
}
2010-10-19 14:25:17 +00:00
///////////////////////////////////////////////////////////////////////
// Functions called via USB/Client
///////////////////////////////////////////////////////////////////////
2010-02-20 21:24:25 +00:00
//-----------------------------------------------------------------------------
2017-09-04 13:56:57 +02:00
// Act as ISO15693 reader, perform anti-collision and then attempt to read a sector
2010-02-20 21:24:25 +00:00
// all demodulation performed in arm rather than host. - greg
//-----------------------------------------------------------------------------
2022-03-23 17:37:40 +01:00
void ReaderIso15693 ( iso15_card_select_t * p_card ) {
2019-03-09 20:34:41 +01:00
2020-07-09 19:41:57 +02:00
LED_A_ON ( ) ;
set_tracing ( true ) ;
2019-03-09 20:34:41 +01:00
2020-07-09 19:41:57 +02:00
uint8_t * answer = BigBuf_malloc ( ISO15693_MAX_RESPONSE_LENGTH ) ;
2020-07-02 12:37:07 +02:00
memset ( answer , 0x00 , ISO15693_MAX_RESPONSE_LENGTH ) ;
2019-03-09 20:34:41 +01:00
2020-07-09 19:41:57 +02:00
// FIRST WE RUN AN INVENTORY TO GET THE TAG UID
// THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
2019-03-09 20:34:41 +01:00
2020-07-09 19:41:57 +02:00
// Send the IDENTIFY command
uint8_t cmd [ 5 ] = { 0 } ;
BuildIdentifyRequest ( cmd ) ;
uint32_t start_time = 0 ;
uint32_t eof_time ;
2022-03-23 18:22:03 +01:00
uint16_t recvlen = 0 ;
2022-03-23 17:37:40 +01:00
int res = SendDataTag ( cmd , sizeof ( cmd ) , true , true , answer , ISO15693_MAX_RESPONSE_LENGTH , start_time , ISO15693_READER_TIMEOUT , & eof_time , & recvlen ) ;
2020-10-20 01:00:23 +02:00
2022-03-23 17:37:40 +01:00
if ( res = = PM3_ETEAROFF ) { // tearoff occurred
reply_ng ( CMD_HF_ISO15693_READER , res , NULL , 0 ) ;
2020-10-13 22:43:28 +02:00
} else {
2020-10-20 01:00:23 +02:00
2021-02-28 19:01:38 +01:00
//start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
2019-03-09 20:34:41 +01:00
2020-10-13 22:43:28 +02:00
// we should do a better check than this
if ( recvlen > = 12 ) {
uint8_t uid [ 8 ] ;
uid [ 0 ] = answer [ 9 ] ; // always E0
uid [ 1 ] = answer [ 8 ] ; // IC Manufacturer code
uid [ 2 ] = answer [ 7 ] ;
uid [ 3 ] = answer [ 6 ] ;
uid [ 4 ] = answer [ 5 ] ;
uid [ 5 ] = answer [ 4 ] ;
uid [ 6 ] = answer [ 3 ] ;
uid [ 7 ] = answer [ 2 ] ;
2021-05-05 19:55:58 +12:00
if ( p_card ! = NULL ) {
memcpy ( p_card - > uid , uid , 8 ) ;
p_card - > uidlen = 8 ;
}
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > = DBG_EXTENDED ) {
2020-10-13 22:43:28 +02:00
Dbprintf ( " [+] UID = %02X%02X%02X%02X%02X%02X%02X%02X " ,
uid [ 0 ] , uid [ 1 ] , uid [ 2 ] , uid [ 3 ] ,
uid [ 4 ] , uid [ 5 ] , uid [ 5 ] , uid [ 6 ]
) ;
}
// send UID back to client.
// arg0 = 1 = OK
// arg1 = len of response (12 bytes)
// arg2 = rtf
// asbytes = uid.
2022-03-23 17:37:40 +01:00
reply_ng ( CMD_HF_ISO15693_READER , PM3_SUCCESS , uid , sizeof ( uid ) ) ;
2020-10-13 22:43:28 +02:00
2021-08-21 23:02:27 +02:00
if ( g_dbglevel > = DBG_EXTENDED ) {
2020-10-13 22:43:28 +02:00
Dbprintf ( " [+] %d octets read from IDENTIFY request: " , recvlen ) ;
DbdecodeIso15693Answer ( recvlen , answer ) ;
Dbhexdump ( recvlen , answer , true ) ;
}
} else {
2021-05-05 19:55:58 +12:00
p_card - > uidlen = 0 ;
2020-10-13 22:43:28 +02:00
DbpString ( " Failed to select card " ) ;
2022-03-23 17:37:40 +01:00
reply_ng ( CMD_HF_ISO15693_READER , PM3_EFAILED , NULL , 0 ) ;
2019-03-09 20:34:41 +01:00
}
}
switch_off ( ) ;
2020-07-02 12:37:07 +02:00
BigBuf_free ( ) ;
}
// When SIM: initialize the Proxmark3 as ISO15693 tag
2020-07-03 21:33:17 +02:00
void Iso15693InitTag ( void ) {
2020-08-13 12:25:04 +02:00
2022-02-08 14:47:06 +01:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2020-07-09 19:41:57 +02:00
// Start from off (no field generated)
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
SpinDelay ( 10 ) ;
// switch simulation FPGA
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION ) ;
// initialize SSC and select proper AD input
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_SIMULATOR ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2020-07-19 20:45:47 +02:00
clear_trace ( ) ;
2020-07-13 12:28:01 +02:00
set_tracing ( true ) ;
2020-07-09 19:41:57 +02:00
StartCountSspClk ( ) ;
2010-02-20 21:24:25 +00:00
}
2022-09-01 16:12:22 +02:00
void EmlClearIso15693 ( void ) {
// Resetting the bitstream also frees the BigBuf memory, so we do this here to prevent
// an inconvenient reset in the future by Iso15693InitTag
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
BigBuf_Clear_EM ( ) ;
reply_ng ( CMD_HF_ISO15693_EML_CLEAR , PM3_SUCCESS , NULL , 0 ) ;
}
void EmlSetMemIso15693 ( uint8_t count , uint8_t * data , uint32_t offset ) {
uint8_t * emCARD = BigBuf_get_EM_addr ( ) ;
memcpy ( emCARD + offset , data , count ) ;
}
2022-09-05 09:52:08 +02:00
void EmlGetMemIso15693 ( uint8_t count , uint8_t * output , uint32_t offset ) {
uint8_t * emCARD = BigBuf_get_EM_addr ( ) ;
memcpy ( output , emCARD + offset , count ) ;
}
2010-02-20 21:24:25 +00:00
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
// all demodulation performed in arm rather than host. - greg
2022-09-01 18:46:20 +02:00
void SimTagIso15693 ( uint8_t * uid , uint8_t block_size ) {
2019-03-09 08:59:13 +01:00
2020-07-19 20:45:47 +02:00
// free eventually allocated BigBuf memory
BigBuf_free_keep_EM ( ) ;
2020-07-09 19:41:57 +02:00
Iso15693InitTag ( ) ;
2019-03-09 08:59:13 +01:00
2019-03-09 20:34:41 +01:00
LED_A_ON ( ) ;
2010-02-20 21:24:25 +00:00
2022-09-01 18:46:20 +02:00
Dbprintf ( " ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X block size %d " , uid [ 0 ] , uid [ 1 ] , uid [ 2 ] , uid [ 3 ] , uid [ 4 ] , uid [ 5 ] , uid [ 6 ] , uid [ 7 ] , block_size ) ;
2010-02-20 21:24:25 +00:00
2019-03-09 20:34:41 +01:00
LED_C_ON ( ) ;
2010-02-20 21:24:25 +00:00
2020-07-19 20:45:47 +02:00
enum { NO_FIELD , IDLE , ACTIVATED , SELECTED , HALTED } chip_state = NO_FIELD ;
2020-08-13 12:25:04 +02:00
2020-07-19 20:45:47 +02:00
bool button_pressed = false ;
2021-02-28 19:01:38 +01:00
int vHf ; // in mV
2020-08-13 12:25:04 +02:00
2020-07-19 20:45:47 +02:00
bool exit_loop = false ;
while ( exit_loop = = false ) {
2020-10-23 10:00:47 +02:00
button_pressed = BUTTON_PRESS ( ) ;
if ( button_pressed | | data_available ( ) )
break ;
2019-03-09 20:34:41 +01:00
WDT_HIT ( ) ;
2019-03-09 08:59:13 +01:00
2020-07-19 20:45:47 +02:00
// find reader field
if ( chip_state = = NO_FIELD ) {
vHf = ( MAX_ADC_HF_VOLTAGE * SumAdc ( ADC_CHAN_HF , 32 ) ) > > 15 ;
if ( vHf > MF_MINFIELDV ) {
chip_state = IDLE ;
LED_A_ON ( ) ;
} else {
2020-08-13 12:25:04 +02:00
continue ;
2020-07-19 20:45:47 +02:00
}
}
2019-03-09 20:34:41 +01:00
// Listen to reader
2020-07-09 19:41:57 +02:00
uint8_t cmd [ ISO15693_MAX_COMMAND_LENGTH ] ;
2020-07-19 20:45:47 +02:00
uint32_t reader_eof_time = 0 ;
int cmd_len = GetIso15693CommandFromReader ( cmd , sizeof ( cmd ) , & reader_eof_time ) ;
if ( cmd_len < 0 ) {
button_pressed = true ;
break ;
2020-07-09 19:41:57 +02:00
}
2019-03-09 08:59:13 +01:00
2020-07-19 20:45:47 +02:00
// TODO: check more flags
2021-05-03 09:35:38 +02:00
if ( ( cmd_len > = 5 ) & & ( cmd [ 0 ] & ISO15_REQ_INVENTORY ) & & ( cmd [ 1 ] = = ISO15693_INVENTORY ) ) {
2020-07-19 20:45:47 +02:00
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
// Build INVENTORY command
uint8_t resp_inv [ CMD_INV_RESP ] = { 0 } ;
resp_inv [ 0 ] = 0 ; // No error, no protocol format extension
resp_inv [ 1 ] = 0 ; // DSFID (data storage format identifier). 0x00 = not supported
// 64-bit UID
resp_inv [ 2 ] = uid [ 7 ] ;
resp_inv [ 3 ] = uid [ 6 ] ;
resp_inv [ 4 ] = uid [ 5 ] ;
resp_inv [ 5 ] = uid [ 4 ] ;
resp_inv [ 6 ] = uid [ 3 ] ;
resp_inv [ 7 ] = uid [ 2 ] ;
resp_inv [ 8 ] = uid [ 1 ] ;
resp_inv [ 9 ] = uid [ 0 ] ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
// CRC
AddCrc15 ( resp_inv , 10 ) ;
CodeIso15693AsTag ( resp_inv , CMD_INV_RESP ) ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
tosend_t * ts = get_tosend ( ) ;
2020-12-12 14:46:40 +01:00
2020-07-19 20:45:47 +02:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
2020-07-21 10:51:48 +02:00
LogTrace_ISO15693 ( resp_inv , CMD_INV_RESP , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
2020-08-13 12:25:04 +02:00
2020-07-19 20:45:47 +02:00
chip_state = SELECTED ;
2019-03-09 20:34:41 +01:00
}
2020-12-12 14:46:40 +01:00
2020-12-01 21:28:37 +00:00
// GET_SYSTEM_INFO
2021-05-03 09:35:38 +02:00
if ( ( cmd [ 1 ] = = ISO15693_GET_SYSTEM_INFO ) ) {
2020-12-01 21:28:37 +00:00
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-12 14:46:40 +01:00
2022-08-26 09:28:04 +02:00
// Build GET_SYSTEM_INFO response
2020-12-01 21:42:22 +00:00
uint8_t resp_sysinfo [ CMD_SYSINFO_RESP ] = { 0 } ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
resp_sysinfo [ 0 ] = 0 ; // Response flags.
2020-12-01 22:56:08 +00:00
resp_sysinfo [ 1 ] = 0x0F ; // Information flags (0x0F - DSFID, AFI, Mem size, IC)
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
// 64-bit UID
resp_sysinfo [ 2 ] = uid [ 7 ] ;
resp_sysinfo [ 3 ] = uid [ 6 ] ;
resp_sysinfo [ 4 ] = uid [ 5 ] ;
resp_sysinfo [ 5 ] = uid [ 4 ] ;
resp_sysinfo [ 6 ] = uid [ 3 ] ;
resp_sysinfo [ 7 ] = uid [ 2 ] ;
resp_sysinfo [ 8 ] = uid [ 1 ] ;
resp_sysinfo [ 9 ] = uid [ 0 ] ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
resp_sysinfo [ 10 ] = 0 ; // DSFID
resp_sysinfo [ 11 ] = 0 ; // AFI
2020-12-01 21:28:37 +00:00
2022-09-01 18:46:20 +02:00
resp_sysinfo [ 12 ] = 0x1F ; // Block count
resp_sysinfo [ 13 ] = block_size - 1 ; // Block size.
2020-12-01 22:56:08 +00:00
resp_sysinfo [ 14 ] = 0x01 ; // IC reference.
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
// CRC
AddCrc15 ( resp_sysinfo , 15 ) ;
CodeIso15693AsTag ( resp_sysinfo , CMD_SYSINFO_RESP ) ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
tosend_t * ts = get_tosend ( ) ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:28:37 +00:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
LogTrace_ISO15693 ( resp_sysinfo , CMD_SYSINFO_RESP , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
}
2020-12-12 14:46:40 +01:00
2022-08-26 09:29:15 +02:00
// READ_BLOCK and READ_MULTI_BLOCK
if ( ( cmd [ 1 ] = = ISO15693_READBLOCK ) | | ( cmd [ 1 ] = = ISO15693_READ_MULTI_BLOCK ) ) {
2020-12-01 21:28:37 +00:00
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
2022-09-05 10:12:25 +02:00
bool addressed = cmd [ 0 ] & ISO15_REQ_ADDRESS ;
2022-08-26 09:29:15 +02:00
bool option = cmd [ 0 ] & ISO15_REQ_OPTION ;
2020-12-01 21:28:37 +00:00
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-12 14:46:40 +01:00
2022-09-05 10:12:25 +02:00
uint8_t address_offset = 0 ;
if ( addressed ) {
address_offset = 8 ;
}
uint8_t block_idx = cmd [ 2 + address_offset ] ;
2022-08-26 09:29:15 +02:00
uint8_t block_count = 1 ;
2022-09-05 10:12:25 +02:00
if ( cmd [ 1 ] = = ISO15693_READ_MULTI_BLOCK ) {
block_count = cmd [ 3 + address_offset ] + 1 ;
2022-08-26 09:29:15 +02:00
}
2020-12-12 14:46:40 +01:00
2022-08-26 09:29:15 +02:00
// Build READ_(MULTI_)BLOCK response
int response_length = 3 + block_size * block_count ;
int security_offset = 0 ;
if ( option ) {
response_length + = block_count ;
security_offset = 1 ;
}
uint8_t resp_readblock [ response_length ] ;
2022-09-05 10:27:54 +02:00
memset ( resp_readblock , 0 , response_length ) ;
2022-08-26 09:29:15 +02:00
resp_readblock [ 0 ] = 0 ; // Response flags
for ( int j = 0 ; j < block_count ; j + + ) {
// where to put the data of the current block
int work_offset = 1 + j * ( block_size + security_offset ) ;
if ( option ) {
resp_readblock [ work_offset ] = 0 ; // Security status
}
2022-09-05 09:52:08 +02:00
// Block data
if ( block_size * ( block_idx + j + 1 ) < = CARD_MEMORY_SIZE ) {
EmlGetMemIso15693 ( block_size , resp_readblock + ( work_offset + security_offset ) ,
block_size * ( block_idx + j ) ) ;
} else {
2022-09-05 10:27:54 +02:00
memset ( resp_readblock + work_offset + security_offset , 0 , block_size ) ;
2022-08-26 09:29:15 +02:00
}
}
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
// CRC
2022-08-26 09:29:15 +02:00
AddCrc15 ( resp_readblock , response_length - 2 ) ;
CodeIso15693AsTag ( resp_readblock , response_length ) ;
2020-12-12 14:46:40 +01:00
2020-12-01 21:42:22 +00:00
tosend_t * ts = get_tosend ( ) ;
2020-12-01 21:28:37 +00:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
2022-08-26 09:29:15 +02:00
LogTrace_ISO15693 ( resp_readblock , response_length , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
2020-12-01 21:28:37 +00:00
}
2022-09-05 10:24:22 +02:00
// WRITE_BLOCK and WRITE_MULTI_BLOCK
if ( ( cmd [ 1 ] = = ISO15693_WRITEBLOCK ) | | ( cmd [ 1 ] = = ISO15693_WRITE_MULTI_BLOCK ) ) {
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
bool addressed = cmd [ 0 ] & ISO15_REQ_ADDRESS ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
uint8_t address_offset = 0 ;
if ( addressed ) {
address_offset = 8 ;
}
uint8_t block_idx = cmd [ 2 + address_offset ] ;
uint8_t block_count = 1 ;
uint8_t multi_offset = 0 ;
if ( cmd [ 1 ] = = ISO15693_WRITE_MULTI_BLOCK ) {
block_count = cmd [ 3 + address_offset ] + 1 ;
multi_offset = 1 ;
}
uint8_t * data = cmd + 3 + address_offset + multi_offset ;
// write data
EmlSetMemIso15693 ( block_count * block_size , data , block_idx * block_size ) ;
// Build WRITE_(MULTI_)BLOCK response
int response_length = 3 ;
uint8_t resp_writeblock [ response_length ] ;
2022-09-05 10:27:54 +02:00
memset ( resp_writeblock , 0 , response_length ) ;
2022-09-05 10:24:22 +02:00
resp_writeblock [ 0 ] = 0 ; // Response flags
// CRC
AddCrc15 ( resp_writeblock , response_length - 2 ) ;
CodeIso15693AsTag ( resp_writeblock , response_length ) ;
tosend_t * ts = get_tosend ( ) ;
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
LogTrace_ISO15693 ( resp_writeblock , response_length , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
}
2020-07-09 19:41:57 +02:00
}
2020-07-19 20:45:47 +02:00
2019-03-09 20:34:41 +01:00
switch_off ( ) ;
2020-07-19 20:45:47 +02:00
if ( button_pressed )
DbpString ( " button pressed " ) ;
2020-09-07 10:39:15 +02:00
2020-08-17 08:52:24 +02:00
reply_ng ( CMD_HF_ISO15693_SIMULATE , PM3_SUCCESS , NULL , 0 ) ;
2010-02-20 21:24:25 +00:00
}
2010-10-19 14:25:17 +00:00
// Since there is no standardized way of reading the AFI out of a tag, we will brute force it
// (some manufactures offer a way to read the AFI, though)
2019-03-10 11:20:22 +01:00
void BruteforceIso15693Afi ( uint32_t speed ) {
2016-08-04 21:37:43 +02:00
2020-07-02 12:37:07 +02:00
uint8_t data [ 7 ] = { 0 } ;
2020-08-13 12:25:04 +02:00
uint8_t recv [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2019-03-09 20:34:41 +01:00
Iso15693InitReader ( ) ;
// first without AFI
2021-10-10 01:35:38 +02:00
// Tags should respond without AFI and with AFI=0 even when AFI is active
2019-03-09 20:34:41 +01:00
data [ 0 ] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1 ;
2021-05-03 09:35:38 +02:00
data [ 1 ] = ISO15693_INVENTORY ;
2019-10-10 11:54:23 +02:00
data [ 2 ] = 0 ; // AFI
2019-04-07 12:07:50 +02:00
AddCrc15 ( data , 3 ) ;
2020-07-02 12:37:07 +02:00
2020-08-13 12:25:04 +02:00
int datalen = 5 ;
2020-07-02 12:37:07 +02:00
uint32_t eof_time = 0 ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( data , datalen , true , speed , recv , sizeof ( recv ) , 0 , ISO15693_READER_TIMEOUT , & eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS ) {
DbpString ( " Failed to select card " ) ;
reply_ng ( CMD_HF_ISO15693_FINDAFI , res , NULL , 0 ) ;
switch_off ( ) ;
return ;
}
2019-03-09 20:34:41 +01:00
2022-03-23 17:37:40 +01:00
uint32_t start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2019-03-09 20:34:41 +01:00
WDT_HIT ( ) ;
if ( recvlen > = 12 ) {
2020-07-02 12:37:07 +02:00
Dbprintf ( " NoAFI UID = %s " , iso15693_sprintUID ( NULL , recv + 2 ) ) ;
2019-03-09 20:34:41 +01:00
}
// now with AFI
data [ 0 ] | = ISO15_REQINV_AFI ;
data [ 2 ] = 0 ; // AFI
data [ 3 ] = 0 ; // mask length
2019-10-10 11:54:23 +02:00
// 4 + 2crc
datalen = 6 ;
2020-07-02 12:37:07 +02:00
bool aborted = false ;
2019-03-09 20:34:41 +01:00
for ( uint16_t i = 0 ; i < 256 ; i + + ) {
2020-07-02 12:37:07 +02:00
2019-03-09 20:34:41 +01:00
data [ 2 ] = i & 0xFF ;
2019-04-07 12:07:50 +02:00
AddCrc15 ( data , 4 ) ;
2020-07-02 12:37:07 +02:00
2022-03-23 17:37:40 +01:00
recvlen = 0 ;
res = SendDataTag ( data , datalen , false , speed , recv , sizeof ( recv ) , start_time , ISO15693_READER_TIMEOUT , & eof_time , & recvlen ) ;
2020-07-09 19:41:57 +02:00
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2020-08-13 12:25:04 +02:00
2019-03-09 20:34:41 +01:00
WDT_HIT ( ) ;
2020-07-02 12:37:07 +02:00
2019-03-09 20:34:41 +01:00
if ( recvlen > = 12 ) {
2020-07-02 12:37:07 +02:00
Dbprintf ( " AFI = %i UID = %s " , i , iso15693_sprintUID ( NULL , recv + 2 ) ) ;
2019-03-09 20:34:41 +01:00
}
2022-03-23 17:37:40 +01:00
aborted = ( BUTTON_PRESS ( ) & & data_available ( ) ) ;
2019-11-27 21:14:31 +02:00
if ( aborted ) {
2019-03-09 20:34:41 +01:00
break ;
}
}
DbpString ( " AFI Bruteforcing done. " ) ;
switch_off ( ) ;
2019-11-27 15:11:43 +02:00
if ( aborted ) {
2021-04-06 23:37:45 +02:00
reply_ng ( CMD_HF_ISO15693_FINDAFI , PM3_EOPABORTED , NULL , 0 ) ;
2019-11-27 15:11:43 +02:00
} else {
2021-04-06 23:37:45 +02:00
reply_ng ( CMD_HF_ISO15693_FINDAFI , PM3_SUCCESS , NULL , 0 ) ;
2019-11-27 15:11:43 +02:00
}
2010-10-19 14:25:17 +00:00
}
// Allows to directly send commands to the tag via the client
2020-07-02 12:37:07 +02:00
// OBS: doesn't turn off rf field afterwards.
2019-03-10 11:20:22 +01:00
void DirectTag15693Command ( uint32_t datalen , uint32_t speed , uint32_t recv , uint8_t * data ) {
2017-09-04 13:56:57 +02:00
2020-07-09 19:41:57 +02:00
LED_A_ON ( ) ;
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t timeout ;
2020-10-13 22:43:28 +02:00
uint32_t eof_time = 0 ;
2020-07-02 12:37:07 +02:00
bool request_answer = false ;
2020-08-13 12:25:04 +02:00
2020-07-09 19:41:57 +02:00
switch ( data [ 1 ] ) {
2021-05-03 09:35:38 +02:00
case ISO15693_WRITEBLOCK :
case ISO15693_LOCKBLOCK :
case ISO15693_WRITE_MULTI_BLOCK :
case ISO15693_WRITE_AFI :
case ISO15693_LOCK_AFI :
case ISO15693_WRITE_DSFID :
case ISO15693_LOCK_DSFID :
2020-07-09 19:41:57 +02:00
timeout = ISO15693_READER_TIMEOUT_WRITE ;
request_answer = data [ 0 ] & ISO15_REQ_OPTION ;
break ;
default :
timeout = ISO15693_READER_TIMEOUT ;
2020-08-13 12:25:04 +02:00
}
2019-03-09 20:34:41 +01:00
2020-08-14 14:56:20 +02:00
uint32_t start_time = 0 ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( data , datalen , true , speed , ( recv ? recvbuf : NULL ) , sizeof ( recvbuf ) , start_time , timeout , & eof_time , & recvlen ) ;
if ( res = = PM3_ETEAROFF ) { // tearoff occurred
reply_ng ( CMD_HF_ISO15693_COMMAND , res , NULL , 0 ) ;
2020-10-13 22:43:28 +02:00
} else {
2020-07-02 12:37:07 +02:00
2022-03-16 15:45:18 +01:00
bool fsk = data [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ;
bool recv_speed = data [ 0 ] & ISO15_REQ_DATARATE_HIGH ;
2020-10-13 22:43:28 +02:00
// send a single EOF to get the tag response
if ( request_answer ) {
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2022-03-23 17:37:40 +01:00
res = SendDataTagEOF ( ( recv ? recvbuf : NULL ) , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT , & eof_time , fsk , recv_speed , & recvlen ) ;
2020-07-09 19:41:57 +02:00
}
2020-08-17 08:52:24 +02:00
2020-10-13 22:43:28 +02:00
if ( recv ) {
2020-10-20 01:00:23 +02:00
recvlen = MIN ( recvlen , ISO15693_MAX_RESPONSE_LENGTH ) ;
2022-03-23 17:37:40 +01:00
reply_ng ( CMD_HF_ISO15693_COMMAND , res , recvbuf , recvlen ) ;
2020-10-13 22:43:28 +02:00
} else {
2022-03-23 17:37:40 +01:00
reply_ng ( CMD_HF_ISO15693_COMMAND , PM3_SUCCESS , NULL , 0 ) ;
2020-07-09 19:41:57 +02:00
}
2019-03-09 20:34:41 +01:00
}
2022-03-23 17:37:40 +01:00
2020-10-13 22:43:28 +02:00
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
2021-12-27 17:39:56 +01:00
// also prevents hf 15 raw -k keep_field on ...
2020-10-13 22:43:28 +02:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LED_D_OFF ( ) ;
2019-03-12 00:12:26 +01:00
}
2020-07-02 12:37:07 +02:00
2020-08-17 08:52:24 +02:00
/*
SLIx functions from official master forks .
void LockPassSlixIso15693 ( uint32_t pass_id , uint32_t password ) {
LED_A_ON ( ) ;
2020-09-07 10:39:15 +02:00
2020-10-06 20:44:23 +02:00
uint8_t cmd_inventory [ ] = { ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1 , 0x01 , 0x00 , 0x00 , 0x00 } ;
uint8_t cmd_get_rnd [ ] = { ISO15693_REQ_DATARATE_HIGH , 0xB2 , 0x04 , 0x00 , 0x00 } ;
uint8_t cmd_set_pass [ ] = { ISO15693_REQ_DATARATE_HIGH , 0xB3 , 0x04 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
//uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t cmd_lock_pass [ ] = { ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS , 0xB5 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x00 , 0x00 } ;
uint16_t crc ;
2022-03-23 18:22:03 +01:00
uint16_t recvlen = 0 ;
2020-10-06 20:44:23 +02:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint32_t start_time = 0 ;
bool done = false ;
2022-03-23 17:37:40 +01:00
int res ;
2020-10-06 20:44:23 +02:00
// setup 'get random number' command
crc = Iso15693Crc ( cmd_get_rnd , 3 ) ;
cmd_get_rnd [ 3 ] = crc & 0xff ;
cmd_get_rnd [ 4 ] = crc > > 8 ;
Dbprintf ( " LockPass: Press button lock password, long-press to terminate. " ) ;
while ( ! done ) {
LED_D_ON ( ) ;
switch ( BUTTON_HELD ( 1000 ) ) {
case BUTTON_SINGLE_CLICK :
Dbprintf ( " LockPass: Reset 'DONE'-LED (A) " ) ;
LED_A_OFF ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
break ;
case BUTTON_HOLD :
Dbprintf ( " LockPass: Terminating " ) ;
done = true ;
break ;
default :
SpinDelay ( 50 ) ;
continue ;
}
if ( done ) [
break ;
}
2022-03-23 17:37:40 +01:00
res = SendDataTag ( cmd_get_rnd , sizeof ( cmd_get_rnd ) , true , true , recvbuf , sizeof ( recvbuf ) , start_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 5 ) {
2020-10-06 20:44:23 +02:00
LED_C_ON ( ) ;
} else {
Dbprintf ( " LockPass: Received random 0x%02X%02X (%d) " , recvbuf [ 1 ] , recvbuf [ 2 ] , recvlen ) ;
// setup 'set password' command
cmd_set_pass [ 4 ] = ( ( password > > 0 ) & 0xFF ) ^ recvbuf [ 1 ] ;
cmd_set_pass [ 5 ] = ( ( password > > 8 ) & 0xFF ) ^ recvbuf [ 2 ] ;
cmd_set_pass [ 6 ] = ( ( password > > 16 ) & 0xFF ) ^ recvbuf [ 1 ] ;
cmd_set_pass [ 7 ] = ( ( password > > 24 ) & 0xFF ) ^ recvbuf [ 2 ] ;
crc = Iso15693Crc ( cmd_set_pass , 8 ) ;
cmd_set_pass [ 8 ] = crc & 0xff ;
cmd_set_pass [ 9 ] = crc > > 8 ;
Dbprintf ( " LockPass: Sending old password to end privacy mode " , cmd_set_pass [ 4 ] , cmd_set_pass [ 5 ] , cmd_set_pass [ 6 ] , cmd_set_pass [ 7 ] ) ;
2022-03-23 17:37:40 +01:00
res = SendDataTag ( cmd_set_pass , sizeof ( cmd_set_pass ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2020-10-06 20:44:23 +02:00
Dbprintf ( " LockPass: Failed to set password (%d) " , recvlen ) ;
LED_B_ON ( ) ;
} else {
crc = Iso15693Crc ( cmd_inventory , 3 ) ;
cmd_inventory [ 3 ] = crc & 0xff ;
cmd_inventory [ 4 ] = crc > > 8 ;
Dbprintf ( " LockPass: Searching for tag... " ) ;
2022-03-23 17:37:40 +01:00
res = SendDataTag ( cmd_inventory , sizeof ( cmd_inventory ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 12 ) {
2020-10-06 20:44:23 +02:00
Dbprintf ( " LockPass: Failed to read inventory (%d) " , recvlen ) ;
LED_B_ON ( ) ;
LED_C_ON ( ) ;
} else {
Dbprintf ( " LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X " , recvbuf [ 9 ] , recvbuf [ 8 ] , recvbuf [ 7 ] , recvbuf [ 6 ] , recvbuf [ 5 ] , recvbuf [ 4 ] , recvbuf [ 3 ] , recvbuf [ 2 ] ) ;
memcpy ( & cmd_lock_pass [ 3 ] , & recvbuf [ 2 ] , 8 ) ;
cmd_lock_pass [ 8 + 3 ] = pass_id ;
crc = Iso15693Crc ( cmd_lock_pass , 8 + 4 ) ;
cmd_lock_pass [ 8 + 4 ] = crc & 0xff ;
cmd_lock_pass [ 8 + 5 ] = crc > > 8 ;
Dbprintf ( " LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X " , cmd_set_pass [ 4 ] , cmd_set_pass [ 5 ] , cmd_set_pass [ 6 ] , cmd_set_pass [ 7 ] , pass_id ) ;
2022-03-23 17:37:40 +01:00
res = SendDataTag ( cmd_lock_pass , sizeof ( cmd_lock_pass ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2020-10-06 20:44:23 +02:00
Dbprintf ( " LockPass: Failed to lock password (%d) " , recvlen ) ;
} else {
Dbprintf ( " LockPass: Successful (%d) " , recvlen ) ;
}
LED_A_ON ( ) ;
}
} }
}
Dbprintf ( " LockPass: Finishing " ) ;
cmd_send ( CMD_ACK , recvlen , 0 , 0 , recvbuf , recvlen ) ;
2020-08-17 08:52:24 +02:00
}
*/
2020-07-02 12:37:07 +02:00
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card.
//
//-----------------------------------------------------------------------------
// Set the UID on Magic ISO15693 tag (based on Iceman's LUA-script).
2022-01-06 15:40:11 +01:00
void SetTag15693Uid ( const uint8_t * uid ) {
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
LED_A_ON ( ) ;
2020-07-02 12:37:07 +02:00
2020-07-09 19:41:57 +02:00
uint8_t cmd [ 4 ] [ 9 ] = {
2021-05-03 09:35:38 +02:00
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x3e , 0x00 , 0x00 , 0x00 , 0x00 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x3f , 0x69 , 0x96 , 0x00 , 0x00 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x38 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x39 }
2020-07-09 19:41:57 +02:00
} ;
2020-08-17 08:52:24 +02:00
// Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X)
2020-07-09 19:41:57 +02:00
cmd [ 2 ] [ 3 ] = uid [ 7 ] ;
cmd [ 2 ] [ 4 ] = uid [ 6 ] ;
cmd [ 2 ] [ 5 ] = uid [ 5 ] ;
cmd [ 2 ] [ 6 ] = uid [ 4 ] ;
2020-08-17 08:52:24 +02:00
// Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X)
2020-07-09 19:41:57 +02:00
cmd [ 3 ] [ 3 ] = uid [ 3 ] ;
cmd [ 3 ] [ 4 ] = uid [ 2 ] ;
cmd [ 3 ] [ 5 ] = uid [ 1 ] ;
cmd [ 3 ] [ 6 ] = uid [ 0 ] ;
2020-07-02 12:37:07 +02:00
AddCrc15 ( cmd [ 0 ] , 7 ) ;
AddCrc15 ( cmd [ 1 ] , 7 ) ;
AddCrc15 ( cmd [ 2 ] , 7 ) ;
AddCrc15 ( cmd [ 3 ] , 7 ) ;
2020-08-17 08:52:24 +02:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2020-08-13 12:25:04 +02:00
2020-08-17 08:52:24 +02:00
uint32_t start_time = 0 ;
uint32_t eof_time = 0 ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = PM3_SUCCESS ;
2020-07-09 19:41:57 +02:00
for ( int i = 0 ; i < 4 ; i + + ) {
2022-03-23 17:37:40 +01:00
res = SendDataTag (
2022-03-23 18:22:03 +01:00
cmd [ i ] ,
sizeof ( cmd [ i ] ) ,
( i = = 0 ) ? true : false ,
true ,
recvbuf ,
sizeof ( recvbuf ) ,
start_time ,
ISO15693_READER_TIMEOUT_WRITE ,
& eof_time ,
& recvlen ) ;
2020-07-09 19:41:57 +02:00
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
}
2020-09-07 10:39:15 +02:00
2022-03-23 17:37:40 +01:00
reply_ng ( CMD_HF_ISO15693_CSETUID , res , NULL , 0 ) ;
2020-08-17 08:52:24 +02:00
switch_off ( ) ;
2020-09-07 10:39:15 +02:00
}
2021-05-04 09:40:30 +02:00
2022-01-06 15:40:11 +01:00
static void init_password_15693_slixl ( uint8_t * buffer , uint8_t * pwd , const uint8_t * rnd ) {
2021-05-04 09:40:30 +02:00
memcpy ( buffer , pwd , 4 ) ;
2021-05-05 21:04:48 +02:00
if ( rnd ) {
buffer [ 0 ] ^ = rnd [ 0 ] ;
buffer [ 1 ] ^ = rnd [ 1 ] ;
buffer [ 2 ] ^ = rnd [ 0 ] ;
buffer [ 3 ] ^ = rnd [ 1 ] ;
}
2021-05-04 09:40:30 +02:00
}
static bool get_rnd_15693_slixl ( uint32_t start_time , uint32_t * eof_time , uint8_t * rnd ) {
// 0x04, == NXP from manufacture id list.
2021-05-05 21:04:48 +02:00
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , ISO15693_GET_RANDOM_NUMBER , 0x04 , 0x00 , 0x00 } ;
AddCrc15 ( c , 3 ) ;
2021-05-04 09:40:30 +02:00
2021-05-05 21:04:48 +02:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( c , sizeof ( c ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 5 ) {
2021-05-05 21:04:48 +02:00
return false ;
}
2021-05-04 09:40:30 +02:00
2021-05-05 21:04:48 +02:00
if ( rnd ) {
memcpy ( rnd , & recvbuf [ 1 ] , 2 ) ;
}
return true ;
2021-05-04 09:40:30 +02:00
}
static uint32_t set_pass_15693_slixl ( uint32_t start_time , uint32_t * eof_time , uint8_t pass_id , uint8_t * password ) {
2021-05-05 21:04:48 +02:00
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_slixl ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
2021-05-04 09:40:30 +02:00
// 0x04, == NXP from manufacture id list.
2021-05-05 21:04:48 +02:00
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , ISO15693_SET_PASSWORD , 0x04 , pass_id , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
init_password_15693_slixl ( & c [ 4 ] , password , rnd ) ;
AddCrc15 ( c , 8 ) ;
2021-05-04 09:40:30 +02:00
2021-05-05 21:04:48 +02:00
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( c , sizeof ( c ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2021-05-05 21:04:48 +02:00
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2021-05-04 09:40:30 +02:00
}
/*
static uint32_t enable_privacy_15693_slixl ( uint32_t start_time , uint32_t * eof_time , uint8_t * uid , uint8_t pass_id , uint8_t * password ) {
2021-06-04 21:56:47 +02:00
uint8_t rnd [ 2 ] ;
2021-05-04 09:40:30 +02:00
if ( get_rnd_15693_slixl ( start_time , eof_time , rnd ) = = false ) {
2021-06-04 21:56:47 +02:00
return PM3_ETIMEOUT ;
}
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS , ISO15693_ENABLE_PRIVACY , pass_id , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
memcpy ( & c [ 3 ] , uid , 8 ) ;
init_password_15693_slixl ( & c [ 11 ] , password , rnd ) ;
AddCrc15 ( c , 15 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0
int res = SendDataTag ( c , sizeof ( c ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2021-06-04 21:56:47 +02:00
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2021-05-04 09:40:30 +02:00
}
static uint32_t write_password_15693_slixl ( uint32_t start_time , uint32_t * eof_time , uint8_t * uid , uint8_t pass_id , uint8_t * password ) {
2021-06-04 21:56:47 +02:00
uint8_t rnd [ 2 ] ;
2021-05-04 09:40:30 +02:00
if ( get_rnd_15693_slixl ( start_time , eof_time , rnd ) = = false ) {
2021-06-04 21:56:47 +02:00
return PM3_ETIMEOUT ;
}
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS , ISO15693_WRITE_PASSWORD , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
memcpy ( & c [ 3 ] , uid , 8 ) ;
c [ 11 ] = pass_id ;
init_password_15693_slixl ( & c [ 12 ] , password , NULL ) ;
AddCrc15 ( c , 16 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( c , sizeof ( c ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2021-06-04 21:56:47 +02:00
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2021-05-04 09:40:30 +02:00
}
static uint32_t destroy_15693_slixl ( uint32_t start_time , uint32_t * eof_time , uint8_t * uid , uint8_t * password ) {
2021-06-04 21:56:47 +02:00
uint8_t rnd [ 2 ] ;
2021-05-04 09:40:30 +02:00
if ( get_rnd_15693_slixl ( start_time , eof_time , rnd ) = = false ) {
2021-06-04 21:56:47 +02:00
return PM3_ETIMEOUT ;
}
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS , ISO15693_DESTROY , ISO15693_ENABLE_PRIVACY , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
memcpy ( & c [ 3 ] , uid , 8 ) ;
init_password_15693_slixl ( & c [ 11 ] , password , rnd ) ;
AddCrc15 ( c , 15 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-23 17:37:40 +01:00
uint16_t recvlen = 0 ;
int res = SendDataTag ( c , sizeof ( c ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
2021-06-04 21:56:47 +02:00
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2021-05-04 09:40:30 +02:00
}
*/
2022-02-18 18:23:53 +01:00
// Sets a PRIVACY password to all ZEROS
2021-05-04 09:40:30 +02:00
void DisablePrivacySlixLIso15693 ( uint8_t * password ) {
2021-05-05 21:04:48 +02:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
2022-02-18 18:23:53 +01:00
// Password identifier Password byte
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
2022-02-18 11:47:20 +01:00
int res = set_pass_15693_slixl ( start_time , & eof_time , 0x04 , password ) ;
2021-05-04 09:40:30 +02:00
reply_ng ( CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY , res , NULL , 0 ) ;
switch_off ( ) ;
}
2022-02-18 18:23:53 +01:00
// Sets a EAS/AFI password to all ZEROS
void DisableEAS_AFISlixLIso15693 ( uint8_t * password ) {
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
// Password identifier Password byte
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
int res = set_pass_15693_slixl ( start_time , & eof_time , 0x10 , password ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_L_DISABLE_AESAFI , res , NULL , 0 ) ;
switch_off ( ) ;
}
2021-05-04 09:40:30 +02:00