2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2010-02-21 08:12:52 +08:00
// Jonathan Westhues, split Nov 2006
// Modified by Greg Jones, Jan 2009
2012-06-21 01:20:21 +08:00
// Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011
2020-08-17 14:52:24 +08:00
// Modified by Christian Herrmann "iceman", 2017, 2020
2020-07-02 18:37:07 +08:00
// Modified by piwi, Oct 2018
2010-02-21 08:12:52 +08:00
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
2010-02-21 05:24:25 +08:00
// Routines to support ISO 15693. This includes both the reader software and
2020-07-02 18:37:07 +08:00
// the `fake tag' modes.
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2020-07-02 18:37:07 +08: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 22:25:17 +08:00
//
// VCD (reader) -> VICC (tag)
// 1 out of 256:
2019-03-10 03:34:41 +08:00
// data rate: 1,66 kbit/s (fc/8192)
// used for long range
2010-10-19 22:25:17 +08:00
// 1 out of 4:
2019-03-10 03:34:41 +08:00
// data rate: 26,48 kbit/s (fc/512)
// used for short range, high speed
2019-03-09 15:59:13 +08:00
//
2010-10-19 22:25:17 +08:00
// VICC (tag) -> VCD (reader)
// Modulation:
2019-08-06 19:51:10 +08:00
// ASK / one subcarrier (423,75 kHz)
// FSK / two subcarriers (423,75 kHz && 484,28 kHz)
2010-10-19 22:25:17 +08:00
// Data Rates / Modes:
2019-03-10 03:34:41 +08: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 22:25:17 +08: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 18:37:07 +08:00
// *) signal decoding is unable to detect collisions.
// *) add anti-collision support for inventory-commands
2012-06-21 01:20:21 +08:00
// *) read security status of a block
2020-07-02 18:37:07 +08:00
// *) sniffing and simulation do not support two subcarrier modes.
// *) remove or refactor code under "deprecated"
2010-10-19 22:25:17 +08:00
// *) document all the functions
2019-08-08 22:57:33 +08:00
# include "iso15693.h"
# include "proxmark3_arm.h"
2010-02-21 06:51:00 +08:00
# include "util.h"
2010-02-21 08:10:28 +08:00
# include "string.h"
2010-10-19 22:25:17 +08:00
# include "iso15693tools.h"
2012-12-05 07:39:18 +08:00
# include "cmd.h"
2019-08-08 22:57:33 +08: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 18:25:04 +08:00
2020-07-02 18:37:07 +08: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-04 03:33:17 +08:00
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when sniffing. All values should be multiples of 16
2020-07-02 18:37:07 +08: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 14:52:24 +08:00
# define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us
2020-07-02 18:37:07 +08:00
# define ISO15693_READER_TIMEOUT_WRITE 4700 // 4700/212kHz = 22ms, nominal 20ms
2020-09-07 16:39:15 +08:00
// iceman: This defines below exists in the header file, just here for my easy reading
2020-08-17 14:52:24 +08: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-21 05:24:25 +08:00
2010-10-19 22:25:17 +08:00
///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 2 - Air Interface
2020-07-02 18:37:07 +08:00
// This section basically contains transmission and receiving of bits
2010-10-19 22:25:17 +08:00
///////////////////////////////////////////////////////////////////////
2020-07-02 18:37:07 +08: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 15:59:13 +08:00
// 32 + 2 crc + 1
2020-12-02 05:28:37 +08: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
# define CMD_READBLOCK_RESP 7
2017-09-05 04:48:35 +08:00
2019-04-07 18:07:50 +08: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 22:19:47 +08:00
2020-07-02 18:37:07 +08:00
static void BuildIdentifyRequest ( uint8_t * cmd ) ;
2017-09-04 19:56:57 +08:00
2020-08-13 18:25:04 +08:00
// ---------------------------
2020-07-21 16:51:48 +08:00
2019-03-09 15:59:13 +08:00
// Signal Processing
2010-10-19 22:25:17 +08:00
// ---------------------------
// prepare data using "1 out of 4" code for later transmission
2020-07-02 18:37:07 +08:00
// resulting data rate is 26.48 kbit/s (fc/512)
2010-10-19 22:25:17 +08:00
// cmd ... data
2020-08-13 18:25:04 +08:00
// n ... length of data
static uint8_t encode15_lut [ ] = {
0x40 , // 01000000
0x10 , // 00010000
0x04 , // 00000100
0x01 // 00000001
2020-07-21 16:51:48 +08:00
} ;
2020-07-04 03:33:17 +08:00
void CodeIso15693AsReader ( uint8_t * cmd , int n ) {
2020-07-02 18:37:07 +08:00
2020-07-13 23:56:19 +08:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-07-10 01:41:57 +08:00
// SOF for 1of4
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0x84 ; //10000100
2020-07-10 01:41:57 +08:00
// data
for ( int i = 0 ; i < n ; i + + ) {
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
volatile uint8_t b = ( cmd [ i ] > > 0 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08: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 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
b = ( cmd [ i ] > > 6 ) & 0x03 ;
ts - > buf [ + + ts - > max ] = encode15_lut [ b ] ;
2020-07-10 01:41:57 +08:00
}
// EOF
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0x20 ; //0010 + 0000 padding
ts - > max + + ;
2010-02-21 05:24:25 +08:00
}
2020-07-02 18:37:07 +08:00
// Encode EOF only
static void CodeIso15693AsReaderEOF ( void ) {
2020-07-13 23:56:19 +08:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
ts - > buf [ + + ts - > max ] = 0x20 ;
ts - > max + + ;
2020-07-02 18:37:07 +08:00
}
// encode data using "1 out of 256" scheme
2019-03-09 15:59:13 +08:00
// data rate is 1,66 kbit/s (fc/8192)
2010-10-19 22:25:17 +08:00
// is designed for more robust communication over longer distances
2019-03-10 18:20:22 +08:00
static void CodeIso15693AsReader256 ( uint8_t * cmd , int n ) {
2010-02-21 05:24:25 +08:00
2020-07-13 23:56:19 +08:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
// SOF for 1of256
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0x81 ; //10000001
2019-03-10 03:34:41 +08:00
2020-07-10 01:41:57 +08:00
// data
2020-08-13 18:25:04 +08:00
for ( int i = 0 ; i < n ; i + + ) {
2020-07-10 01:41:57 +08:00
for ( int j = 0 ; j < = 255 ; j + + ) {
if ( cmd [ i ] = = j ) {
2020-07-13 23:56:19 +08:00
tosend_stuffbit ( 0 ) ;
tosend_stuffbit ( 1 ) ;
2020-07-10 01:41:57 +08:00
} else {
2020-07-13 23:56:19 +08:00
tosend_stuffbit ( 0 ) ;
tosend_stuffbit ( 0 ) ;
2020-07-10 01:41:57 +08:00
}
}
}
2010-02-21 05:24:25 +08:00
2020-07-10 01:41:57 +08:00
// EOF
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0x20 ; //0010 + 0000 padding
ts - > max + + ;
2010-02-21 05:24:25 +08:00
}
2020-08-13 18:25:04 +08:00
static const uint8_t encode_4bits [ 16 ] = {
2020-08-03 23:42:05 +08:00
// 0 1 2 3
2020-07-13 18:28:01 +08:00
0xaa , 0x6a , 0x9a , 0x5a ,
2020-08-03 23:42:05 +08:00
// 4 5 6 7
2020-07-13 18:28:01 +08:00
0xa6 , 0x66 , 0x96 , 0x56 ,
2020-08-03 23:42:05 +08:00
// 8 9 A B
2020-07-13 18:28:01 +08:00
0xa9 , 0x69 , 0x99 , 0x59 ,
2020-08-03 23:42:05 +08:00
// C D E F
2020-07-13 18:28:01 +08:00
0xa5 , 0x65 , 0x95 , 0x55
} ;
2020-07-02 18:37:07 +08:00
2020-07-04 03:33:17 +08:00
void CodeIso15693AsTag ( uint8_t * cmd , size_t len ) {
2020-07-10 01:41:57 +08: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 23:56:19 +08:00
tosend_reset ( ) ;
tosend_t * ts = get_tosend ( ) ;
2020-07-10 01:41:57 +08:00
// SOF
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0x1D ; // 00011101
2020-07-10 01:41:57 +08:00
// data
2020-08-03 23:42:05 +08:00
for ( int i = 0 ; i < len ; i + = 2 ) {
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i ] & 0xF ] ;
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i ] > > 4 ] ;
2020-08-03 23:42:05 +08:00
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i + 1 ] & 0xF ] ;
ts - > buf [ + + ts - > max ] = encode_4bits [ cmd [ i + 1 ] > > 4 ] ;
2020-07-10 01:41:57 +08:00
}
// EOF
2020-07-13 23:56:19 +08:00
ts - > buf [ + + ts - > max ] = 0xB8 ; // 10111000
ts - > max + + ;
2010-02-21 05:24:25 +08:00
}
2020-07-02 18:37:07 +08:00
// Transmit the command (to the tag) that was placed in cmd[].
2020-07-04 03:33:17 +08:00
void TransmitTo15693Tag ( const uint8_t * cmd , int len , uint32_t * start_time ) {
2019-03-09 15:59:13 +08:00
2020-07-10 01:41:57 +08: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-20 02:45:47 +08:00
// wait
while ( GetCountSspClk ( ) < * start_time ) ;
2020-07-10 01:41:57 +08:00
LED_B_ON ( ) ;
for ( int c = 0 ; c < len ; c + + ) {
2020-07-13 18:28:01 +08:00
volatile uint8_t data = cmd [ c ] ;
2020-07-20 02:45:47 +08:00
2020-07-13 18:28:01 +08:00
for ( uint8_t i = 0 ; i < 8 ; i + + ) {
2020-07-10 01:41:57 +08: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-14 04:43:28 +08:00
FpgaDisableTracing ( ) ;
2017-09-04 19:56:57 +08:00
}
2020-07-02 18:37:07 +08:00
//-----------------------------------------------------------------------------
2020-07-10 01:41:57 +08:00
// Transmit the tag response (to the reader) that was placed in cmd[].
2020-07-02 18:37:07 +08:00
//-----------------------------------------------------------------------------
2020-07-04 03:33:17 +08:00
void TransmitTo15693Reader ( const uint8_t * cmd , size_t len , uint32_t * start_time , uint32_t slot_time , bool slow ) {
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08: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 18:25:04 +08:00
2020-07-10 01:41:57 +08: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-20 02:45:47 +08:00
// wait
while ( GetCountSspClk ( ) < ( modulation_start_time & 0xfffffff8 ) ) ;
2020-07-10 01:41:57 +08: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 18:25:04 +08:00
uint8_t bits_to_send = 0x00 ;
2020-07-10 01:41:57 +08:00
for ( size_t c = 0 ; c < len ; c + + ) {
2020-07-15 21:16:35 +08:00
for ( int i = ( c = = 0 ? 4 : 7 ) ; i > = 0 ; i - - ) {
2020-07-20 02:45:47 +08:00
2020-07-10 01:41:57 +08:00
uint8_t cmd_bits = ( ( cmd [ c ] > > i ) & 0x01 ) ? 0xff : 0x00 ;
2020-07-20 02:45:47 +08:00
2020-08-13 18:25:04 +08:00
for ( int j = 0 ; j < ( slow ? 4 : 1 ) ; ) {
2020-07-10 01:41:57 +08: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 23:42:05 +08:00
2020-07-10 01:41:57 +08:00
// send the remaining bits, padded with 0:
bits_to_send = bits_to_shift < < ( 8 - shift_delay ) ;
2020-08-03 23:42:05 +08:00
if ( bits_to_send ) {
2020-08-13 18:25:04 +08:00
for ( ; ; ) {
2020-08-03 23:42:05 +08:00
if ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXRDY ) {
AT91C_BASE_SSC - > SSC_THR = bits_to_send ;
break ;
}
2020-07-10 01:41:57 +08:00
}
}
LED_C_OFF ( ) ;
2010-02-21 05:24:25 +08:00
}
2020-07-02 18:37:07 +08: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 16:51:48 +08:00
typedef struct {
2020-07-10 01:41:57 +08: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 ;
uint8_t * output ;
int len ;
int sum1 ;
int sum2 ;
int threshold_sof ;
int threshold_half ;
uint16_t previous_amplitude ;
2020-07-02 18:37:07 +08:00
} DecodeTag_t ;
2010-10-19 22:25:17 +08:00
2020-07-02 18:37:07 +08:00
//-----------------------------------------------------------------------------
// DEMODULATE tag answer
//-----------------------------------------------------------------------------
2020-07-21 16:51:48 +08:00
static RAMFUNC int Handle15693SamplesFromTag ( uint16_t amplitude , DecodeTag_t * tag ) {
switch ( tag - > state ) {
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_SOF_LOW : {
2020-07-10 01:41:57 +08:00
// waiting for a rising edge
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
2020-07-10 01:41:57 +08:00
}
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
tag - > previous_amplitude = amplitude ;
2020-07-10 01:41:57 +08:00
}
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_SOF_RISING_EDGE : {
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 2 ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
tag - > threshold_sof = ( amplitude - tag - > previous_amplitude ) / 2 ;
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 2 ;
tag - > threshold_sof = tag - > threshold_sof / 2 ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
tag - > state = STATE_TAG_SOF_HIGH ;
2020-07-10 01:41:57 +08:00
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_SOF_HIGH : {
2020-07-10 01:41:57 +08:00
// waiting for 10 times high. Take average over the last 8
2020-07-21 16:51:48 +08:00
if ( amplitude > tag - > threshold_sof ) {
tag - > posCount + + ;
if ( tag - > posCount > 2 ) {
tag - > threshold_half + = amplitude ; // keep track of average high value
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 10 ) {
tag - > threshold_half > > = 2 ; // (4 times 1/2 average)
tag - > state = STATE_TAG_SOF_HIGH_END ;
2020-07-10 01:41:57 +08:00
}
} else { // high phase was too short
2020-07-21 16:51:48 +08:00
tag - > posCount = 1 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
}
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_SOF_HIGH_END : {
2020-07-10 01:41:57 +08:00
// check for falling edge
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 13 & & amplitude < tag - > threshold_sof ) {
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-10 01:41:57 +08:00
LED_C_ON ( ) ;
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
if ( tag - > posCount > 13 ) { // high phase too long
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
}
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_RECEIVING_DATA : {
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount < = 4 ) {
tag - > sum1 + = amplitude ;
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > sum2 + = amplitude ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 8 ) {
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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
2020-07-21 16:51:48 +08:00
} else if ( tag - > sum1 < tag - > threshold_half & & tag - > sum2 > tag - > threshold_half ) { // modulation in second half
2020-07-10 01:41:57 +08:00
// logic 1
2020-07-21 16:51:48 +08:00
if ( tag - > lastBit = = SOF_PART1 ) { // still part of SOF
tag - > lastBit = SOF_PART2 ; // SOF completed
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > lastBit = LOGIC1 ;
tag - > shiftReg > > = 1 ;
tag - > shiftReg | = 0x80 ;
tag - > bitCount + + ;
if ( tag - > bitCount = = 8 ) {
tag - > output [ tag - > len ] = tag - > shiftReg ;
tag - > len + + ;
2020-08-19 22:26:26 +08:00
if ( tag - > len > tag - > max_len ) {
2020-07-10 01:41:57 +08:00
// buffer overflow, give up
LED_C_OFF ( ) ;
return true ;
}
2020-07-21 16:51:48 +08:00
tag - > bitCount = 0 ;
tag - > shiftReg = 0 ;
2020-07-10 01:41:57 +08:00
}
}
2020-07-21 16:51:48 +08:00
} else if ( tag - > sum1 > tag - > threshold_half & & tag - > sum2 < tag - > threshold_half ) { // modulation in first half
2020-07-10 01:41:57 +08:00
// logic 0
2020-07-21 16:51:48 +08:00
if ( tag - > lastBit = = SOF_PART1 ) { // incomplete SOF
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
} else {
2020-07-21 16:51:48 +08:00
tag - > lastBit = LOGIC0 ;
tag - > shiftReg > > = 1 ;
tag - > bitCount + + ;
if ( tag - > bitCount = = 8 ) {
tag - > output [ tag - > len ] = tag - > shiftReg ;
tag - > len + + ;
2020-08-19 22:26:26 +08:00
if ( tag - > len > tag - > max_len ) {
2020-07-10 01:41:57 +08:00
// buffer overflow, give up
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
2020-07-21 16:51:48 +08:00
tag - > bitCount = 0 ;
tag - > shiftReg = 0 ;
2020-07-10 01:41:57 +08:00
}
}
} else { // no modulation
2020-07-21 16:51:48 +08:00
if ( tag - > lastBit = = SOF_PART2 ) { // only SOF (this is OK for iClass)
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
return true ;
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
}
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
2020-07-10 01:41:57 +08:00
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_EOF : {
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount < = 4 ) {
tag - > sum1 + = amplitude ;
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > sum2 + = amplitude ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 8 ) {
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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
}
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
2020-07-10 01:41:57 +08:00
break ;
2020-07-20 02:45:47 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
case STATE_TAG_EOF_TAIL : {
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 1 ) {
tag - > sum1 = 0 ;
tag - > sum2 = 0 ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount < = 4 ) {
tag - > sum1 + = amplitude ;
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
tag - > sum2 + = amplitude ;
2020-07-10 01:41:57 +08:00
}
2020-08-12 03:40:22 +08:00
2020-07-21 16:51:48 +08:00
if ( tag - > posCount = = 8 ) {
if ( tag - > sum1 < tag - > threshold_half & & tag - > sum2 < tag - > threshold_half ) { // no modulation in both halves
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
return true ;
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount = 0 ;
tag - > previous_amplitude = amplitude ;
tag - > state = STATE_TAG_SOF_LOW ;
2020-07-10 01:41:57 +08:00
LED_C_OFF ( ) ;
}
}
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
2020-07-10 01:41:57 +08:00
break ;
2020-07-20 02:45:47 +08:00
}
2020-07-10 01:41:57 +08:00
}
return false ;
2020-07-02 18:37:07 +08:00
}
2010-02-21 05:24:25 +08:00
2020-07-21 16:51:48 +08: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 18:37:07 +08:00
}
2017-09-04 19:56:57 +08:00
2020-07-21 16:51:48 +08: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 18:37:07 +08:00
}
2019-03-09 15:59:13 +08:00
2020-07-02 18:37:07 +08:00
/*
* Receive and decode the tag response , also log to tracebuffer
*/
2020-08-13 18:25:04 +08:00
int GetIso15693AnswerFromTag ( uint8_t * response , uint16_t max_len , uint16_t timeout , uint32_t * eof_time ) {
2020-07-02 18:37:07 +08:00
2020-07-13 23:56:19 +08:00
int samples = 0 , ret = 0 ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
// the Decoder data structure
2020-08-03 23:42:05 +08:00
DecodeTag_t dtm = { 0 } ;
DecodeTag_t * dt = & dtm ;
DecodeTagInit ( dt , response , max_len ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
// And put the FPGA in the appropriate mode
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
// Setup and start DMA.
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
2020-07-15 21:16:35 +08:00
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
2020-07-21 16:51:48 +08:00
// Setup and start DMA.
if ( FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
if ( DBGLEVEL > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
return - 4 ;
}
2020-07-15 21:16:35 +08:00
2020-07-10 01:41:57 +08:00
uint32_t dma_start_time = 0 ;
2020-07-15 21:16:35 +08:00
uint16_t * upTo = dma - > buf ;
2020-07-02 18:37:07 +08:00
2020-08-13 18:25:04 +08:00
for ( ; ; ) {
2020-07-02 18:37:07 +08:00
2020-08-13 18:25:04 +08:00
volatile uint16_t behindBy = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
if ( behindBy = = 0 )
2020-07-13 23:56:19 +08:00
continue ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
samples + + ;
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
2020-07-02 18:37:07 +08:00
2020-07-13 18:28:01 +08:00
volatile uint16_t tagdata = * upTo + + ;
2020-07-02 18:37:07 +08:00
2020-07-15 21:16:35 +08:00
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
2020-08-14 20:56:20 +08: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-09-07 16:39:15 +08:00
2020-08-14 20:56:20 +08:00
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
DbpString ( " stopped " ) ;
break ;
}
2020-07-10 01:41:57 +08:00
}
}
2020-07-02 18:37:07 +08:00
2020-08-03 23:42:05 +08:00
if ( Handle15693SamplesFromTag ( tagdata , dt ) ) {
2020-08-14 20:56:20 +08:00
2020-07-10 01:41:57 +08:00
* eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM ; // end of EOF
2020-08-14 20:56:20 +08:00
2020-08-03 23:42:05 +08:00
if ( dt - > lastBit = = SOF_PART2 ) {
2020-07-10 01:41:57 +08:00
* eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2020-08-19 22:11:44 +08:00
if ( dt - > len > dt - > max_len ) {
2020-07-10 01:41:57 +08:00
ret = - 2 ; // buffer overflow
2020-08-19 22:22:56 +08:00
Dbprintf ( " overflow (%d > %d " , dt - > len , dt - > max_len ) ;
2020-07-10 01:41:57 +08:00
}
break ;
}
2020-07-02 18:37:07 +08:00
2020-08-14 20:56:20 +08:00
// timeout
2020-08-03 23:42:05 +08:00
if ( samples > timeout & & dt - > state < STATE_TAG_RECEIVING_DATA ) {
2020-09-07 16:39:15 +08:00
ret = - 3 ;
2020-07-10 01:41:57 +08:00
break ;
}
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
}
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
FpgaDisableSscDma ( ) ;
2020-10-14 04:43:28 +08:00
FpgaDisableTracing ( ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
uint32_t sof_time = * eof_time
2020-08-03 23:42:05 +08:00
- ( dt - > len * 8 * 8 * 16 ) // time for byte transfers
2020-07-10 22:37:56 +08:00
- ( 32 * 16 ) // time for SOF transfer
2020-08-03 23:42:05 +08:00
- ( dt - > lastBit ! = SOF_PART2 ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
if ( DBGLEVEL > = DBG_EXTENDED ) {
2020-07-20 02:45:47 +08:00
Dbprintf ( " samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d, maxlen = %u " ,
2020-08-13 18:25:04 +08:00
samples ,
ret ,
dt - > state ,
dt - > lastBit ,
dt - > len ,
dt - > bitCount ,
dt - > posCount ,
dt - > max_len
2020-07-10 01:41:57 +08:00
) ;
Dbprintf ( " timing: sof_time = %d, eof_time = %d " , ( sof_time * 4 ) , ( * eof_time * 4 ) ) ;
}
2020-07-02 18:37:07 +08:00
2020-07-21 16:51:48 +08:00
if ( ret < 0 ) {
2020-07-10 01:41:57 +08:00
return ret ;
}
2020-08-19 22:22:56 +08:00
LogTrace_ISO15693 ( dt - > output , dt - > len , ( sof_time * 4 ) , ( * eof_time * 4 ) , NULL , false ) ;
2020-08-03 23:42:05 +08:00
return dt - > len ;
2020-07-02 18:37:07 +08:00
}
2017-08-21 23:17:43 +08:00
2010-02-21 05:24:25 +08:00
2020-07-02 18:37:07 +08: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 16:51:48 +08:00
typedef struct {
2020-07-10 01:41:57 +08: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 18:37:07 +08:00
} DecodeReader_t ;
2020-08-13 18:25:04 +08: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 16:51:48 +08: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 18:37:07 +08:00
}
2019-03-09 15:59:13 +08:00
2020-08-13 18:25:04 +08:00
static void DecodeReaderReset ( DecodeReader_t * reader ) {
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_UNSYNCD ;
2020-07-02 18:37:07 +08:00
}
2010-02-21 05:24:25 +08:00
2020-08-12 03:40:22 +08:00
//static inline __attribute__((always_inline))
2020-08-13 18:25:04 +08:00
static int RAMFUNC Handle15693SampleFromReader ( bool bit , DecodeReader_t * reader ) {
2020-07-21 16:51:48 +08:00
switch ( reader - > state ) {
2020-07-10 01:41:57 +08:00
case STATE_READER_UNSYNCD :
// wait for unmodulated carrier
if ( bit ) {
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-10 01:41:57 +08: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 16:51:48 +08:00
reader - > posCount = 1 ;
reader - > state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF ;
2020-07-10 01:41:57 +08:00
}
break ;
case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
2020-07-10 01:41:57 +08:00
if ( bit ) { // detected rising edge
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else { // SOF
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF ;
2020-07-10 01:41:57 +08:00
}
} else {
2020-07-21 16:51:48 +08:00
if ( reader - > posCount > 5 ) { // stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
} else {
// do nothing, keep waiting
}
}
break ;
case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
if ( bit = = false ) { // detected a falling edge
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else { // SOF for 1 out of 256 coding
2020-07-21 16:51:48 +08:00
reader - > Coding = CODING_1_OUT_OF_256 ;
reader - > state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
if ( reader - > posCount > 29 ) { // stayed high for too long
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
2020-07-10 01:41:57 +08:00
} else {
// do nothing, keep waiting
}
}
break ;
case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
2020-07-10 01:41:57 +08:00
if ( bit ) { // detected rising edge
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
LED_B_ON ( ) ;
}
} else { // CODING_1_OUT_OF_4
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
reader - > posCount = 1 ;
reader - > state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 ;
2020-07-10 01:41:57 +08:00
}
}
} else {
2020-07-21 16:51:48 +08:00
if ( reader - > Coding = = CODING_1_OUT_OF_256 ) {
if ( reader - > posCount > 34 ) { // signal stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
} else {
// do nothing, keep waiting
}
} else { // CODING_1_OUT_OF_4
2020-07-21 16:51:48 +08:00
if ( reader - > posCount > 26 ) { // signal stayed low for too long
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
} else {
// do nothing, keep waiting
}
}
}
break ;
case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
2020-07-10 01:41:57 +08:00
if ( bit ) {
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
LED_B_ON ( ) ;
} else {
// do nothing, keep waiting
}
} else { // unexpected falling edge
2020-08-13 18:25:04 +08:00
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
}
break ;
case STATE_READER_RECEIVE_DATA_1_OUT_OF_4 :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
if ( reader - > posCount = = 1 ) {
reader - > sum1 = bit ? 1 : 0 ;
} else if ( reader - > posCount < = 4 ) {
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
if ( bit )
reader - > sum1 + + ;
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
} else if ( reader - > posCount = = 5 ) {
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
reader - > sum2 = bit ? 1 : 0 ;
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
if ( bit )
reader - > sum2 + + ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( reader - > posCount = = 8 ) {
reader - > posCount = 0 ;
if ( reader - > sum1 < = 1 & & reader - > sum2 > = 3 ) { // EOF
2020-07-10 01:41:57 +08:00
LED_B_OFF ( ) ; // Finished receiving
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount ! = 0 ) {
2020-07-10 01:41:57 +08:00
return true ;
}
2020-07-21 16:51:48 +08:00
} else if ( reader - > sum1 > = 3 & & reader - > sum2 < = 1 ) { // detected a 2bit position
reader - > shiftReg > > = 2 ;
reader - > shiftReg | = ( reader - > bitCount < < 6 ) ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( reader - > bitCount = = 15 ) { // we have a full byte
reader - > output [ reader - > byteCount + + ] = reader - > shiftReg ;
if ( reader - > byteCount > reader - > byteCountMax ) {
2020-07-10 01:41:57 +08:00
// buffer overflow, give up
LED_B_OFF ( ) ;
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM ) ;
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_RECEIVE_JAMMING ;
2020-07-10 01:41:57 +08:00
}
}
2020-07-21 16:51:48 +08:00
2020-07-10 01:41:57 +08:00
} else {
2020-07-21 16:51:48 +08:00
reader - > bitCount + + ;
2020-07-10 01:41:57 +08:00
}
}
break ;
case STATE_READER_RECEIVE_DATA_1_OUT_OF_256 :
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
} else if ( bit ) {
2020-07-21 16:51:48 +08:00
reader - > sum2 + + ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( reader - > posCount = = 8 ) {
reader - > posCount = 0 ;
if ( reader - > sum1 < = 1 & & reader - > sum2 > = 3 ) { // EOF
2020-07-10 01:41:57 +08:00
LED_B_OFF ( ) ; // Finished receiving
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount ! = 0 ) {
2020-07-10 01:41:57 +08:00
return true ;
}
2020-07-21 16:51:48 +08:00
} else if ( reader - > sum1 > = 3 & & reader - > sum2 < = 1 ) { // detected the bit position
reader - > shiftReg = reader - > bitCount ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( reader - > bitCount = = 255 ) { // we have a full byte
reader - > output [ reader - > byteCount + + ] = reader - > shiftReg ;
if ( reader - > byteCount > reader - > byteCountMax ) {
2020-07-10 01:41:57 +08:00
// buffer overflow, give up
LED_B_OFF ( ) ;
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
}
2020-07-21 16:51:48 +08:00
if ( reader - > byteCount = = reader - > jam_search_len ) {
if ( ! memcmp ( reader - > output , reader - > jam_search_string , reader - > jam_search_len ) ) {
2020-07-10 01:41:57 +08:00
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM ) ;
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_RECEIVE_JAMMING ;
2020-07-10 01:41:57 +08:00
}
}
}
2020-07-21 16:51:48 +08:00
reader - > bitCount + + ;
2020-07-10 01:41:57 +08:00
}
break ;
case STATE_READER_RECEIVE_JAMMING :
2020-07-21 16:51:48 +08:00
reader - > posCount + + ;
if ( reader - > Coding = = CODING_1_OUT_OF_4 ) {
if ( reader - > posCount = = 7 * 16 ) { // 7 bits jammed
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ) ; // stop jamming
// FpgaDisableTracing();
LED_D_OFF ( ) ;
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
}
} else {
2020-07-21 16:51:48 +08:00
if ( reader - > posCount = = 7 * 256 ) { // 7 bits jammend
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ) ; // stop jamming
LED_D_OFF ( ) ;
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
}
}
break ;
default :
LED_B_OFF ( ) ;
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
break ;
}
return false ;
2020-07-02 18:37:07 +08:00
}
2017-09-04 19:56:57 +08:00
2020-07-02 18:37:07 +08: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 15:59:13 +08:00
2020-07-04 03:33:17 +08:00
int GetIso15693CommandFromReader ( uint8_t * received , size_t max_len , uint32_t * eof_time ) {
2020-07-10 01:41:57 +08:00
int samples = 0 ;
bool gotFrame = false ;
// the decoder data structure
2020-08-03 23:42:05 +08:00
DecodeReader_t * dr = ( DecodeReader_t * ) BigBuf_malloc ( sizeof ( DecodeReader_t ) ) ;
DecodeReaderInit ( dr , received , max_len , 0 , NULL ) ;
2020-07-10 01:41:57 +08: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 21:16:35 +08:00
dmabuf8_t * dma = get_dma8 ( ) ;
2020-07-21 16:51:48 +08:00
if ( FpgaSetupSscDma ( dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
if ( DBGLEVEL > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
return - 4 ;
}
2020-07-15 21:16:35 +08:00
uint8_t * upTo = dma - > buf ;
2020-07-10 01:41:57 +08:00
2020-08-06 22:17:08 +08:00
uint32_t dma_start_time = GetCountSspClk ( ) & 0xfffffff8 ;
2020-07-10 01:41:57 +08:00
2020-07-21 16:51:48 +08:00
for ( ; ; ) {
2020-08-13 18:25:04 +08:00
volatile uint16_t behindBy = ( ( uint8_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
2020-07-10 01:41:57 +08:00
if ( behindBy = = 0 ) continue ;
2020-08-13 18:25:04 +08:00
2020-07-21 16:51:48 +08:00
if ( samples = = 0 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
2020-07-10 01:41:57 +08:00
2020-07-13 18:28:01 +08:00
volatile uint8_t b = * upTo + + ;
2020-07-15 21:16:35 +08:00
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) { // we have read all of the DMA buffer content.
2020-08-06 22:17:08 +08:00
upTo = dma - > buf ; // start reading the circular buffer from the beginning
2020-07-15 21:16:35 +08:00
if ( behindBy > ( 9 * DMA_BUFFER_SIZE / 10 ) ) {
2020-07-13 18:28:01 +08:00
Dbprintf ( " About to blow circular buffer - aborted! behindBy %d " , behindBy ) ;
2020-07-10 01:41:57 +08:00
break ;
}
}
2020-08-06 22:17:08 +08: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-10 01:41:57 +08:00
}
for ( int i = 7 ; i > = 0 ; i - - ) {
2020-08-03 23:42:05 +08:00
if ( Handle15693SampleFromReader ( ( b > > i ) & 0x01 , dr ) ) {
2020-07-10 01:41:57 +08:00
* eof_time = dma_start_time + samples - DELAY_READER_TO_ARM ; // end of EOF
gotFrame = true ;
break ;
}
samples + + ;
}
2020-07-21 16:51:48 +08:00
if ( gotFrame ) {
break ;
}
2020-07-10 01:41:57 +08:00
if ( BUTTON_PRESS ( ) ) {
2020-08-03 23:42:05 +08:00
dr - > byteCount = - 1 ;
2020-07-10 01:41:57 +08:00
break ;
}
WDT_HIT ( ) ;
}
FpgaDisableSscDma ( ) ;
2020-07-20 02:45:47 +08:00
if ( DBGLEVEL > = DBG_EXTENDED ) {
Dbprintf ( " samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d " ,
2020-08-13 18:25:04 +08:00
samples , gotFrame , dr - > state , dr - > byteCount ,
dr - > bitCount , dr - > posCount ) ;
2020-07-20 02:45:47 +08:00
}
2020-07-10 01:41:57 +08:00
2020-08-03 23:42:05 +08:00
if ( dr - > byteCount > = 0 ) {
2020-07-10 01:41:57 +08:00
uint32_t sof_time = * eof_time
2020-08-13 18:25:04 +08: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 23:42:05 +08:00
LogTrace_ISO15693 ( dr - > output , dr - > byteCount , ( sof_time * 32 ) , ( * eof_time * 32 ) , NULL , true ) ;
2020-07-10 01:41:57 +08:00
}
2020-08-03 23:42:05 +08:00
return dr - > byteCount ;
2010-02-21 05:24:25 +08: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 18:20:22 +08:00
void AcquireRawAdcSamplesIso15693 ( void ) {
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
uint8_t * dest = BigBuf_malloc ( 4000 ) ;
2010-02-21 05:24:25 +08:00
2020-07-10 01:41:57 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER ) ;
LED_D_ON ( ) ;
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2019-03-09 15:59:13 +08:00
2020-07-10 01:41:57 +08:00
uint8_t cmd [ 5 ] ;
BuildIdentifyRequest ( cmd ) ;
CodeIso15693AsReader ( cmd , sizeof ( cmd ) ) ;
2010-02-21 05:24:25 +08:00
2020-07-10 01:41:57 +08:00
// Give the tags time to energize
SpinDelay ( 100 ) ;
2016-08-05 03:37:43 +08:00
2020-07-10 01:41:57 +08:00
// Now send the command
2020-07-13 23:56:19 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-07-10 01:41:57 +08:00
uint32_t start_time = 0 ;
2020-07-13 23:56:19 +08:00
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
2019-03-09 15:59:13 +08:00
2020-07-10 01:41:57 +08:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) ;
2019-03-09 15:59:13 +08:00
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ) ;
2019-03-09 15:59:13 +08:00
2020-08-13 18:25:04 +08:00
for ( int c = 0 ; c < 4000 ; ) {
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
2020-07-10 01:41:57 +08:00
uint16_t r = AT91C_BASE_SSC - > SSC_RHR ;
dest [ c + + ] = r > > 5 ;
}
}
2019-03-09 15:59:13 +08:00
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2010-10-19 22:25:17 +08:00
}
2020-07-02 18:37:07 +08:00
void SniffIso15693 ( uint8_t jam_search_len , uint8_t * jam_search_string ) {
2020-08-14 20:56:20 +08:00
LEDsoff ( ) ;
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2020-08-14 20:56:20 +08:00
DbpString ( " Starting to sniff. Press PM3 Button to stop. " ) ;
2020-07-21 16:51:48 +08:00
BigBuf_free ( ) ;
2020-07-10 01:41:57 +08:00
clear_trace ( ) ;
set_tracing ( true ) ;
2020-08-13 18:25:04 +08:00
2020-08-03 23:42:05 +08:00
DecodeTag_t dtag = { 0 } ;
uint8_t response [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
DecodeTagInit ( & dtag , response , sizeof ( response ) ) ;
2020-07-10 01:41:57 +08:00
2020-08-03 23:42:05 +08: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-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ) ;
LED_D_OFF ( ) ;
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
2020-08-14 20:56:20 +08:00
2020-07-10 01:41:57 +08:00
StartCountSspClk ( ) ;
2020-08-14 20:56:20 +08:00
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
2020-07-21 16:51:48 +08:00
// Setup and start DMA.
2020-08-12 03:40:22 +08:00
if ( FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
2020-08-14 20:56:20 +08:00
if ( DBGLEVEL > DBG_ERROR ) DbpString ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-07-21 16:51:48 +08:00
switch_off ( ) ;
return ;
}
2020-08-12 03:40:22 +08:00
2020-07-20 02:45:47 +08:00
bool tag_is_active = false ;
bool reader_is_active = false ;
bool expect_tag_answer = false ;
2020-07-21 16:51:48 +08:00
int dma_start_time = 0 ;
2020-08-12 03:40:22 +08:00
// Count of samples received so far, so that we can include timing
int samples = 0 ;
2020-08-13 18:25:04 +08:00
2020-08-12 03:40:22 +08:00
uint16_t * upTo = dma - > buf ;
2020-07-10 01:41:57 +08:00
2020-08-12 03:40:22 +08:00
for ( ; ; ) {
2020-08-08 17:41:26 +08:00
2020-08-13 18:25:04 +08:00
volatile int behind_by = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
2020-08-12 03:40:22 +08:00
if ( behind_by < 1 ) continue ;
2020-08-08 17:41:26 +08:00
2020-07-10 01:41:57 +08:00
samples + + ;
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
}
2020-07-21 16:51:48 +08:00
2020-08-12 03:40:22 +08:00
volatile uint16_t sniffdata = * upTo + + ;
2020-07-21 16:51:48 +08:00
2020-08-12 03:40:22 +08:00
// we have read all of the DMA buffer content
2020-08-13 18:25:04 +08:00
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) {
2020-07-21 16:51:48 +08:00
2020-08-12 03:40:22 +08:00
// start reading the circular buffer from the beginning
2020-08-13 18:25:04 +08:00
upTo = dma - > buf ;
2020-08-12 03:40:22 +08: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 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
2020-08-08 17:41:26 +08:00
DbpString ( " Sniff stopped " ) ;
2020-07-10 01:41:57 +08:00
break ;
}
}
}
2020-07-10 22:37:56 +08:00
// no need to try decoding reader data if the tag is sending
2020-07-20 02:45:47 +08:00
if ( tag_is_active = = false ) {
2020-07-10 22:37:56 +08:00
2020-08-12 03:40:22 +08:00
if ( Handle15693SampleFromReader ( ( sniffdata & 0x02 ) > > 1 , & dreader ) ) {
2020-07-10 01:41:57 +08:00
2020-07-10 22:37:56 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 8 - DELAY_READER_TO_ARM_SNIFF ; // end of EOF
2020-08-03 23:42:05 +08:00
if ( dreader . byteCount > 0 ) {
2020-07-10 01:41:57 +08:00
uint32_t sof_time = eof_time
2020-08-13 18:25:04 +08: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 23:42:05 +08:00
LogTrace_ISO15693 ( dreader . output , dreader . byteCount , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
2020-07-10 01:41:57 +08:00
}
// And ready to receive another command.
2020-08-03 23:42:05 +08:00
DecodeReaderReset ( & dreader ) ;
DecodeTagReset ( & dtag ) ;
2020-07-20 02:45:47 +08:00
reader_is_active = false ;
expect_tag_answer = true ;
2020-07-10 01:41:57 +08:00
2020-08-03 23:42:05 +08:00
} else if ( Handle15693SampleFromReader ( sniffdata & 0x01 , & dreader ) ) {
2020-07-10 01:41:57 +08:00
2020-07-10 22:37:56 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 16 - DELAY_READER_TO_ARM_SNIFF ; // end of EOF
2020-08-03 23:42:05 +08:00
if ( dreader . byteCount > 0 ) {
2020-07-10 01:41:57 +08:00
uint32_t sof_time = eof_time
2020-08-13 18:25:04 +08: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 23:42:05 +08:00
LogTrace_ISO15693 ( dreader . output , dreader . byteCount , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
2020-07-10 01:41:57 +08:00
}
// And ready to receive another command
2020-08-03 23:42:05 +08:00
DecodeReaderReset ( & dreader ) ;
DecodeTagReset ( & dtag ) ;
2020-07-20 02:45:47 +08:00
reader_is_active = false ;
expect_tag_answer = true ;
2020-07-10 01:41:57 +08:00
} else {
2020-08-03 23:42:05 +08:00
reader_is_active = ( dreader . state > = STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ) ;
2020-07-10 01:41:57 +08:00
}
}
2020-07-21 16:51:48 +08:00
if ( reader_is_active = = false & & expect_tag_answer ) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet
2020-08-03 23:42:05 +08:00
if ( Handle15693SamplesFromTag ( sniffdata > > 2 , & dtag ) ) {
2020-07-10 01:41:57 +08:00
2020-07-10 22:37:56 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM_SNIFF ; // end of EOF
2020-08-03 23:42:05 +08:00
if ( dtag . lastBit = = SOF_PART2 ) {
2020-07-10 22:37:56 +08:00
eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
2020-07-10 01:41:57 +08:00
}
uint32_t sof_time = eof_time
2020-08-03 23:42:05 +08:00
- dtag . len * 8 * 8 * 16 // time for byte transfers
2020-07-10 22:37:56 +08:00
- ( 32 * 16 ) // time for SOF transfer
2020-08-03 23:42:05 +08:00
- ( dtag . lastBit ! = SOF_PART2 ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
2020-07-10 22:37:56 +08:00
2020-08-03 23:42:05 +08:00
LogTrace_ISO15693 ( dtag . output , dtag . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
2020-07-10 01:41:57 +08:00
// And ready to receive another response.
2020-08-03 23:42:05 +08:00
DecodeTagReset ( & dtag ) ;
DecodeReaderReset ( & dreader ) ;
2020-07-20 02:45:47 +08:00
expect_tag_answer = false ;
tag_is_active = false ;
2020-07-10 01:41:57 +08:00
} else {
2020-08-03 23:42:05 +08:00
tag_is_active = ( dtag . state > = STATE_TAG_RECEIVING_DATA ) ;
2020-07-10 01:41:57 +08:00
}
}
}
2020-07-21 16:51:48 +08:00
2020-08-08 17:41:26 +08:00
FpgaDisableTracing ( ) ;
2020-07-20 02:45:47 +08:00
switch_off ( ) ;
2020-07-10 01:41:57 +08:00
2020-08-12 03:40:22 +08:00
DbpString ( " " ) ;
2020-08-08 17:41:26 +08:00
DbpString ( _CYAN_ ( " Sniff statistics " ) ) ;
2020-08-12 03:40:22 +08:00
DbpString ( " ================================= " ) ;
2020-08-08 17:41:26 +08:00
Dbprintf ( " DecodeTag State........%d " , dtag . state ) ;
Dbprintf ( " DecodeTag byteCnt......%d " , dtag . len ) ;
Dbprintf ( " DecodeTag posCount.....%d " , dtag . posCount ) ;
Dbprintf ( " DecodeReader State.....%d " , dreader . state ) ;
Dbprintf ( " DecodeReader byteCnt...%d " , dreader . byteCount ) ;
Dbprintf ( " DecodeReader posCount..%d " , dreader . posCount ) ;
2020-08-12 03:40:22 +08:00
Dbprintf ( " Trace length........... " _YELLOW_ ( " %d " ) , BigBuf_get_traceLen ( ) ) ;
2020-08-13 18:25:04 +08:00
DbpString ( " " ) ;
2020-08-08 17:41:26 +08:00
2010-10-19 22:25:17 +08:00
}
2020-07-10 01:41:57 +08:00
// Initialize Proxmark3 as ISO15693 reader
2019-03-10 18:20:22 +08:00
void Iso15693InitReader ( void ) {
2020-07-20 02:45:47 +08:00
2020-08-13 18:25:04 +08:00
LEDsoff ( ) ;
2019-03-10 03:34:41 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2010-10-19 22:25:17 +08:00
2019-03-10 03:34:41 +08:00
// Start from off (no field generated)
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
2020-07-20 02:45:47 +08:00
SpinDelay ( 10 ) ;
2010-10-19 22:25:17 +08:00
2020-07-10 01:41:57 +08:00
// switch field on
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER ) ;
LED_D_ON ( ) ;
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
// initialize SSC and select proper AD input
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2020-07-13 23:56:19 +08:00
set_tracing ( true ) ;
2020-07-10 01:41:57 +08:00
// give tags some time to energize
2020-07-20 02:45:47 +08:00
SpinDelay ( 250 ) ;
2020-07-10 01:41:57 +08:00
StartCountSspClk ( ) ;
2010-10-19 22:25:17 +08:00
}
///////////////////////////////////////////////////////////////////////
// ISO 15693 Part 3 - Air Interface
// This section basicly contains transmission and receiving of bits
///////////////////////////////////////////////////////////////////////
2020-07-02 18:37:07 +08:00
// Encode an identify request, which is the first
2010-10-19 22:25:17 +08:00
// thing that you must send to a tag to get a response.
2019-04-07 02:21:03 +08:00
// It expects "cmdout" to be at least CMD_ID_RESP large
2020-07-02 18:37:07 +08:00
// When READER:
static void BuildIdentifyRequest ( uint8_t * cmd ) {
2019-03-10 03:34:41 +08:00
// flags
cmd [ 0 ] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1 ;
2020-07-10 01:41:57 +08:00
// inventory command code
cmd [ 1 ] = ISO15_CMD_INVENTORY ;
// no mask
cmd [ 2 ] = 0x00 ;
2019-03-10 03:34:41 +08:00
// CRC
2019-04-07 18:07:50 +08:00
AddCrc15 ( cmd , 3 ) ;
2010-10-19 22:25:17 +08:00
}
2012-06-21 01:20:21 +08:00
// Universal Method for sending to and recv bytes from a tag
2019-03-10 03:34:41 +08: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-24 03:40:01 +08:00
// return: length of received data
2017-09-04 19:56:57 +08:00
// logging enabled
2020-08-13 18:25:04 +08:00
int SendDataTag ( uint8_t * send , int sendlen , bool init , bool speed_fast , uint8_t * recv ,
2020-07-02 18:37:07 +08:00
uint16_t max_recv_len , uint32_t start_time , uint16_t timeout , uint32_t * eof_time ) {
2020-07-10 01:41:57 +08:00
if ( init ) {
Iso15693InitReader ( ) ;
2020-08-14 20:56:20 +08:00
start_time = GetCountSspClk ( ) ;
2020-07-10 01:41:57 +08:00
}
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
if ( speed_fast ) {
// high speed (1 out of 4)
CodeIso15693AsReader ( send , sendlen ) ;
} else {
// low speed (1 out of 256)
CodeIso15693AsReader256 ( send , sendlen ) ;
}
2020-10-14 04:43:28 +08:00
int res = 0 ;
2020-07-13 23:56:19 +08:00
tosend_t * ts = get_tosend ( ) ;
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
2020-10-20 07:00:23 +08:00
2020-10-14 04:43:28 +08:00
if ( tearoff_hook ( ) = = PM3_ETEAROFF ) { // tearoff occured
2020-07-02 18:37:07 +08:00
2020-10-14 04:43:28 +08:00
res = PM3_ETEAROFF ;
} else {
2020-10-20 07:00:23 +08:00
2020-10-14 04:43:28 +08:00
* eof_time = start_time + 32 * ( ( 8 * ts - > max ) - 4 ) ; // substract the 4 padding bits after EOF
LogTrace_ISO15693 ( send , sendlen , ( start_time * 4 ) , ( * eof_time * 4 ) , NULL , true ) ;
if ( recv ! = NULL ) {
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time ) ;
}
2020-07-10 01:41:57 +08:00
}
return res ;
2020-07-02 18:37:07 +08:00
}
2019-03-09 15:59:13 +08:00
2020-07-02 18:37:07 +08:00
int SendDataTagEOF ( uint8_t * recv , uint16_t max_recv_len , uint32_t start_time , uint16_t timeout , uint32_t * eof_time ) {
2015-06-30 04:36:55 +08:00
2020-07-10 01:41:57 +08:00
CodeIso15693AsReaderEOF ( ) ;
2020-07-13 23:56:19 +08:00
tosend_t * ts = get_tosend ( ) ;
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time ) ;
uint32_t end_time = start_time + 32 * ( 8 * ts - > max - 4 ) ; // substract the 4 padding bits after EOF
2020-07-21 16:51:48 +08:00
LogTrace_ISO15693 ( NULL , 0 , ( start_time * 4 ) , ( end_time * 4 ) , NULL , true ) ;
2017-09-04 19:56:57 +08:00
2020-07-10 01:41:57 +08:00
int res = 0 ;
if ( recv ! = NULL ) {
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time ) ;
}
return res ;
2010-10-19 22:25:17 +08:00
}
2010-02-21 05:24:25 +08:00
2010-10-19 22:25:17 +08:00
// --------------------------------------------------------------------
2019-03-09 15:59:13 +08:00
// Debug Functions
2010-10-19 22:25:17 +08:00
// --------------------------------------------------------------------
2010-02-21 05:24:25 +08:00
2010-10-19 22:25:17 +08:00
// Decodes a message from a tag and displays its metadata and content
# define DBD15STATLEN 48
2020-05-10 22:59:38 +08:00
static void DbdecodeIso15693Answer ( int len , uint8_t * d ) {
2019-03-10 03:34:41 +08:00
if ( len > 3 ) {
2020-07-02 18:37:07 +08:00
2019-06-08 00:41:39 +08:00
char status [ DBD15STATLEN + 1 ] = { 0 } ;
2020-07-02 18:37:07 +08:00
if ( d [ 0 ] & ISO15_RES_EXT )
2019-03-13 02:18:16 +08:00
strncat ( status , " ProtExt " , DBD15STATLEN - strlen ( status ) ) ;
2020-07-02 18:37:07 +08:00
if ( d [ 0 ] & ISO15_RES_ERROR ) {
2019-03-10 03:34:41 +08:00
// error
2019-03-13 02:18:16 +08:00
strncat ( status , " Error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
switch ( d [ 1 ] ) {
case 0x01 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 01: not supported " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x02 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 02: not recognized " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x03 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 03: opt not supported " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x0f :
2019-03-13 02:18:16 +08:00
strncat ( status , " 0F: no info " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x10 :
2019-09-14 23:50:58 +08:00
strncat ( status , " 10: don't exist " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x11 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 11: lock again " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x12 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 12: locked " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x13 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 13: program error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
case 0x14 :
2019-03-13 02:18:16 +08:00
strncat ( status , " 14: lock error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
break ;
default :
2019-03-13 02:18:16 +08:00
strncat ( status , " unknown error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
}
2019-03-13 02:18:16 +08:00
strncat ( status , " " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
} else {
2019-03-13 02:18:16 +08:00
strncat ( status , " No error " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
}
2019-04-07 18:10:52 +08:00
if ( CheckCrc15 ( d , len ) )
2020-07-02 18:37:07 +08:00
strncat ( status , " [+] crc ( " _GREEN_ ( " OK " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
else
2020-07-02 18:37:07 +08:00
strncat ( status , " [!] crc ( " _RED_ ( " fail " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
2019-06-06 16:05:09 +08:00
if ( DBGLEVEL > = DBG_ERROR ) Dbprintf ( " %s " , status ) ;
2019-03-10 03:34:41 +08:00
}
2010-02-21 05:24:25 +08:00
}
2010-10-19 22:25:17 +08:00
///////////////////////////////////////////////////////////////////////
// Functions called via USB/Client
///////////////////////////////////////////////////////////////////////
2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2017-09-04 19:56:57 +08:00
// Act as ISO15693 reader, perform anti-collision and then attempt to read a sector
2010-02-21 05:24:25 +08:00
// all demodulation performed in arm rather than host. - greg
//-----------------------------------------------------------------------------
2017-09-04 19:56:57 +08:00
// ok
// parameter is unused !?!
2019-03-10 18:20:22 +08:00
void ReaderIso15693 ( uint32_t parameter ) {
2019-03-10 03:34:41 +08:00
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
set_tracing ( true ) ;
2019-03-10 03:34:41 +08:00
2020-07-10 01:41:57 +08:00
uint8_t * answer = BigBuf_malloc ( ISO15693_MAX_RESPONSE_LENGTH ) ;
2020-07-02 18:37:07 +08:00
memset ( answer , 0x00 , ISO15693_MAX_RESPONSE_LENGTH ) ;
2019-03-10 03:34:41 +08:00
2020-07-10 01:41:57 +08:00
// FIRST WE RUN AN INVENTORY TO GET THE TAG UID
// THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
2019-03-10 03:34:41 +08:00
2020-07-10 01:41:57 +08:00
// Send the IDENTIFY command
uint8_t cmd [ 5 ] = { 0 } ;
BuildIdentifyRequest ( cmd ) ;
uint32_t start_time = 0 ;
uint32_t eof_time ;
2020-10-14 04:43:28 +08:00
int recvlen = SendDataTag ( cmd , sizeof ( cmd ) , true , true , answer , ISO15693_MAX_RESPONSE_LENGTH , start_time , ISO15693_READER_TIMEOUT , & eof_time ) ;
2020-10-20 07:00:23 +08:00
2020-10-14 04:43:28 +08:00
if ( recvlen = = PM3_ETEAROFF ) { // tearoff occured
reply_mix ( CMD_ACK , recvlen , 0 , 0 , NULL , 0 ) ;
} else {
2020-10-20 07:00:23 +08:00
2020-10-14 04:43:28 +08:00
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2019-03-10 03:34:41 +08:00
2020-10-14 04:43:28 +08: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 ] ;
if ( DBGLEVEL > = DBG_EXTENDED ) {
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.
reply_mix ( CMD_ACK , 1 , sizeof ( uid ) , 0 , uid , sizeof ( uid ) ) ;
if ( DBGLEVEL > = DBG_EXTENDED ) {
Dbprintf ( " [+] %d octets read from IDENTIFY request: " , recvlen ) ;
DbdecodeIso15693Answer ( recvlen , answer ) ;
Dbhexdump ( recvlen , answer , true ) ;
}
} else {
DbpString ( " Failed to select card " ) ;
2020-10-20 07:00:23 +08:00
reply_mix ( CMD_ACK , 0 , 0 , 0 , NULL , 0 ) ;
2019-03-10 03:34:41 +08:00
}
}
switch_off ( ) ;
2020-07-02 18:37:07 +08:00
BigBuf_free ( ) ;
}
// When SIM: initialize the Proxmark3 as ISO15693 tag
2020-07-04 03:33:17 +08:00
void Iso15693InitTag ( void ) {
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
// 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-20 02:45:47 +08:00
clear_trace ( ) ;
2020-07-13 18:28:01 +08:00
set_tracing ( true ) ;
2020-07-10 01:41:57 +08:00
StartCountSspClk ( ) ;
2010-02-21 05:24:25 +08:00
}
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
// all demodulation performed in arm rather than host. - greg
2020-07-02 18:37:07 +08:00
void SimTagIso15693 ( uint8_t * uid ) {
2019-03-09 15:59:13 +08:00
2020-07-20 02:45:47 +08:00
// free eventually allocated BigBuf memory
BigBuf_free_keep_EM ( ) ;
2020-07-10 01:41:57 +08:00
Iso15693InitTag ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
LED_A_ON ( ) ;
2010-02-21 05:24:25 +08:00
2019-03-10 03:34:41 +08:00
Dbprintf ( " ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X " , uid [ 0 ] , uid [ 1 ] , uid [ 2 ] , uid [ 3 ] , uid [ 4 ] , uid [ 5 ] , uid [ 6 ] , uid [ 7 ] ) ;
2010-02-21 05:24:25 +08:00
2019-03-10 03:34:41 +08:00
LED_C_ON ( ) ;
2010-02-21 05:24:25 +08:00
2020-07-20 02:45:47 +08:00
2020-07-13 23:56:19 +08:00
2020-07-20 02:45:47 +08:00
enum { NO_FIELD , IDLE , ACTIVATED , SELECTED , HALTED } chip_state = NO_FIELD ;
2020-08-13 18:25:04 +08:00
2020-07-20 02:45:47 +08:00
bool button_pressed = false ;
2020-08-13 18:25:04 +08:00
int vHf = 0 ; // in mV
2020-07-20 02:45:47 +08:00
bool exit_loop = false ;
while ( exit_loop = = false ) {
2020-10-23 16:00:47 +08:00
button_pressed = BUTTON_PRESS ( ) ;
if ( button_pressed | | data_available ( ) )
break ;
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
2019-03-09 15:59:13 +08:00
2020-07-20 02:45:47 +08:00
// find reader field
if ( chip_state = = NO_FIELD ) {
# if defined RDV4
vHf = ( MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc ( ADC_CHAN_HF_RDV40 , 32 ) ) > > 15 ;
# else
vHf = ( MAX_ADC_HF_VOLTAGE * SumAdc ( ADC_CHAN_HF , 32 ) ) > > 15 ;
# endif
if ( vHf > MF_MINFIELDV ) {
chip_state = IDLE ;
LED_A_ON ( ) ;
} else {
2020-08-13 18:25:04 +08:00
continue ;
2020-07-20 02:45:47 +08:00
}
}
2019-03-10 03:34:41 +08:00
// Listen to reader
2020-07-10 01:41:57 +08:00
uint8_t cmd [ ISO15693_MAX_COMMAND_LENGTH ] ;
2020-07-20 02:45:47 +08:00
uint32_t reader_eof_time = 0 ;
int cmd_len = GetIso15693CommandFromReader ( cmd , sizeof ( cmd ) , & reader_eof_time ) ;
if ( cmd_len < 0 ) {
button_pressed = true ;
exit_loop = true ;
break ;
2020-07-10 01:41:57 +08:00
}
2019-03-09 15:59:13 +08:00
2020-07-20 02:45:47 +08:00
// TODO: check more flags
if ( ( cmd_len > = 5 ) & & ( cmd [ 0 ] & ISO15_REQ_INVENTORY ) & & ( cmd [ 1 ] = = ISO15_CMD_INVENTORY ) ) {
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-02 05:42:22 +08: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 ] ;
// CRC
AddCrc15 ( resp_inv , 10 ) ;
CodeIso15693AsTag ( resp_inv , CMD_INV_RESP ) ;
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-12-02 05:28:37 +08:00
2020-07-20 02:45:47 +08:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
2020-07-21 16:51:48 +08:00
LogTrace_ISO15693 ( resp_inv , CMD_INV_RESP , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
2020-08-13 18:25:04 +08:00
2020-07-20 02:45:47 +08:00
chip_state = SELECTED ;
2019-03-10 03:34:41 +08:00
}
2020-12-02 05:28:37 +08:00
// GET_SYSTEM_INFO
if ( ( cmd [ 1 ] = = ISO15_CMD_SYSINFO ) ) {
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-02 05:42:22 +08:00
// Build GET_SYSTEM_INFO command
uint8_t resp_sysinfo [ CMD_SYSINFO_RESP ] = { 0 } ;
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
resp_sysinfo [ 0 ] = 0 ; // Response flags.
2020-12-02 06:56:08 +08:00
resp_sysinfo [ 1 ] = 0x0F ; // Information flags (0x0F - DSFID, AFI, Mem size, IC)
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08: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-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
resp_sysinfo [ 10 ] = 0 ; // DSFID
resp_sysinfo [ 11 ] = 0 ; // AFI
2020-12-02 05:28:37 +08:00
2020-12-02 06:56:08 +08:00
resp_sysinfo [ 12 ] = 0x1B ; // Memory size.
resp_sysinfo [ 13 ] = 0x03 ; // Memory size.
resp_sysinfo [ 14 ] = 0x01 ; // IC reference.
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
// CRC
AddCrc15 ( resp_sysinfo , 15 ) ;
CodeIso15693AsTag ( resp_sysinfo , CMD_SYSINFO_RESP ) ;
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-12-02 05:28:37 +08: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 ) ;
}
// READ_BLOCK
if ( ( cmd [ 1 ] = = ISO15_CMD_READ ) ) {
bool slow = ! ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) ;
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
2020-12-02 05:42:22 +08:00
// Build GET_SYSTEM_INFO command
uint8_t resp_readblock [ CMD_READBLOCK_RESP ] = { 0 } ;
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
resp_readblock [ 0 ] = 0 ; // Response flags.
resp_readblock [ 1 ] = 0 ; // Block data.
resp_readblock [ 2 ] = 0 ; // Block data.
resp_readblock [ 3 ] = 0 ; // Block data.
resp_readblock [ 4 ] = 0 ; // Block data.
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
// CRC
AddCrc15 ( resp_readblock , 5 ) ;
CodeIso15693AsTag ( resp_readblock , CMD_READBLOCK_RESP ) ;
2020-12-02 05:28:37 +08:00
2020-12-02 05:42:22 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-12-02 05:28:37 +08:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , slow ) ;
LogTrace_ISO15693 ( resp_readblock , CMD_READBLOCK_RESP , response_time * 32 , ( response_time * 32 ) + ( ts - > max * 32 * 64 ) , NULL , false ) ;
}
2020-07-10 01:41:57 +08:00
}
2020-07-20 02:45:47 +08:00
2019-03-10 03:34:41 +08:00
switch_off ( ) ;
2020-07-20 02:45:47 +08:00
if ( button_pressed )
DbpString ( " button pressed " ) ;
2020-09-07 16:39:15 +08:00
2020-08-17 14:52:24 +08:00
reply_ng ( CMD_HF_ISO15693_SIMULATE , PM3_SUCCESS , NULL , 0 ) ;
2010-02-21 05:24:25 +08:00
}
2010-10-19 22:25:17 +08: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 18:20:22 +08:00
void BruteforceIso15693Afi ( uint32_t speed ) {
2016-08-05 03:37:43 +08:00
2020-07-02 18:37:07 +08:00
uint8_t data [ 7 ] = { 0 } ;
2020-08-13 18:25:04 +08:00
uint8_t recv [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2019-03-10 03:34:41 +08:00
Iso15693InitReader ( ) ;
// first without AFI
// Tags should respond wihtout AFI and with AFI=0 even when AFI is active
data [ 0 ] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1 ;
data [ 1 ] = ISO15_CMD_INVENTORY ;
2019-10-10 17:54:23 +08:00
data [ 2 ] = 0 ; // AFI
2019-04-07 18:07:50 +08:00
AddCrc15 ( data , 3 ) ;
2020-07-02 18:37:07 +08:00
2020-08-13 18:25:04 +08:00
int datalen = 5 ;
2020-07-02 18:37:07 +08:00
uint32_t eof_time = 0 ;
2020-07-10 01:41:57 +08:00
uint32_t start_time = GetCountSspClk ( ) ;
int recvlen = SendDataTag ( data , datalen , true , speed , recv , sizeof ( recv ) , 0 , ISO15693_READER_TIMEOUT , & eof_time ) ;
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
if ( recvlen > = 12 ) {
2020-07-02 18:37:07 +08:00
Dbprintf ( " NoAFI UID = %s " , iso15693_sprintUID ( NULL , recv + 2 ) ) ;
2020-10-14 04:43:28 +08:00
} else {
DbpString ( " Failed to select card " ) ;
reply_ng ( CMD_ACK , PM3_ESOFT , NULL , 0 ) ;
switch_off ( ) ;
return ;
2019-03-10 03:34:41 +08:00
}
// now with AFI
data [ 0 ] | = ISO15_REQINV_AFI ;
data [ 2 ] = 0 ; // AFI
data [ 3 ] = 0 ; // mask length
2019-10-10 17:54:23 +08:00
// 4 + 2crc
datalen = 6 ;
2020-07-02 18:37:07 +08:00
bool aborted = false ;
2019-03-10 03:34:41 +08:00
for ( uint16_t i = 0 ; i < 256 ; i + + ) {
2020-07-02 18:37:07 +08:00
2019-03-10 03:34:41 +08:00
data [ 2 ] = i & 0xFF ;
2019-04-07 18:07:50 +08:00
AddCrc15 ( data , 4 ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
recvlen = SendDataTag ( data , datalen , false , speed , recv , sizeof ( recv ) , start_time , ISO15693_READER_TIMEOUT , & eof_time ) ;
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2020-08-13 18:25:04 +08:00
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
2020-07-02 18:37:07 +08:00
2019-03-10 03:34:41 +08:00
if ( recvlen > = 12 ) {
2020-07-02 18:37:07 +08:00
Dbprintf ( " AFI = %i UID = %s " , i , iso15693_sprintUID ( NULL , recv + 2 ) ) ;
2019-03-10 03:34:41 +08:00
}
2019-11-28 03:14:31 +08:00
aborted = BUTTON_PRESS ( ) ;
if ( aborted ) {
2019-03-10 03:34:41 +08:00
DbpString ( " button pressed, aborting.. " ) ;
break ;
}
}
DbpString ( " AFI Bruteforcing done. " ) ;
switch_off ( ) ;
2019-11-27 21:11:43 +08:00
if ( aborted ) {
reply_ng ( CMD_ACK , PM3_EOPABORTED , NULL , 0 ) ;
} else {
reply_ng ( CMD_ACK , PM3_SUCCESS , NULL , 0 ) ;
}
2010-10-19 22:25:17 +08:00
}
// Allows to directly send commands to the tag via the client
2020-07-02 18:37:07 +08:00
// OBS: doesn't turn off rf field afterwards.
2019-03-10 18:20:22 +08:00
void DirectTag15693Command ( uint32_t datalen , uint32_t speed , uint32_t recv , uint8_t * data ) {
2017-09-04 19:56:57 +08:00
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t timeout ;
2020-10-14 04:43:28 +08:00
uint32_t eof_time = 0 ;
2020-07-02 18:37:07 +08:00
bool request_answer = false ;
2020-08-13 18:25:04 +08:00
2020-07-10 01:41:57 +08:00
switch ( data [ 1 ] ) {
case ISO15_CMD_WRITE :
case ISO15_CMD_LOCK :
case ISO15_CMD_WRITEMULTI :
case ISO15_CMD_WRITEAFI :
case ISO15_CMD_LOCKAFI :
case ISO15_CMD_WRITEDSFID :
case ISO15_CMD_LOCKDSFID :
timeout = ISO15693_READER_TIMEOUT_WRITE ;
request_answer = data [ 0 ] & ISO15_REQ_OPTION ;
break ;
default :
timeout = ISO15693_READER_TIMEOUT ;
2020-08-13 18:25:04 +08:00
}
2019-03-10 03:34:41 +08:00
2020-08-14 20:56:20 +08:00
uint32_t start_time = 0 ;
2020-10-14 04:43:28 +08:00
int recvlen = SendDataTag ( data , datalen , true , speed , ( recv ? recvbuf : NULL ) , sizeof ( recvbuf ) , start_time , timeout , & eof_time ) ;
2020-08-13 18:25:04 +08:00
2020-10-14 04:43:28 +08:00
if ( recvlen = = PM3_ETEAROFF ) { // tearoff occured
reply_mix ( CMD_ACK , recvlen , 0 , 0 , NULL , 0 ) ;
} else {
2020-07-02 18:37:07 +08:00
2020-10-14 04:43:28 +08:00
// send a single EOF to get the tag response
if ( request_answer ) {
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
recvlen = SendDataTagEOF ( ( recv ? recvbuf : NULL ) , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT , & eof_time ) ;
2020-07-10 01:41:57 +08:00
}
2020-08-17 14:52:24 +08:00
2020-10-14 04:43:28 +08:00
if ( recv ) {
2020-10-20 07:00:23 +08:00
recvlen = MIN ( recvlen , ISO15693_MAX_RESPONSE_LENGTH ) ;
2020-10-14 04:43:28 +08:00
reply_mix ( CMD_ACK , recvlen , 0 , 0 , recvbuf , recvlen ) ;
} else {
reply_mix ( CMD_ACK , 1 , 0 , 0 , NULL , 0 ) ;
2020-07-10 01:41:57 +08:00
}
2019-03-10 03:34:41 +08:00
}
2020-10-14 04:43:28 +08:00
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LED_D_OFF ( ) ;
2019-03-12 07:12:26 +08:00
}
2020-07-02 18:37:07 +08:00
2020-08-17 14:52:24 +08:00
/*
SLIx functions from official master forks .
void LockPassSlixIso15693 ( uint32_t pass_id , uint32_t password ) {
LED_A_ON ( ) ;
2020-09-07 16:39:15 +08:00
2020-10-07 02:44:23 +08: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 ;
int recvlen = 0 ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint32_t start_time = 0 ;
bool done = false ;
// 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 ;
}
recvlen = SendDataTag ( cmd_get_rnd , sizeof ( cmd_get_rnd ) , true , true , recvbuf , sizeof ( recvbuf ) , start_time ) ;
if ( recvlen ! = 5 ) {
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 ] ) ;
recvlen = SendDataTag ( cmd_set_pass , sizeof ( cmd_set_pass ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time ) ;
if ( recvlen ! = 3 ) {
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... " ) ;
recvlen = SendDataTag ( cmd_inventory , sizeof ( cmd_inventory ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time ) ;
if ( recvlen ! = 12 ) {
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 ) ;
recvlen = SendDataTag ( cmd_lock_pass , sizeof ( cmd_lock_pass ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time ) ;
if ( recvlen ! = 3 ) {
Dbprintf ( " LockPass: Failed to lock password (%d) " , recvlen ) ;
} else {
Dbprintf ( " LockPass: Successful (%d) " , recvlen ) ;
}
LED_A_ON ( ) ;
}
} }
}
Dbprintf ( " LockPass: Finishing " ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
cmd_send ( CMD_ACK , recvlen , 0 , 0 , recvbuf , recvlen ) ;
LED_A_OFF ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
LED_D_OFF ( ) ;
2020-08-17 14:52:24 +08:00
}
*/
2020-07-02 18:37:07 +08:00
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card.
//
//-----------------------------------------------------------------------------
// Set the UID on Magic ISO15693 tag (based on Iceman's LUA-script).
void SetTag15693Uid ( uint8_t * uid ) {
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
uint8_t cmd [ 4 ] [ 9 ] = {
{ ISO15_REQ_DATARATE_HIGH , ISO15_CMD_WRITE , 0x3e , 0x00 , 0x00 , 0x00 , 0x00 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15_CMD_WRITE , 0x3f , 0x69 , 0x96 , 0x00 , 0x00 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15_CMD_WRITE , 0x38 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15_CMD_WRITE , 0x39 }
} ;
2020-08-17 14:52:24 +08:00
// Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X)
2020-07-10 01:41:57 +08:00
cmd [ 2 ] [ 3 ] = uid [ 7 ] ;
cmd [ 2 ] [ 4 ] = uid [ 6 ] ;
cmd [ 2 ] [ 5 ] = uid [ 5 ] ;
cmd [ 2 ] [ 6 ] = uid [ 4 ] ;
2020-08-17 14:52:24 +08:00
// Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X)
2020-07-10 01:41:57 +08:00
cmd [ 3 ] [ 3 ] = uid [ 3 ] ;
cmd [ 3 ] [ 4 ] = uid [ 2 ] ;
cmd [ 3 ] [ 5 ] = uid [ 1 ] ;
cmd [ 3 ] [ 6 ] = uid [ 0 ] ;
2020-07-02 18:37:07 +08:00
AddCrc15 ( cmd [ 0 ] , 7 ) ;
AddCrc15 ( cmd [ 1 ] , 7 ) ;
AddCrc15 ( cmd [ 2 ] , 7 ) ;
AddCrc15 ( cmd [ 3 ] , 7 ) ;
2020-08-17 14:52:24 +08:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2020-08-13 18:25:04 +08:00
2020-08-17 14:52:24 +08:00
uint32_t start_time = 0 ;
uint32_t eof_time = 0 ;
2020-07-10 01:41:57 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
2020-08-17 14:52:24 +08:00
SendDataTag ( cmd [ i ] , sizeof ( cmd [ i ] ) , i = = 0 ? true : false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , & eof_time ) ;
2020-07-10 01:41:57 +08:00
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
}
2020-09-07 16:39:15 +08:00
2020-08-17 14:52:24 +08:00
reply_ng ( CMD_HF_ISO15693_CSETUID , PM3_SUCCESS , NULL , 0 ) ;
switch_off ( ) ;
2020-09-07 16:39:15 +08:00
}