2010-02-21 05:24:25 +08:00
//-----------------------------------------------------------------------------
2022-01-06 09:19:46 +08: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 08:12:52 +08:00
//
2022-01-06 09:19:46 +08: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 08:12:52 +08:00
//-----------------------------------------------------------------------------
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
2022-03-16 22:33:44 +08:00
// *) simulation do not support two subcarrier modes.
2020-07-02 18:37:07 +08:00
// *) 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"
2021-05-03 15:35:38 +08:00
# include "protocols.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
2024-01-18 19:21:21 +08:00
# define ISO15693_MAX_RESPONSE_LENGTH 2116 // allows read multiple block with the maximum block size of 256bits and a maximum block number of 64 with REQ_OPTION (lock status for each block).
2020-07-02 18:37:07 +08:00
# 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
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)
2024-01-19 20:52:57 +08:00
# define CalculateCrc15(data, len) Crc16ex(CRC_15693, (data), (len))
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
} ;
2022-01-06 22:40:11 +08:00
void CodeIso15693AsReader ( const 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
}
2023-01-29 11:59:50 +08:00
static int get_uid_slix ( uint32_t start_time , uint32_t * eof_time , uint8_t * uid ) {
2023-01-28 12:46:40 +08:00
uint8_t * answer = BigBuf_malloc ( ISO15693_MAX_RESPONSE_LENGTH ) ;
memset ( answer , 0x00 , ISO15693_MAX_RESPONSE_LENGTH ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t cmd [ 5 ] = { 0 } ;
BuildIdentifyRequest ( cmd ) ;
uint16_t recvlen = 0 ;
SendDataTag ( cmd , sizeof ( cmd ) , false , true , answer , ISO15693_MAX_RESPONSE_LENGTH , start_time , ISO15693_READER_TIMEOUT , eof_time , & recvlen ) ;
2023-01-29 11:59:50 +08:00
if ( recvlen ! = 12 ) {
return PM3_ETIMEOUT ;
}
uid [ 0 ] = answer [ 2 ] ;
uid [ 1 ] = answer [ 3 ] ;
2023-01-28 12:46:40 +08:00
uid [ 2 ] = answer [ 4 ] ;
uid [ 3 ] = answer [ 5 ] ;
uid [ 4 ] = answer [ 6 ] ;
uid [ 5 ] = answer [ 7 ] ;
uid [ 6 ] = answer [ 8 ] ;
2023-01-29 11:59:50 +08:00
uid [ 7 ] = answer [ 9 ] ;
2023-01-28 12:46:40 +08:00
BigBuf_free ( ) ;
return PM3_SUCCESS ;
}
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
2022-01-06 22:40:11 +08:00
static void CodeIso15693AsReader256 ( const 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
2022-01-06 22:40:11 +08:00
void CodeIso15693AsTag ( const 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
2022-03-22 02:22:27 +08:00
for ( size_t i = 0 ; i < len ; i + + ) {
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-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[].
2023-01-04 21:27:00 +08:00
void TransmitTo15693Tag ( const uint8_t * cmd , int len , uint32_t * start_time , bool shallow_mod ) {
2019-03-09 15:59:13 +08:00
2023-08-28 18:00:44 +08:00
# ifdef RDV4
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | ( shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4 : FPGA_HF_READER_MODE_SEND_FULL_MOD ) ) ;
2023-09-08 02:13:18 +08:00
# else
2023-01-04 21:27:00 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | ( shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD : FPGA_HF_READER_MODE_SEND_FULL_MOD ) ) ;
2023-09-08 02:13:18 +08:00
# endif
2023-08-28 18:00:44 +08:00
2020-07-10 01:41:57 +08:00
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 ;
2022-03-24 00:37:40 +08:00
uint16_t len ;
2020-07-10 01:41:57 +08:00
int sum1 ;
int sum2 ;
int threshold_sof ;
int threshold_half ;
2022-03-24 00:37:40 +08:00
uint16_t previous_amplitude ;
uint8_t * output ;
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
//-----------------------------------------------------------------------------
2022-03-16 22:21:28 +08:00
static RAMFUNC int Handle15693SamplesFromTag ( uint16_t amplitude , DecodeTag_t * tag , bool recv_speed ) {
2020-07-21 16:51:48 +08:00
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
}
2022-03-24 01:22:03 +08:00
if ( tag - > posCount = = ( recv_speed ? 10 : 40 ) ) {
2020-07-21 16:51:48 +08:00
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount = = ( recv_speed ? 13 : 52 ) & & amplitude < tag - > threshold_sof ) {
2020-07-21 16:51:48 +08: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-10 01:41:57 +08:00
LED_C_ON ( ) ;
} else {
2020-07-21 16:51:48 +08:00
tag - > posCount + + ;
2022-03-24 01:22:03 +08:00
if ( tag - > posCount > ( recv_speed ? 13 : 52 ) ) { // high phase too long
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 ( ) ;
}
}
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 16:51:48 +08:00
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 16:51:48 +08: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-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 ) {
2021-04-17 04:14:14 +08:00
tag - > output [ tag - > len ] = tag - > shiftReg & 0xFF ;
2020-07-21 16:51:48 +08:00
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 ) {
2021-04-17 04:14:14 +08:00
tag - > output [ tag - > len ] = ( tag - > shiftReg & 0xFF ) ;
2020-07-21 16:51:48 +08:00
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 16:51:48 +08:00
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 16:51:48 +08: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-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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount < = ( recv_speed ? 4 : 16 ) ) {
2020-07-21 16:51:48 +08:00
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
2022-03-24 01:22:03 +08:00
if ( tag - > posCount = = ( recv_speed ? 8 : 32 ) ) {
2020-07-21 16:51:48 +08:00
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
2022-03-16 20:58:04 +08: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-17 00:36:37 +08: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 20:58:04 +08:00
# define MAX_COUNT(c, s) ((s) ? (c >= 13) : (c >= 52))
2020-07-02 18:37:07 +08:00
2022-03-16 20:58:04 +08:00
typedef struct DecodeTagFSK {
2022-03-24 01:22:03 +08:00
enum {
2022-03-16 20:58:04 +08:00
STATE_FSK_ERROR ,
2022-03-24 01:22:03 +08:00
STATE_FSK_BEFORE_SOF ,
STATE_FSK_SOF_484 ,
STATE_FSK_SOF_424 ,
STATE_FSK_SOF_END_484 ,
2022-03-16 20:58:04 +08:00
STATE_FSK_SOF_END_424 ,
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
SOF
2022-03-24 01:22:03 +08:00
} lastBit ;
uint8_t count ;
uint8_t bitCount ;
uint8_t shiftReg ;
uint16_t len ;
uint16_t max_len ;
uint8_t * output ;
2022-03-16 20:58:04 +08:00
} DecodeTagFSK_t ;
2020-07-02 18:37:07 +08:00
2022-03-16 20:58:04 +08:00
static void DecodeTagFSKReset ( DecodeTagFSK_t * DecodeTag ) {
2022-03-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
DecodeTag - > bitCount = 0 ;
DecodeTag - > len = 0 ;
DecodeTag - > shiftReg = 0 ;
2022-03-16 20:58:04 +08:00
}
2020-08-14 20:56:20 +08:00
2022-03-16 20:58:04 +08:00
static void DecodeTagFSKInit ( DecodeTagFSK_t * DecodeTag , uint8_t * data , uint16_t max_len ) {
2022-03-24 01:22:03 +08:00
DecodeTag - > output = data ;
DecodeTag - > max_len = max_len ;
DecodeTagFSKReset ( DecodeTag ) ;
2022-03-16 20:58:04 +08:00
}
2020-08-14 20:56:20 +08:00
2022-03-16 20:58:04 +08:00
// Performances of this function are crutial for stability
// as it is called in real time for every samples
2022-03-24 01:22:03 +08: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-10 01:41:57 +08:00
}
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
}
2022-03-24 01:22:03 +08:00
break ;
2020-08-14 20:56:20 +08:00
2022-03-24 01:22:03 +08:00
case STATE_FSK_SOF_424 :
2022-03-16 20:58:04 +08:00
//DbpString("STATE_FSK_SOF_424");
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " SOF_424 failed: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2022-03-16 20:58:04 +08:00
}
2022-03-24 01:22:03 +08:00
break ;
2020-08-14 20:56:20 +08:00
2022-03-24 01:22:03 +08:00
case STATE_FSK_SOF_END_484 :
if ( FREQ_IS_424 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
2022-03-16 20:58:04 +08:00
DecodeTag - > state = STATE_FSK_SOF_END_424 ;
2022-03-24 01:22:03 +08: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 20:58:04 +08: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-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2020-07-10 01:41:57 +08:00
}
2022-03-24 01:22:03 +08:00
break ;
2022-03-16 20:58:04 +08:00
case STATE_FSK_SOF_END_424 :
2022-03-24 01:22:03 +08:00
if ( FREQ_IS_484 ( freq ) & & LOGIC_COUNT ( DecodeTag - > count , recv_speed ) ) {
// SOF finished at 484
DecodeTag - > count = 1 ;
2022-03-16 20:58:04 +08:00
DecodeTag - > lastBit = SOF ;
2022-03-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_484 ;
2022-03-16 20:58:04 +08:00
LED_C_ON ( ) ;
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
DecodeTag - > lastBit = SOF ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_424 ;
LED_C_ON ( ) ;
2022-03-24 01:22:03 +08:00
} else if ( FREQ_IS_424 ( freq ) & & ! MAX_COUNT ( DecodeTag - > count , recv_speed ) ) // still in SOF_END_424
2022-03-16 20:58:04 +08:00
DecodeTag - > count + + ;
2022-03-24 01:22:03 +08:00
else { // SOF failed, roll back
2022-03-16 20:58:04 +08: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-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_BEFORE_SOF ;
2020-07-10 01:41:57 +08:00
}
break ;
2020-07-02 18:37:07 +08:00
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
DecodeTag - > lastBit = LOGIC1_PART2 ;
2020-07-02 18:37:07 +08:00
2022-03-16 20:58:04 +08: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-24 01:22:03 +08:00
} else {
// end of LOGIC0_PART1
2022-03-16 20:58:04 +08:00
DecodeTag - > lastBit = LOGIC0_PART1 ;
}
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_484 ;
2022-03-24 01:22:03 +08: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 20:58:04 +08:00
DecodeTag - > lastBit = LOGIC1_PART2 ;
2020-07-02 18:37:07 +08:00
2022-03-16 20:58:04 +08: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-24 01:22:03 +08: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 20:58:04 +08: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-24 01:22:03 +08:00
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_EOF ;
LED_C_OFF ( ) ;
} else { // error
2022-03-16 20:58:04 +08: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-24 01:22:03 +08: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 20:58:04 +08: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-24 01:22:03 +08:00
} else {
// end of LOGIC1_PART1
2022-03-16 20:58:04 +08:00
DecodeTag - > lastBit = LOGIC1_PART1 ;
}
DecodeTag - > count = 1 ;
DecodeTag - > state = STATE_FSK_RECEIVING_DATA_424 ;
2022-03-24 01:22:03 +08: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 20:58:04 +08: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-24 01:22:03 +08: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 20:58:04 +08: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-24 01:22:03 +08: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 20:58:04 +08:00
# ifdef DEBUG
if ( DEBUG )
Dbprintf ( " EOF error: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
# endif
2022-03-24 01:22:03 +08:00
DecodeTag - > state = STATE_FSK_ERROR ;
return true ;
}
break ;
case STATE_FSK_ERROR :
LED_C_OFF ( ) ;
2022-03-16 20:58:04 +08:00
# ifdef DEBUG
if ( DEBUG )
2022-03-24 01:22:03 +08:00
Dbprintf ( " FSK error: freq=%d, count=%d, recv_speed=%d " , freq , DecodeTag - > count , recv_speed ) ;
2022-03-16 20:58:04 +08:00
# endif
2022-03-24 01:22:03 +08:00
return true ; // error
break ;
}
return false ;
2022-03-16 20:58:04 +08:00
}
/*
* Receive and decode the tag response , also log to tracebuffer
*/
2022-03-24 00:37:40 +08: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 20:58:04 +08:00
2022-03-24 00:37:40 +08:00
int samples = 0 , ret = PM3_SUCCESS ;
if ( resp_len ) {
* resp_len = 0 ;
}
2022-03-16 20:58:04 +08:00
// the Decoder data structure
DecodeTag_t dtm = { 0 } ;
DecodeTag_t * dt = & dtm ;
2022-03-16 22:45:18 +08:00
DecodeTagFSK_t dtfm = { 0 } ;
DecodeTagFSK_t * dtf = & dtfm ;
2022-03-24 00:37:40 +08:00
if ( fsk )
2022-03-16 22:45:18 +08:00
DecodeTagFSKInit ( dtf , response , max_len ) ;
2022-03-24 00:37:40 +08:00
else
DecodeTagInit ( dt , response , max_len ) ;
2022-03-16 20:58:04 +08: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 22:45:18 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_2SUBCARRIERS_424_484_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ) ;
2022-03-16 20:58:04 +08: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-24 00:37:40 +08:00
return PM3_EINIT ;
2022-03-16 20:58:04 +08:00
}
uint32_t dma_start_time = 0 ;
2024-05-14 18:40:26 +08:00
const uint16_t * upTo = dma - > buf ;
2022-03-16 20:58:04 +08:00
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-24 00:37:40 +08:00
if ( fsk ) {
if ( Handle15693FSKSamplesFromTag ( tagdata > > 14 , dtf , recv_speed ) ) {
2022-03-16 20:58:04 +08:00
2022-03-16 22:45:18 +08:00
* eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM ; // end of EOF
2022-03-16 20:58:04 +08:00
2022-03-24 00:37:40 +08:00
if ( dtf - > lastBit = = SOF ) {
2022-03-16 22:45:18 +08:00
* eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2022-03-24 00:37:40 +08:00
if ( dtf - > len > dtf - > max_len ) {
ret = PM3_EOVFLOW ;
2023-10-03 03:39:15 +08:00
Dbprintf ( " overflow (%d > %d) " , dtf - > len , dtf - > max_len ) ;
2022-03-16 22:45:18 +08:00
}
break ;
2022-03-16 20:58:04 +08:00
}
2022-03-16 22:45:18 +08:00
// timeout
2022-03-24 00:37:40 +08:00
if ( samples > timeout & & dtf - > state < STATE_FSK_RECEIVING_DATA_484 ) {
ret = PM3_ETIMEOUT ;
2022-03-16 22:45:18 +08:00
break ;
2022-03-16 20:58:04 +08:00
}
2022-03-24 00:37:40 +08:00
} else {
if ( Handle15693SamplesFromTag ( tagdata & 0x3FFF , dt , recv_speed ) ) {
2022-03-16 20:58:04 +08:00
2022-03-16 22:45:18 +08:00
* eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM ; // end of EOF
2022-03-24 00:37:40 +08:00
if ( dt - > lastBit = = SOF_PART2 ) {
2022-03-16 22:45:18 +08:00
* eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2022-03-24 00:37:40 +08:00
if ( dt - > len > dt - > max_len ) {
ret = PM3_EOVFLOW ;
2023-10-03 03:39:15 +08:00
Dbprintf ( " overflow (%d > %d) " , dt - > len , dt - > max_len ) ;
2022-03-16 22:45:18 +08:00
}
break ;
}
2022-03-16 20:58:04 +08:00
2022-03-16 22:45:18 +08:00
// timeout
2022-03-24 00:37:40 +08:00
if ( samples > timeout & & dt - > state < STATE_TAG_RECEIVING_DATA ) {
ret = PM3_ETIMEOUT ;
2022-03-16 22:45:18 +08:00
break ;
}
}
2022-03-16 20:58:04 +08:00
}
FpgaDisableSscDma ( ) ;
FpgaDisableTracing ( ) ;
2022-03-16 22:45:18 +08:00
uint32_t sof_time = * eof_time - ( 32 * 16 ) ; // time for SOF transfer
2022-03-24 00:37:40 +08:00
if ( fsk ) {
2022-03-16 22:45:18 +08:00
sof_time - = ( dtf - > len * 8 * 8 * 16 ) // time for byte transfers
+ ( dtf - > lastBit ! = SOF ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
2022-03-24 00:37:40 +08:00
} else {
sof_time - = ( dt - > len * 8 * 8 * 16 ) // time for byte transfers
+ ( dt - > lastBit ! = SOF_PART2 ? ( 32 * 16 ) : 0 ) ; // time for EOF transfer
2020-07-10 01:41:57 +08:00
}
2020-07-02 18:37:07 +08:00
2022-03-24 00:37:40 +08:00
if ( ret ! = PM3_SUCCESS ) {
* resp_len = 0 ;
2020-07-10 01:41:57 +08:00
return ret ;
}
2020-08-19 22:22:56 +08:00
2022-03-24 00:37:40 +08: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 22:45:18 +08:00
LogTrace_ISO15693 ( dt - > output , dt - > len , ( sof_time * 4 ) , ( * eof_time * 4 ) , NULL , false ) ;
2022-03-24 00:37:40 +08:00
* resp_len = dt - > len ;
2022-03-16 22:45:18 +08:00
}
2022-03-24 00:37:40 +08:00
return PM3_SUCCESS ;
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 :
if ( bit ) { // detected rising edge
2024-01-18 19:21:21 +08:00
if ( reader - > posCount < 2 ) { // rising edge too early (nominally expected at 4)
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
} else { // SOF
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF ;
2024-01-18 19:21:21 +08:00
reader - > posCount = 1 ;
2020-07-10 01:41:57 +08:00
}
} else {
2024-01-18 19:21:21 +08:00
reader - > posCount + + ;
if ( reader - > posCount > 6 ) { // stayed low for too long
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2020-07-10 01:41:57 +08:00
}
}
break ;
case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF :
2024-01-18 19:21:21 +08:00
if ( ! bit ) { // detected a falling edge
if ( reader - > posCount < 14 ) { // falling edge too early (nominally expected at 16 earliest)
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2024-01-18 19:21:21 +08:00
} else if ( reader - > posCount < = 18 ) { // SOF for 1 out of 4 coding
2020-07-21 16:51:48 +08:00
reader - > Coding = CODING_1_OUT_OF_4 ;
reader - > state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF ;
2024-01-18 19:21:21 +08:00
reader - > posCount = 1 ;
} else if ( reader - > posCount < 22 ) { // falling edge too early (nominally expected at 24 latest)
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2024-01-18 19:21:21 +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 ;
2024-01-18 19:21:21 +08:00
reader - > posCount = 1 ;
2020-07-10 01:41:57 +08:00
}
} else {
2024-01-18 19:21:21 +08:00
reader - > posCount + + ;
if ( reader - > posCount > 26 ) { // stayed high for too long
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
} else {
// do nothing, keep waiting
}
}
break ;
case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF :
if ( bit ) { // detected rising edge
2024-01-18 19:21:21 +08:00
if ( reader - > posCount < 2 ) { // rising edge too early (nominally expected at 8)
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
} else {
reader - > posCount = 1 ;
if ( reader - > Coding = = CODING_1_OUT_OF_256 ) {
reader - > bitCount = 1 ;
2020-07-21 16:51:48 +08:00
reader - > byteCount = 0 ;
reader - > sum1 = 1 ;
2020-07-10 01:41:57 +08:00
LED_B_ON ( ) ;
2024-01-18 19:21:21 +08:00
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256 ;
} else { // CODING_1_OUT_OF_4
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 ;
2020-07-10 01:41:57 +08:00
}
}
} else {
2024-01-18 19:21:21 +08:00
reader - > posCount + + ;
if ( reader - > posCount > 6 ) { // signal stayed low for too long
DecodeReaderReset ( reader ) ;
} else {
// do nothing, keep waiting
2020-07-10 01:41:57 +08:00
}
}
break ;
case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4 :
if ( bit ) {
2024-01-18 19:21:21 +08:00
reader - > posCount + + ;
if ( reader - > posCount = = 8 ) {
reader - > posCount = 0 ;
2020-07-21 16:51:48 +08:00
reader - > bitCount = 0 ;
reader - > byteCount = 0 ;
2024-01-18 19:21:21 +08:00
reader - > sum1 = 0 ;
2020-07-21 16:51:48 +08:00
reader - > state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4 ;
2020-07-10 01:41:57 +08:00
LED_B_ON ( ) ;
}
} 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 :
2024-01-18 19:21:21 +08:00
if ( ! bit ) {
reader - > sum1 + + ;
if ( reader - > sum1 = = 1 ) { // first low bit
if ( reader - > posCount < = 6 ) { // bits : 00
reader - > shiftReg > > = 2 ;
//reader->shiftReg |= (0 << 6);
reader - > bitCount + = 2 ;
reader - > posCount = - 28 ;
} else if ( reader - > posCount < = 9 ) { // EOF
LED_B_OFF ( ) ; // Finished receiving
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount > 0 ) {
return true ;
}
} else if ( reader - > posCount < = 14 ) { // bits : 01
reader - > shiftReg > > = 2 ;
reader - > shiftReg | = ( 1 < < 6 ) ;
reader - > bitCount + = 2 ;
reader - > posCount = - 20 ;
} else if ( reader - > posCount < 18 ) { // unexpected falling edge
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount > = 0 ) {
reader - > output [ reader - > byteCount + + ] = reader - > posCount ;
reader - > output [ reader - > byteCount + + ] = reader - > bitCount ;
reader - > output [ reader - > byteCount + + ] = 0x42 ;
return true ;
}
} else if ( reader - > posCount < = 22 ) { // bits : 10
reader - > shiftReg > > = 2 ;
reader - > shiftReg | = ( 2 < < 6 ) ;
reader - > bitCount + = 2 ;
reader - > posCount = - 12 ;
} else if ( reader - > posCount < 26 ) { // unexpected falling edge
DecodeReaderReset ( reader ) ;
if ( reader - > byteCount > = 0 ) {
reader - > output [ reader - > byteCount + + ] = reader - > posCount ;
reader - > output [ reader - > byteCount + + ] = reader - > bitCount ;
reader - > output [ reader - > byteCount + + ] = 0x43 ;
return true ;
}
} else { // bits : 11
reader - > shiftReg > > = 2 ;
reader - > shiftReg | = ( 3 < < 6 ) ;
reader - > bitCount + = 2 ;
reader - > posCount = - 4 ;
}
2020-07-21 16:51:48 +08:00
2024-01-25 01:18:13 +08:00
if ( reader - > bitCount = = 8 ) {
2024-01-18 19:21:21 +08:00
reader - > output [ reader - > byteCount + + ] = reader - > shiftReg ;
if ( reader - > byteCount > reader - > byteCountMax ) {
// buffer overflow, give up
LED_B_OFF ( ) ;
DecodeReaderReset ( reader ) ;
}
2020-07-21 16:51:48 +08:00
2024-01-18 19:21:21 +08:00
reader - > bitCount = 0 ;
reader - > shiftReg = 0 ;
if ( reader - > byteCount = = reader - > jam_search_len ) {
2024-01-25 01:18:13 +08:00
if ( ! memcmp ( reader - > output , reader - > jam_search_string , reader - > jam_search_len ) ) {
LED_D_ON ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM ) ;
reader - > state = STATE_READER_RECEIVE_JAMMING ;
}
2024-01-18 19:21:21 +08:00
}
}
} else if ( reader - > sum1 > 6 ) { // too long low bit
2020-07-21 16:51:48 +08:00
DecodeReaderReset ( reader ) ;
2024-01-18 19:21:21 +08:00
if ( reader - > byteCount > = 0 ) {
reader - > output [ reader - > byteCount + + ] = reader - > posCount ;
reader - > output [ reader - > byteCount + + ] = reader - > bitCount ;
reader - > output [ reader - > byteCount + + ] = 0x44 ;
2020-07-10 01:41:57 +08:00
return true ;
}
}
2024-01-18 19:21:21 +08:00
} else {
reader - > posCount + + ;
if ( reader - > posCount > 30 ) {
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
if ( reader - > byteCount > = 0 ) {
reader - > output [ reader - > byteCount + + ] = reader - > posCount ;
reader - > output [ reader - > byteCount + + ] = reader - > bitCount ;
reader - > output [ reader - > byteCount + + ] = 0x45 ;
return true ;
2020-07-10 01:41:57 +08:00
}
2024-01-18 19:21:21 +08:00
}
if ( reader - > sum1 = = 1 ) {
reader - > state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF ;
if ( reader - > byteCount > = 0 ) {
reader - > output [ reader - > byteCount + + ] = reader - > posCount ;
reader - > output [ reader - > byteCount + + ] = reader - > bitCount ;
reader - > output [ reader - > byteCount + + ] = 0x46 ;
return true ;
2020-07-10 01:41:57 +08:00
}
2024-01-18 19:21:21 +08:00
} else if ( reader - > sum1 > 1 ) {
reader - > posCount + = reader - > sum1 ;
reader - > sum1 = 0 ;
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 ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-07-21 16:51:48 +08:00
return - 4 ;
}
2024-05-14 18:40:26 +08:00
const 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-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 ) {
2021-07-28 01:16:28 +08:00
LEDsoff ( ) ;
DbpString ( " Starting to acquire data... " ) ;
2022-02-08 21:47:06 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2021-07-28 01:16:28 +08: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-10 01:41:57 +08:00
LED_A_ON ( ) ;
2021-07-28 01:16:28 +08:00
2020-07-10 01:41:57 +08:00
uint8_t * dest = BigBuf_malloc ( 4000 ) ;
2010-02-21 05:24:25 +08:00
2021-07-28 01:16:28 +08:00
// switch field on
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER ) ;
LED_D_ON ( ) ;
2021-07-28 01:16:28 +08:00
// initialize SSC and select proper AD input
2020-07-10 01:41:57 +08:00
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2019-03-09 15:59:13 +08:00
2021-07-28 01:16:28 +08:00
StartCountSspClk ( ) ;
2010-02-21 05:24:25 +08:00
2020-07-10 01:41:57 +08:00
// Give the tags time to energize
2021-07-28 01:16:28 +08:00
SpinDelay ( 250 ) ;
2016-08-05 03:37:43 +08:00
2020-07-10 01:41:57 +08:00
// Now send the command
2024-05-14 18:40:26 +08:00
const tosend_t * ts = get_tosend ( ) ;
2020-07-13 23:56:19 +08:00
2020-07-10 01:41:57 +08:00
uint32_t start_time = 0 ;
2023-01-04 21:27:00 +08:00
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time , false ) ;
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
2021-07-28 01:16:28 +08:00
FpgaDisableSscDma ( ) ;
2020-07-10 01:41:57 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
LEDsoff ( ) ;
2010-10-19 22:25:17 +08:00
}
2022-03-16 18:26:07 +08:00
void SniffIso15693 ( uint8_t jam_search_len , uint8_t * jam_search_string , bool iclass ) {
2020-07-02 18:37:07 +08:00
2020-08-14 20:56:20 +08:00
LEDsoff ( ) ;
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
2022-02-08 21:47:06 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2020-07-10 01:41:57 +08:00
2024-01-25 18:22:55 +08:00
if ( g_dbglevel > = DBG_INFO ) {
2024-01-25 17:21:36 +08:00
DbpString ( " Press " _GREEN_ ( " pm3 button " ) " to abort sniffing " ) ;
}
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
2022-02-08 21:47:06 +08:00
DecodeTagFSK_t dtagfsk = { 0 } ;
uint8_t response2 [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
2022-03-24 01:22:03 +08:00
DecodeTagFSKInit ( & dtagfsk , response2 , sizeof ( response2 ) ) ;
2022-02-08 21:47:06 +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
2022-03-04 16:45:12 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE | FPGA_HF_READER_2SUBCARRIERS_424_484_KHZ ) ;
2022-03-16 18:26:07 +08:00
2020-07-10 01:41:57 +08:00
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 ) {
2021-08-22 05:02:27 +08:00
if ( g_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 ;
2022-02-08 21:47:06 +08:00
bool expect_fsk_answer = false ;
2022-03-16 18:26:07 +08:00
bool expect_fast_answer = true ; // default to true is required for iClass
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
2024-05-14 18:40:26 +08:00
const 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
2022-07-06 19:50:15 +08:00
volatile uint16_t sniffdata = 0 ;
2022-03-04 19:32:08 +08:00
volatile uint16_t sniffdata_prev = sniffdata ;
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 ( ) ) {
break ;
}
}
}
2020-07-10 22:37:56 +08:00
// no need to try decoding reader data if the tag is sending
2024-01-15 11:11:20 +08:00
if ( tag_is_active = = false ) {
2020-07-10 22:37:56 +08:00
2023-06-15 20:19:02 +08:00
int extra_8s = 1 ;
if ( Handle15693SampleFromReader ( ( sniffdata & 0x02 ) > > 1 , & dreader ) | |
( + + extra_8s & & Handle15693SampleFromReader ( sniffdata & 0x01 , & dreader ) ) ) {
2020-07-10 01:41:57 +08:00
2020-08-03 23:42:05 +08:00
if ( dreader . byteCount > 0 ) {
2023-06-15 20:19:02 +08:00
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
// not sure where the extra +8's on the EOF time comes from though, if someone knows update this comment
uint32_t eof_time = dma_start_time + ( samples * 16 ) + ( extra_8s * 8 ) - DELAY_READER_TO_ARM_SNIFF ; // end of EOF
2020-07-10 01:41:57 +08:00
uint32_t sof_time = eof_time
2023-06-15 20:19:02 +08:00
- dreader . byteCount * ( dreader . Coding = = CODING_1_OUT_OF_4 ? 1024 : 16384 ) // time for byte transfers
- 256 // time for SOF transfer (1024/fc / 4)
- 128 ; // time for EOF transfer (512/fc / 4)
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
2020-08-03 23:42:05 +08:00
LogTrace_ISO15693 ( dreader . output , dreader . byteCount , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
2022-02-08 21:47:06 +08:00
2024-01-15 11:11:20 +08:00
if ( iclass = = false ) { // Those flags don't exist in iClass
2022-03-16 18:26:07 +08:00
expect_fsk_answer = dreader . output [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ;
expect_fast_answer = dreader . output [ 0 ] & ISO15_REQ_DATARATE_HIGH ;
}
2020-07-10 01:41:57 +08:00
}
2023-06-15 20:19:02 +08:00
// And ready to receive another command.
2022-03-04 19:32:08 +08:00
//DecodeReaderReset(&dreader); // already reseted
2020-08-03 23:42:05 +08:00
DecodeTagReset ( & dtag ) ;
2022-02-08 21:47:06 +08:00
DecodeTagFSKReset ( & dtagfsk ) ;
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
}
}
2023-06-15 20:19:02 +08:00
// no need to try decoding tag data if the reader is currently sending or no answer expected yet
2024-01-15 11:11:20 +08:00
if ( ( reader_is_active = = false ) & & expect_tag_answer ) {
2020-07-21 16:51:48 +08:00
2024-01-15 11:11:20 +08:00
if ( expect_fsk_answer = = false ) {
2023-06-15 20:19:02 +08:00
// single subcarrier tag response
2022-03-16 22:21:28 +08:00
if ( Handle15693SamplesFromTag ( ( sniffdata > > 4 ) < < 2 , & dtag , expect_fast_answer ) ) {
2020-07-10 01:41:57 +08:00
2023-06-15 20:19:02 +08:00
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
2022-02-08 21:47:06 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM_SNIFF ; // end of EOF
2024-01-15 11:11:20 +08:00
2022-02-08 21:47:06 +08:00
if ( dtag . lastBit = = SOF_PART2 ) {
eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2024-01-15 11:11:20 +08:00
2022-02-08 21:47:06 +08:00
uint32_t sof_time = eof_time
2023-06-15 20:19:02 +08:00
- dtag . len * 1024 // time for byte transfers (4096/fc / 4)
- 512 // time for SOF transfer (2048/fc / 4)
- ( dtag . lastBit ! = SOF_PART2 ? 512 : 0 ) ; // time for EOF transfer (2048/fc / 4)
2022-02-08 21:47:06 +08:00
2023-06-15 20:19:02 +08:00
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
2022-02-08 21:47:06 +08:00
LogTrace_ISO15693 ( dtag . output , dtag . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
2023-06-15 20:19:02 +08:00
2022-02-08 21:47:06 +08:00
// 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 ) ;
}
2024-01-15 11:11:20 +08:00
2022-03-24 01:22:03 +08:00
} else {
2023-06-15 20:19:02 +08:00
// dual subcarrier tag response
2024-01-15 11:11:20 +08:00
if ( FREQ_IS_0 ( ( sniffdata > > 2 ) & 0x3 ) ) { // tolerate 1 00
2022-03-04 19:32:08 +08:00
sniffdata = sniffdata_prev ;
2024-01-15 11:11:20 +08:00
}
2022-02-08 21:47:06 +08:00
2022-03-04 19:32:08 +08:00
if ( Handle15693FSKSamplesFromTag ( ( sniffdata > > 2 ) & 0x3 , & dtagfsk , expect_fast_answer ) ) {
2022-03-24 01:22:03 +08:00
if ( dtagfsk . len > 0 ) {
2023-06-15 20:19:02 +08:00
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
2022-03-04 19:32:08 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) - DELAY_TAG_TO_ARM_SNIFF ; // end of EOF
2024-01-15 11:11:20 +08:00
2022-03-04 19:32:08 +08:00
if ( dtagfsk . lastBit = = SOF ) {
eof_time - = ( 8 * 16 ) ; // needed 8 additional samples to confirm single SOF (iCLASS)
}
2024-01-15 11:11:20 +08:00
2022-03-04 19:32:08 +08:00
uint32_t sof_time = eof_time
2023-06-15 20:19:02 +08:00
- dtagfsk . len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different
- 512 // time for SOF transfer (2048/fc / 4)
- ( dtagfsk . lastBit ! = SOF ? 512 : 0 ) ; // time for EOF transfer (2048/fc / 4)
2020-07-10 22:37:56 +08:00
2023-06-15 20:19:02 +08:00
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
2022-03-04 19:32:08 +08:00
LogTrace_ISO15693 ( dtagfsk . output , dtagfsk . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
2022-02-08 21:47:06 +08:00
}
DecodeTagFSKReset ( & dtagfsk ) ;
DecodeReaderReset ( & dreader ) ;
expect_tag_answer = false ;
tag_is_active = false ;
2023-06-15 20:19:02 +08:00
// FSK answer no more expected: switch back to ASK
expect_fsk_answer = false ;
} else {
tag_is_active = ( dtagfsk . state > = STATE_FSK_RECEIVING_DATA_484 ) ;
2022-02-08 21:47:06 +08:00
}
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 ( " " ) ;
2023-06-26 21:01:08 +08:00
if ( g_dbglevel > DBG_ERROR ) {
DbpString ( _CYAN_ ( " Sniff statistics " ) ) ;
DbpString ( " ================================= " ) ;
Dbprintf ( " DecodeTag State........ %d " , dtag . state ) ;
Dbprintf ( " DecodeTag byteCnt...... %d " , dtag . len ) ;
Dbprintf ( " DecodeTag posCount..... %d " , dtag . posCount ) ;
Dbprintf ( " DecodeTagFSK State..... %d " , dtagfsk . state ) ;
Dbprintf ( " DecodeTagFSK byteCnt... %d " , dtagfsk . len ) ;
Dbprintf ( " DecodeTagFSK count..... %d " , dtagfsk . count ) ;
Dbprintf ( " DecodeReader State..... %d " , dreader . state ) ;
Dbprintf ( " DecodeReader byteCnt... %d " , dreader . byteCount ) ;
2023-06-27 21:25:00 +08:00
Dbprintf ( " DecodeReader posCount.. %d " , dreader . posCount ) ;
2023-06-26 21:01:08 +08:00
}
Dbprintf ( " Trace length........... " _YELLOW_ ( " %d " ) , BigBuf_get_traceLen ( ) ) ;
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 ( ) ;
2022-02-08 21:47:06 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
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
2021-10-10 07:35:38 +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
// 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
2021-05-03 15:35:38 +08:00
cmd [ 1 ] = ISO15693_INVENTORY ;
2020-07-10 01:41:57 +08:00
// 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
2024-05-14 18:40:26 +08:00
int SendDataTag ( const uint8_t * send , int sendlen , bool init , bool speed_fast , uint8_t * recv ,
2022-03-24 00:37:40 +08:00
uint16_t max_recv_len , uint32_t start_time , uint16_t timeout , uint32_t * eof_time , uint16_t * resp_len ) {
2020-07-02 18:37:07 +08:00
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 ) ;
}
2022-03-24 00:37:40 +08:00
2024-05-14 18:40:26 +08:00
const tosend_t * ts = get_tosend ( ) ;
2023-01-04 21:27:00 +08:00
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time , false ) ;
2020-10-20 07:00:23 +08:00
2021-03-08 06:43:53 +08:00
if ( tearoff_hook ( ) = = PM3_ETEAROFF ) { // tearoff occurred
2022-03-24 00:37:40 +08:00
* resp_len = 0 ;
return PM3_ETEAROFF ;
2020-10-14 04:43:28 +08:00
} else {
2020-10-20 07:00:23 +08:00
2022-03-24 00:37:40 +08:00
int res = PM3_SUCCESS ;
2021-10-10 07:35:38 +08:00
* eof_time = start_time + 32 * ( ( 8 * ts - > max ) - 4 ) ; // subtract the 4 padding bits after EOF
2020-10-14 04:43:28 +08:00
LogTrace_ISO15693 ( send , sendlen , ( start_time * 4 ) , ( * eof_time * 4 ) , NULL , true ) ;
if ( recv ! = NULL ) {
2024-01-14 21:23:51 +08:00
bool fsk = ( ( send [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ) = = ISO15_REQ_SUBCARRIER_TWO ) ;
bool recv_speed = ( ( send [ 0 ] & ISO15_REQ_DATARATE_HIGH ) = = ISO15_REQ_DATARATE_HIGH ) ;
2022-03-24 00:37:40 +08:00
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time , fsk , recv_speed , resp_len ) ;
2020-10-14 04:43:28 +08:00
}
2022-03-24 00:37:40 +08:00
return res ;
2020-07-10 01:41:57 +08:00
}
2020-07-02 18:37:07 +08:00
}
2019-03-09 15:59:13 +08:00
2022-03-24 00:37:40 +08: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-30 04:36:55 +08:00
2020-07-10 01:41:57 +08:00
CodeIso15693AsReaderEOF ( ) ;
2024-05-14 18:40:26 +08:00
const tosend_t * ts = get_tosend ( ) ;
2023-01-04 21:27:00 +08:00
TransmitTo15693Tag ( ts - > buf , ts - > max , & start_time , false ) ;
2021-10-10 07:35:38 +08:00
uint32_t end_time = start_time + 32 * ( 8 * ts - > max - 4 ) ; // subtract 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
2022-03-24 00:37:40 +08:00
int res = PM3_SUCCESS ;
if ( recv ) {
res = GetIso15693AnswerFromTag ( recv , max_recv_len , timeout , eof_time , fsk , recv_speed , resp_len ) ;
2020-07-10 01:41:57 +08:00
}
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
2024-05-14 18:40:26 +08:00
static void DbdecodeIso15693Answer ( int n , const uint8_t * d ) {
2019-03-10 03:34:41 +08:00
2024-05-14 18:40:26 +08:00
if ( n > 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
}
2024-05-14 18:40:26 +08:00
if ( CheckCrc15 ( d , n ) )
2022-02-25 01:03:19 +08:00
strncat ( status , " [+] crc ( " _GREEN_ ( " ok " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
else
2022-02-25 01:03:19 +08:00
strncat ( status , " [!] crc ( " _RED_ ( " fail " ) " ) " , DBD15STATLEN - strlen ( status ) ) ;
2019-03-10 03:34:41 +08:00
2021-08-22 05:02:27 +08:00
if ( g_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
//-----------------------------------------------------------------------------
2022-03-24 00:37:40 +08:00
void ReaderIso15693 ( iso15_card_select_t * p_card ) {
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 ;
2022-03-24 01:22:03 +08:00
uint16_t recvlen = 0 ;
2022-03-24 00:37:40 +08: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 07:00:23 +08:00
2022-03-24 00:37:40 +08:00
if ( res = = PM3_ETEAROFF ) { // tearoff occurred
reply_ng ( CMD_HF_ISO15693_READER , res , NULL , 0 ) ;
2020-10-14 04:43:28 +08:00
} else {
2020-10-20 07:00:23 +08:00
2021-03-01 02:01:38 +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 ] ;
2021-05-05 15:55:58 +08:00
if ( p_card ! = NULL ) {
memcpy ( p_card - > uid , uid , 8 ) ;
p_card - > uidlen = 8 ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) {
2020-10-14 04:43:28 +08: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-24 00:37:40 +08:00
reply_ng ( CMD_HF_ISO15693_READER , PM3_SUCCESS , uid , sizeof ( uid ) ) ;
2020-10-14 04:43:28 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_EXTENDED ) {
2024-01-14 21:23:51 +08:00
Dbprintf ( " [+] %d bytes read from IDENTIFY request: " , recvlen ) ;
2020-10-14 04:43:28 +08:00
DbdecodeIso15693Answer ( recvlen , answer ) ;
Dbhexdump ( recvlen , answer , true ) ;
}
} else {
2021-05-05 15:55:58 +08:00
p_card - > uidlen = 0 ;
2020-10-14 04:43:28 +08:00
DbpString ( " Failed to select card " ) ;
2022-03-24 00:37:40 +08:00
reply_ng ( CMD_HF_ISO15693_READER , PM3_EFAILED , 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
2022-02-08 21:47:06 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF_15 ) ;
2020-07-10 01:41:57 +08: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-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
}
2022-09-01 22:12:22 +08: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 ) ;
}
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
2024-05-14 18:40:26 +08:00
void SimTagIso15693 ( const uint8_t * uid , uint8_t block_size ) {
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 ( ) ;
2024-01-25 15:54:10 +08:00
// Init early to be sure FPGA is loaded before any EML operation
// usefull when eml memory is empty (UID supplied)
2024-01-26 18:20:25 +08:00
Iso15693InitTag ( ) ; // to be sure FPGA is loaded before any EML operation
2020-07-20 02:45:47 +08:00
2024-01-25 01:18:13 +08:00
iso15_tag_t * tag = ( iso15_tag_t * ) BigBuf_get_EM_addr ( ) ;
if ( tag = = NULL ) {
2024-01-24 20:47:59 +08:00
Dbprintf ( " Can't allocate emulator memory " ) ;
reply_ng ( CMD_HF_ISO15693_SIMULATE , PM3_EFAILED , NULL , 0 ) ;
return ;
2024-01-16 22:20:01 +08:00
}
2024-01-25 07:37:15 +08:00
if ( uid ! = NULL ) {
2024-01-25 08:55:07 +08:00
2024-01-25 07:37:15 +08:00
uint8_t empty [ 8 ] = { 0 } ;
2024-01-25 08:45:18 +08:00
// User supplied not empty?
if ( memcmp ( uid , empty , 8 ) ) {
// Set default values if user supplied a UID.
// Assume emulator memory is empty
2024-01-25 07:37:15 +08:00
tag - > uid [ 0 ] = uid [ 7 ] ; // always E0
tag - > uid [ 1 ] = uid [ 6 ] ; // IC Manufacturer code
tag - > uid [ 2 ] = uid [ 5 ] ;
tag - > uid [ 3 ] = uid [ 4 ] ;
tag - > uid [ 4 ] = uid [ 3 ] ;
tag - > uid [ 5 ] = uid [ 2 ] ;
tag - > uid [ 6 ] = uid [ 1 ] ;
tag - > uid [ 7 ] = uid [ 0 ] ;
2024-01-24 20:48:45 +08:00
tag - > dsfid = 0 ;
tag - > dsfidLock = false ;
tag - > afi = 0 ;
tag - > afiLock = false ;
tag - > bytesPerPage = ( block_size > 0 ) ? block_size : 4 ;
tag - > pagesCount = 64 ;
tag - > ic = 0 ;
memset ( tag - > locks , 0 , sizeof ( tag - > locks ) ) ;
memset ( tag - > data , 0 , sizeof ( tag - > data ) ) ;
2024-01-16 22:20:01 +08:00
}
}
2024-01-25 07:37:15 +08:00
2024-01-25 08:45:18 +08:00
if ( ( tag - > pagesCount > ISO15693_TAG_MAX_PAGES ) | |
2024-01-25 08:55:07 +08:00
( ( tag - > pagesCount * tag - > bytesPerPage ) > ISO15693_TAG_MAX_SIZE ) | |
( tag - > pagesCount = = 0 ) | |
( tag - > bytesPerPage = = 0 ) ) {
2024-01-24 20:47:59 +08:00
Dbprintf ( " Tag size error: pagesCount = %d, bytesPerPage=%d " , tag - > pagesCount , tag - > bytesPerPage ) ;
reply_ng ( CMD_HF_ISO15693_SIMULATE , PM3_EOPABORTED , NULL , 0 ) ;
return ;
}
2024-01-16 22:20:01 +08:00
2019-03-10 03:34:41 +08:00
LED_A_ON ( ) ;
2010-02-21 05:24:25 +08:00
2024-01-25 08:45:18 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
Dbprintf ( " ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X, %u bytes/blocks x %u blocks "
2024-01-25 08:55:07 +08:00
, tag - > uid [ 7 ]
, tag - > uid [ 6 ]
, tag - > uid [ 5 ]
, tag - > uid [ 4 ]
, tag - > uid [ 3 ]
, tag - > uid [ 2 ]
, tag - > uid [ 1 ]
, tag - > uid [ 0 ]
, tag - > bytesPerPage
, tag - > pagesCount
) ;
2024-01-25 08:45:18 +08:00
}
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
bool button_pressed = false ;
2021-03-01 02:01:38 +08:00
int vHf ; // in mV
2020-08-13 18:25:04 +08:00
2020-07-20 02:45:47 +08:00
bool exit_loop = false ;
2024-01-16 22:20:01 +08:00
uint8_t cmd [ ISO15693_MAX_COMMAND_LENGTH ] = { 0 } ;
uint8_t recv [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
uint8_t mask_len = 0 ;
uint8_t maskCpt = 0 ;
uint8_t cmdCpt = 0 ;
uint16_t recvLen = 0 ;
uint8_t error = 0 ;
uint8_t pageNum = 0 ;
uint8_t nbPages = 0 ;
2024-01-19 23:30:11 +08:00
uint8_t pwdId = 0 ;
2024-01-16 22:20:01 +08:00
2020-07-20 02:45:47 +08:00
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
2024-01-16 22:20:01 +08:00
if ( tag - > state = = TAG_STATE_NO_FIELD ) {
2020-07-20 02:45:47 +08:00
vHf = ( MAX_ADC_HF_VOLTAGE * SumAdc ( ADC_CHAN_HF , 32 ) ) > > 15 ;
if ( vHf > MF_MINFIELDV ) {
2024-01-16 22:20:01 +08:00
tag - > state = TAG_STATE_READY ;
2020-07-20 02:45:47 +08:00
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-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 ;
break ;
2020-07-10 01:41:57 +08:00
}
2019-03-09 15:59:13 +08:00
2024-01-16 22:20:01 +08:00
if ( cmd_len < = 3 )
continue ;
// Shorten 0 terminated msgs
// (Some times received commands are prolonged with a random number of 0 bytes...)
2024-01-25 01:18:13 +08:00
while ( cmd [ cmd_len - 1 ] = = 0 ) {
2024-01-16 22:20:01 +08:00
cmd_len - - ;
if ( cmd_len < = 3 )
break ;
}
if ( g_dbglevel > = DBG_DEBUG ) {
Dbprintf ( " %d bytes read from reader: " , cmd_len ) ;
Dbhexdump ( cmd_len , cmd , false ) ;
}
if ( cmd_len < 3 )
continue ;
// Check CRC and drop received cmd with bad CRC
uint16_t crc = CalculateCrc15 ( cmd , cmd_len - 2 ) ;
2024-01-25 01:18:13 +08:00
if ( ( ( crc & 0xff ) ! = cmd [ cmd_len - 2 ] ) | | ( ( crc > > 8 ) ! = cmd [ cmd_len - 1 ] ) ) {
2024-01-16 22:20:01 +08:00
crc = CalculateCrc15 ( cmd , + + cmd_len - 2 ) ; // if crc end with 00
2024-01-25 01:18:13 +08:00
if ( ( ( crc & 0xff ) ! = cmd [ cmd_len - 2 ] ) | | ( ( crc > > 8 ) ! = cmd [ cmd_len - 1 ] ) ) {
2024-01-16 22:20:01 +08:00
crc = CalculateCrc15 ( cmd , + + cmd_len - 2 ) ; // if crc end with 00 00
2024-01-25 01:18:13 +08:00
if ( ( ( crc & 0xff ) ! = cmd [ cmd_len - 2 ] ) | | ( ( crc > > 8 ) ! = cmd [ cmd_len - 1 ] ) ) {
2024-01-19 20:52:34 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " CrcFail!, expected CRC=%02X%02X " , crc & 0xff , crc > > 8 ) ;
2024-01-25 01:18:13 +08:00
continue ;
} else if ( g_dbglevel > = DBG_DEBUG )
2024-01-16 22:20:01 +08:00
Dbprintf ( " CrcOK " ) ;
2024-01-25 01:18:13 +08:00
} else if ( g_dbglevel > = DBG_DEBUG )
2024-01-16 22:20:01 +08:00
Dbprintf ( " CrcOK " ) ;
2024-01-25 01:18:13 +08:00
} else if ( g_dbglevel > = DBG_DEBUG )
2024-01-16 22:20:01 +08:00
Dbprintf ( " CrcOK " ) ;
cmd_len - = 2 ; // remove the CRC from the cmd
recvLen = 0 ;
2024-01-19 20:52:34 +08:00
tag - > expectFast = ( ( cmd [ 0 ] & ISO15_REQ_DATARATE_HIGH ) = = ISO15_REQ_DATARATE_HIGH ) ;
tag - > expectFsk = ( ( cmd [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ) = = ISO15_REQ_SUBCARRIER_TWO ) ;
2024-01-16 22:20:01 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
if ( tag - > expectFsk )
Dbprintf ( " ISO15_REQ_SUBCARRIER_TWO support is currently experimental! " ) ;
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQ_PROTOCOL_EXT ) = = ISO15_REQ_PROTOCOL_EXT )
2024-01-16 22:20:01 +08:00
Dbprintf ( " ISO15_REQ_PROTOCOL_EXT not supported! " ) ;
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQ_OPTION ) = = ISO15_REQ_OPTION )
2024-01-16 22:20:01 +08:00
Dbprintf ( " ISO15_REQ_OPTION not supported! " ) ;
}
2024-01-19 20:52:34 +08:00
if ( ( ( cmd [ 0 ] & ISO15_REQ_INVENTORY ) = = ISO15_REQ_INVENTORY ) & & tag - > state ! = TAG_STATE_SILENCED ) {
2024-01-16 22:20:01 +08:00
// REQ_INVENTORY flaged requests are interpreted as a INVENTORY no matter
// what is the CMD (as observed from various actual tags)
// TODO: support colision avoidances
if ( g_dbglevel > = DBG_DEBUG ) {
Dbprintf ( " Inventory req " ) ;
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQINV_SLOT1 ) = = ISO15_REQINV_SLOT1 )
2024-01-16 22:20:01 +08:00
Dbprintf ( " ISO15_REQINV_SLOT1/SLOT16 not supported! " ) ;
}
cmdCpt = 2 ;
// Check AFI
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQINV_AFI ) = = ISO15_REQINV_AFI ) {
2024-01-16 22:20:01 +08:00
if ( cmd [ cmdCpt ] ! = tag - > afi & & cmd [ cmdCpt ] ! = 0 )
continue ; // bad AFI : drop request
cmdCpt + + ;
}
// Check mask
if ( cmdCpt > = cmd_len )
continue ; // mask is not present : drop request
mask_len = cmd [ cmdCpt + + ] ;
maskCpt = 0 ;
2024-01-24 22:47:39 +08:00
while ( mask_len > = 8 & & cmdCpt < ( uint8_t ) cmd_len & & maskCpt < 8 ) { // Byte comparison
2024-01-16 22:20:01 +08:00
if ( cmd [ cmdCpt + + ] ! = tag - > uid [ maskCpt + + ] ) {
error + + ; // mask don't match : drop request
break ;
}
mask_len - = 8 ;
}
if ( mask_len > 0 & & cmdCpt > = cmd_len )
continue ; // mask is shorter than declared mask lenght: drop request
while ( mask_len > 0 ) { // Bit comparison
mask_len - - ;
if ( ( ( cmd [ cmdCpt ] > > mask_len ) & 1 ) ! = ( ( tag - > uid [ maskCpt ] > > mask_len ) & 1 ) ) {
error + + ; // mask don't match : drop request
break ;
}
}
if ( error > 0 )
continue ;
// No error: Answer
recv [ 0 ] = ISO15_NOERROR ;
recv [ 1 ] = tag - > dsfid ;
memcpy ( & recv [ 2 ] , tag - > uid , 8 ) ;
recvLen = 10 ;
2024-01-25 01:18:13 +08:00
} else {
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQ_SELECT ) = = ISO15_REQ_SELECT ) {
2024-01-16 22:20:01 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Selected Request " ) ;
if ( tag - > state ! = TAG_STATE_SELECTED )
continue ; // drop selected request if not selected
tag - > state = TAG_STATE_READY ; // Select flag set if already selected : unselect
}
cmdCpt = 2 ;
2024-01-19 20:52:34 +08:00
if ( ( cmd [ 0 ] & ISO15_REQ_ADDRESS ) = = ISO15_REQ_ADDRESS ) {
2024-01-16 22:20:01 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Addressed Request " ) ;
2024-01-25 01:18:13 +08:00
if ( cmd_len < cmdCpt + 8 )
2024-01-16 22:20:01 +08:00
continue ;
2024-01-25 01:18:13 +08:00
if ( memcmp ( & cmd [ cmdCpt ] , tag - > uid , 8 ) ! = 0 ) {
if ( cmd_len < cmdCpt + 9 | | memcmp ( & cmd [ cmdCpt + 1 ] , tag - > uid , 8 ) ! = 0 ) {
// check uid even if manifacturer byte is present
2024-01-20 00:30:46 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Address don't match tag uid " ) ;
if ( cmd [ 1 ] = = ISO15693_SELECT )
tag - > state = TAG_STATE_READY ; // we are not anymore the selected TAG
continue ; // drop addressed request with other uid
}
2024-01-22 20:16:02 +08:00
cmdCpt + + ;
2024-01-16 22:20:01 +08:00
}
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Address match tag uid " ) ;
2024-01-25 01:18:13 +08:00
cmdCpt + = 8 ;
} else if ( tag - > state = = TAG_STATE_SILENCED ) {
2024-01-16 22:20:01 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Unaddressed request in quiet state: drop " ) ;
continue ; // drop unadressed request in quiet state
}
2024-01-25 01:18:13 +08:00
switch ( cmd [ 1 ] ) {
case ISO15693_INVENTORY :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Inventory cmd " ) ;
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
2024-01-25 01:18:13 +08:00
recv [ 1 ] = tag - > dsfid ;
memcpy ( & recv [ 2 ] , tag - > uid , 8 ) ;
recvLen = 10 ;
break ;
case ISO15693_STAYQUIET :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " StayQuiet cmd " ) ;
tag - > state = TAG_STATE_SILENCED ;
break ;
case ISO15693_READBLOCK :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " ReadBlock cmd " ) ;
pageNum = cmd [ cmdCpt + + ] ;
if ( pageNum > = tag - > pagesCount )
error = ISO15_ERROR_BLOCK_UNAVAILABLE ;
else {
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
if ( ( cmd [ 0 ] & ISO15_REQ_OPTION ) = = ISO15_REQ_OPTION ) { // ask for lock status
recv [ 1 ] = tag - > locks [ pageNum ] ;
recvLen + + ;
}
for ( uint8_t i = 0 ; i < tag - > bytesPerPage ; i + + )
recv [ recvLen + i ] = tag - > data [ ( pageNum * tag - > bytesPerPage ) + i ] ;
recvLen + = tag - > bytesPerPage ;
}
break ;
case ISO15693_WRITEBLOCK :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " WriteBlock cmd " ) ;
pageNum = cmd [ cmdCpt + + ] ;
if ( pageNum > = tag - > pagesCount )
error = ISO15_ERROR_BLOCK_UNAVAILABLE ;
else {
for ( uint8_t i = 0 ; i < tag - > bytesPerPage ; i + + )
tag - > data [ ( pageNum * tag - > bytesPerPage ) + i ] = cmd [ i + cmdCpt ] ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_LOCKBLOCK :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " LockBlock cmd " ) ;
pageNum = cmd [ cmdCpt + + ] ;
if ( pageNum > = tag - > pagesCount )
error = ISO15_ERROR_BLOCK_UNAVAILABLE ;
else if ( tag - > locks [ pageNum ] )
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY ;
else {
tag - > locks [ pageNum ] = 1 ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_READ_MULTI_BLOCK :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " ReadMultiBlock cmd " ) ;
pageNum = cmd [ cmdCpt + + ] ;
nbPages = cmd [ cmdCpt + + ] ;
if ( pageNum + nbPages > = tag - > pagesCount )
error = ISO15_ERROR_BLOCK_UNAVAILABLE ;
else {
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
for ( int i = 0 ; i < ( nbPages + 1 ) * tag - > bytesPerPage & & \
recvLen + 3 < ISO15693_MAX_RESPONSE_LENGTH ; i + + ) {
if ( ( i % tag - > bytesPerPage ) = = 0 & & ( cmd [ 0 ] & ISO15_REQ_OPTION ) )
recv [ recvLen + + ] = tag - > locks [ pageNum + ( i / tag - > bytesPerPage ) ] ;
recv [ recvLen + + ] = tag - > data [ ( pageNum * tag - > bytesPerPage ) + i ] ;
}
if ( recvLen + 3 > ISO15693_MAX_RESPONSE_LENGTH ) // limit response size
recvLen = ISO15693_MAX_RESPONSE_LENGTH - 3 ; // to avoid overflow
}
break ;
case ISO15693_WRITE_AFI :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " WriteAFI cmd " ) ;
if ( tag - > afiLock )
error = ISO15_ERROR_BLOCK_LOCKED ;
else {
tag - > afi = cmd [ cmdCpt + + ] ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_LOCK_AFI :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " LockAFI cmd " ) ;
if ( tag - > afiLock )
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY ;
else {
tag - > afiLock = true ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_WRITE_DSFID :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " WriteDSFID cmd " ) ;
if ( tag - > dsfidLock )
error = ISO15_ERROR_BLOCK_LOCKED ;
else {
tag - > dsfid = cmd [ cmdCpt + + ] ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_LOCK_DSFID :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " LockDSFID cmd " ) ;
if ( tag - > dsfidLock )
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY ;
else {
tag - > dsfidLock = true ;
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
}
break ;
case ISO15693_SELECT :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " Select cmd " ) ;
tag - > state = TAG_STATE_SELECTED ;
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
2024-01-25 01:18:13 +08:00
break ;
case ISO15693_RESET_TO_READY :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " ResetToReady cmd " ) ;
tag - > state = TAG_STATE_READY ;
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
2024-01-25 01:18:13 +08:00
break ;
case ISO15693_GET_SYSTEM_INFO :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " GetSystemInfo cmd " ) ;
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
2024-01-25 01:18:13 +08:00
recv [ 1 ] = 0x0f ; // sysinfo contain all info
memcpy ( & recv [ 2 ] , tag - > uid , 8 ) ;
recv [ 10 ] = tag - > dsfid ;
recv [ 11 ] = tag - > afi ;
recv [ 12 ] = tag - > pagesCount - 1 ;
recv [ 13 ] = tag - > bytesPerPage - 1 ;
recv [ 14 ] = tag - > ic ;
recvLen = 15 ;
break ;
case ISO15693_READ_MULTI_SECSTATUS :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " ReadMultiSecStatus cmd " ) ;
pageNum = cmd [ cmdCpt + + ] ;
nbPages = cmd [ cmdCpt + + ] ;
if ( pageNum + nbPages > = tag - > pagesCount )
error = ISO15_ERROR_BLOCK_UNAVAILABLE ;
else {
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
for ( uint8_t i = 0 ; i < nbPages + 1 ; i + + )
recv [ recvLen + + ] = tag - > locks [ pageNum + i ] ;
2024-01-16 22:20:01 +08:00
}
2024-01-25 01:18:13 +08:00
break ;
case ISO15693_GET_RANDOM_NUMBER :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " GetRandomNumber cmd " ) ;
tag - > random [ 0 ] = ( uint8_t ) ( reader_eof_time ) ^ 0xFF ; // poor random number
tag - > random [ 1 ] = ( uint8_t ) ( reader_eof_time > > 8 ) ^ 0xFF ;
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
2024-01-25 01:18:13 +08:00
recv [ 1 ] = tag - > random [ 0 ] ; // poor random number
recv [ 2 ] = tag - > random [ 1 ] ;
recvLen = 3 ;
break ;
case ISO15693_SET_PASSWORD :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " SetPassword cmd " ) ;
if ( cmd_len > cmdCpt + 5 )
cmdCpt + + ; // skip manifacturer code
if ( cmd_len > cmdCpt + 4 ) {
pwdId = cmd [ cmdCpt + + ] ;
if ( pwdId = = 4 ) { // Privacy password
tag - > privacyPasswd [ 0 ] = cmd [ cmdCpt ] ^ tag - > random [ 0 ] ;
tag - > privacyPasswd [ 1 ] = cmd [ cmdCpt + 1 ] ^ tag - > random [ 1 ] ;
tag - > privacyPasswd [ 2 ] = cmd [ cmdCpt + 2 ] ^ tag - > random [ 0 ] ;
tag - > privacyPasswd [ 3 ] = cmd [ cmdCpt + 3 ] ^ tag - > random [ 1 ] ;
}
}
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
2024-01-25 01:18:13 +08:00
break ;
case ISO15693_ENABLE_PRIVACY :
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " EnablePrivacy cmd " ) ;
// not realy entering privacy mode
// just return NOERROR
2024-01-16 22:20:01 +08:00
recv [ 0 ] = ISO15_NOERROR ;
recvLen = 1 ;
2024-01-25 01:18:13 +08:00
break ;
default :
if ( g_dbglevel > = DBG_DEBUG )
Dbprintf ( " ISO15693 CMD 0x%2X not supported " , cmd [ 1 ] ) ;
2024-01-16 22:20:01 +08:00
2024-01-25 01:18:13 +08:00
error = ISO15_ERROR_CMD_NOT_SUP ;
break ;
2024-01-16 22:20:01 +08:00
}
if ( error ! = 0 ) { // Error happened
recv [ 0 ] = ISO15_RES_ERROR ;
recv [ 1 ] = error ;
recvLen = 2 ;
2024-01-19 23:04:12 +08:00
error = 0 ;
2024-01-16 22:20:01 +08:00
if ( g_dbglevel > = DBG_DEBUG )
Dbprintf ( " ERROR 0x%2X in received request " , error ) ;
}
}
if ( recvLen > 0 ) { // We need to answer
AddCrc15 ( recv , recvLen ) ;
recvLen + = 2 ;
CodeIso15693AsTag ( recv , recvLen ) ;
2024-05-14 18:40:26 +08:00
const tosend_t * ts = get_tosend ( ) ;
2024-01-16 22:20:01 +08:00
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM ;
if ( tag - > expectFsk ) { // Not suppoted yet
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " %ERROR: FSK answers are not supported yet " ) ;
//TransmitTo15693ReaderFSK(ts->buf,ts->max, &response_time, 0, !tag->expectFast);
2024-01-25 01:18:13 +08:00
} else
2024-01-16 22:20:01 +08:00
TransmitTo15693Reader ( ts - > buf , ts - > max , & response_time , 0 , ! tag - > expectFast ) ;
LogTrace_ISO15693 ( recv , recvLen , 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
2024-01-25 08:45:18 +08:00
if ( button_pressed ) {
2020-07-20 02:45:47 +08:00
DbpString ( " button pressed " ) ;
2024-01-25 08:45:18 +08:00
}
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)
2024-01-14 21:23:51 +08:00
void BruteforceIso15693Afi ( uint32_t flags ) {
clear_trace ( ) ;
2016-08-05 03:37:43 +08:00
2019-03-10 03:34:41 +08:00
Iso15693InitReader ( ) ;
2024-01-14 21:23:51 +08:00
bool speed = ( ( flags & ISO15_HIGH_SPEED ) = = ISO15_HIGH_SPEED ) ;
2019-03-10 03:34:41 +08:00
// first without AFI
2021-10-10 07:35:38 +08:00
// Tags should respond without AFI and with AFI=0 even when AFI is active
2024-01-14 21:23:51 +08:00
uint8_t data [ 7 ] = { 0 } ;
uint8_t recv [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0 } ;
2019-03-10 03:34:41 +08:00
2024-01-14 21:23:51 +08:00
data [ 0 ] = ( ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1 ) ;
2021-05-03 15:35:38 +08:00
data [ 1 ] = ISO15693_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 ;
2022-03-24 00:37:40 +08: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-10 03:34:41 +08:00
2022-03-24 00:37:40 +08:00
uint32_t 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 ) ) ;
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
2022-03-24 00:37:40 +08:00
recvlen = 0 ;
res = SendDataTag ( data , datalen , false , speed , recv , sizeof ( recv ) , start_time , ISO15693_READER_TIMEOUT , & eof_time , & recvlen ) ;
2020-07-10 01:41:57 +08:00
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
}
2022-03-24 00:37:40 +08:00
aborted = ( BUTTON_PRESS ( ) & & data_available ( ) ) ;
2019-11-28 03:14:31 +08:00
if ( aborted ) {
2019-03-10 03:34:41 +08:00
break ;
}
}
DbpString ( " AFI Bruteforcing done. " ) ;
switch_off ( ) ;
2019-11-27 21:11:43 +08:00
if ( aborted ) {
2021-04-07 05:37:45 +08:00
reply_ng ( CMD_HF_ISO15693_FINDAFI , PM3_EOPABORTED , NULL , 0 ) ;
2019-11-27 21:11:43 +08:00
} else {
2021-04-07 05:37:45 +08:00
reply_ng ( CMD_HF_ISO15693_FINDAFI , PM3_SUCCESS , NULL , 0 ) ;
2019-11-27 21:11:43 +08:00
}
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.
2024-01-14 21:23:51 +08:00
void SendRawCommand15693 ( iso15_raw_cmd_t * packet ) {
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
2024-01-14 21:23:51 +08:00
uint16_t timeout = ISO15693_READER_TIMEOUT ;
if ( ( packet - > flags & ISO15_LONG_WAIT ) = = ISO15_LONG_WAIT ) {
timeout = ISO15693_READER_TIMEOUT_WRITE ;
}
bool speed = ( ( packet - > flags & ISO15_HIGH_SPEED ) = = ISO15_HIGH_SPEED ) ;
bool keep_field_on = ( ( packet - > flags & ISO15_NO_DISCONNECT ) = = ISO15_NO_DISCONNECT ) ;
bool read_respone = ( ( packet - > flags & ISO15_READ_RESPONSE ) = = ISO15_READ_RESPONSE ) ;
bool init = ( ( packet - > flags & ISO15_CONNECT ) = = ISO15_CONNECT ) ;
2020-08-13 18:25:04 +08:00
2024-01-14 21:23:51 +08:00
// This is part of ISO15693 protocol definitions where the following commands needs to request option.
2024-01-15 08:14:58 +08:00
// note:
// it seem like previous we just guessed and never followed the fISO145_REQ_OPTION flag if it was set / not set from client side.
2024-01-15 20:08:55 +08:00
// this is a problem. Since without this the response from the tag is one byte shorter. And a lot of client side functions has been
2024-01-15 08:14:58 +08:00
// hardcoded to assume for the extra byte in the response.
2024-01-14 21:23:51 +08:00
bool request_answer = false ;
2024-01-15 08:14:58 +08:00
2024-01-14 21:23:51 +08:00
switch ( packet - > raw [ 1 ] ) {
case ISO15693_SET_PASSWORD :
case ISO15693_ENABLE_PRIVACY :
2021-05-03 15:35:38 +08:00
case ISO15693_WRITEBLOCK :
case ISO15693_LOCKBLOCK :
case ISO15693_WRITE_MULTI_BLOCK :
case ISO15693_WRITE_AFI :
case ISO15693_LOCK_AFI :
case ISO15693_WRITE_DSFID :
2023-01-28 12:46:40 +08:00
case ISO15693_WRITE_PASSWORD :
case ISO15693_PASSWORD_PROTECT_EAS :
2021-05-03 15:35:38 +08:00
case ISO15693_LOCK_DSFID :
2024-01-14 21:23:51 +08:00
request_answer = ( ( packet - > raw [ 0 ] & ISO15_REQ_OPTION ) = = ISO15_REQ_OPTION ) ;
2020-07-10 01:41:57 +08:00
break ;
default :
2024-01-14 21:23:51 +08:00
break ;
2020-08-13 18:25:04 +08:00
}
2019-03-10 03:34:41 +08:00
2024-01-14 21:23:51 +08:00
uint32_t eof_time = 0 ;
2020-08-14 20:56:20 +08:00
uint32_t start_time = 0 ;
2022-03-24 00:37:40 +08:00
uint16_t recvlen = 0 ;
2024-01-14 21:23:51 +08:00
uint8_t buf [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0x00 } ;
int res = SendDataTag ( packet - > raw , packet - > rawlen , init , speed , ( read_respone ? buf : NULL ) , sizeof ( buf ) , start_time , timeout , & eof_time , & recvlen ) ;
2022-03-24 00:37:40 +08:00
if ( res = = PM3_ETEAROFF ) { // tearoff occurred
reply_ng ( CMD_HF_ISO15693_COMMAND , res , NULL , 0 ) ;
2020-10-14 04:43:28 +08:00
} else {
2020-07-02 18:37:07 +08:00
2024-01-15 11:11:20 +08:00
// if tag answers with an error code, it don't care about EOF packet
if ( recvlen ) {
recvlen = MIN ( recvlen , ISO15693_MAX_RESPONSE_LENGTH ) ;
reply_ng ( CMD_HF_ISO15693_COMMAND , res , buf , recvlen ) ;
}
2024-01-14 21:23:51 +08:00
// looking at the first byte of the RAW bytes to determine Subcarrier, datarate, request option
2024-01-15 08:14:58 +08:00
bool fsk = ( ( packet - > raw [ 0 ] & ISO15_REQ_SUBCARRIER_TWO ) = = ISO15_REQ_SUBCARRIER_TWO ) ;
bool recv_speed = ( ( packet - > raw [ 0 ] & ISO15_REQ_DATARATE_HIGH ) = = ISO15_REQ_DATARATE_HIGH ) ;
2022-03-16 22:45:18 +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 ;
2024-01-14 21:23:51 +08:00
res = SendDataTagEOF ( ( read_respone ? buf : NULL ) , sizeof ( buf ) , start_time , ISO15693_READER_TIMEOUT , & eof_time , fsk , recv_speed , & recvlen ) ;
2020-07-10 01:41:57 +08:00
}
2020-08-17 14:52:24 +08:00
2024-01-14 21:23:51 +08:00
if ( read_respone ) {
2020-10-20 07:00:23 +08:00
recvlen = MIN ( recvlen , ISO15693_MAX_RESPONSE_LENGTH ) ;
2024-01-14 21:23:51 +08:00
reply_ng ( CMD_HF_ISO15693_COMMAND , res , buf , recvlen ) ;
2020-10-14 04:43:28 +08:00
} else {
2022-03-24 00:37:40 +08:00
reply_ng ( CMD_HF_ISO15693_COMMAND , PM3_SUCCESS , NULL , 0 ) ;
2020-07-10 01:41:57 +08:00
}
2019-03-10 03:34:41 +08:00
}
2022-03-24 00:37:40 +08:00
2024-01-14 21:23:51 +08:00
if ( keep_field_on = = false ) {
switch_off ( ) ; // disconnect raw
SpinDelay ( 20 ) ;
}
LED_A_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 ;
2022-03-24 01:22:03 +08:00
uint16_t recvlen = 0 ;
2020-10-07 02:44:23 +08:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint32_t start_time = 0 ;
bool done = false ;
2022-03-24 00:37:40 +08:00
int res ;
2020-10-07 02:44:23 +08: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-24 00:37:40 +08: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-07 02:44:23 +08: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-24 00:37:40 +08: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-07 02:44:23 +08: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-24 00:37:40 +08:00
res = SendDataTag ( cmd_inventory , sizeof ( cmd_inventory ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 12 ) {
2020-10-07 02:44:23 +08: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-24 00:37:40 +08: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-07 02:44:23 +08: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 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).
2022-01-06 22:40:11 +08:00
void SetTag15693Uid ( const uint8_t * uid ) {
2020-07-02 18:37:07 +08:00
2020-07-10 01:41:57 +08:00
LED_A_ON ( ) ;
uint8_t cmd [ 4 ] [ 9 ] = {
2024-01-16 00:14:04 +08:00
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x3e , 0x00 , 0x00 , 0x00 , 0x00 , 0xE9 , 0x8F } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x3f , 0x69 , 0x96 , 0x00 , 0x00 , 0x8A , 0xBB } ,
2020-07-10 01:41:57 +08:00
2024-04-22 15:04:01 +08:00
// Command 3 : 02 21 38 u8u7u6u5 (where uX = uid byte X)
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x38 , uid [ 7 ] , uid [ 6 ] , uid [ 5 ] , uid [ 4 ] } ,
// Command 4 : 02 21 39 u4u3u2u1 (where uX = uid byte X)
{ ISO15_REQ_DATARATE_HIGH , ISO15693_WRITEBLOCK , 0x39 , uid [ 3 ] , uid [ 2 ] , uid [ 1 ] , uid [ 0 ] }
} ;
2020-07-10 01:41:57 +08:00
2020-07-02 18:37:07 +08:00
AddCrc15 ( cmd [ 2 ] , 7 ) ;
AddCrc15 ( cmd [ 3 ] , 7 ) ;
2024-01-16 00:14:04 +08:00
uint8_t buf [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0x00 } ;
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 ;
2022-03-24 00:37:40 +08:00
uint16_t recvlen = 0 ;
2024-01-16 00:14:04 +08:00
2022-03-24 00:37:40 +08:00
int res = PM3_SUCCESS ;
2024-01-16 00:14:04 +08:00
2020-07-10 01:41:57 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
2022-03-24 00:37:40 +08:00
res = SendDataTag (
2024-01-16 18:53:42 +08:00
cmd [ i ] ,
sizeof ( cmd [ i ] ) ,
( i = = 0 ) ? true : false ,
true ,
buf ,
sizeof ( buf ) ,
start_time ,
ISO15693_READER_TIMEOUT_WRITE ,
& eof_time ,
& recvlen
) ;
2024-01-16 00:14:04 +08:00
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
2022-03-24 00:37:40 +08:00
reply_ng ( CMD_HF_ISO15693_CSETUID , res , NULL , 0 ) ;
2020-08-17 14:52:24 +08:00
switch_off ( ) ;
2020-09-07 16:39:15 +08:00
}
2021-05-04 15:40:30 +08:00
2024-04-22 15:04:01 +08:00
// Set the UID on Magic ISO15693 tag ( Gen2 ?)
// E0 00 09 - seem to be command
// 0x41, 0x40 - seem to be block referens
void SetTag15693Uid_v2 ( const uint8_t * uid ) {
LED_A_ON ( ) ;
2024-04-22 21:41:59 +08:00
uint8_t cmd [ 4 ] [ 10 ] = {
{ ISO15_REQ_DATARATE_HIGH , ISO15693_MAGIC_WRITE , 0x09 , 0x47 , 0x3f , 0x03 , 0x8b , 0x00 , 0x00 , 0x00 } ,
{ ISO15_REQ_DATARATE_HIGH , ISO15693_MAGIC_WRITE , 0x09 , 0x52 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ,
// hf 15 raw -wac -d 02 e0 09 41 + uid first four bytes
2024-04-22 23:30:52 +08:00
{ ISO15_REQ_DATARATE_HIGH , ISO15693_MAGIC_WRITE , 0x09 , 0x40 , uid [ 7 ] , uid [ 6 ] , uid [ 5 ] , uid [ 4 ] , 0x00 , 0x00 } ,
2024-04-22 21:41:59 +08:00
// hf 15 raw -wac -d 02 e0 09 40 + uid last four bytes
2024-04-22 23:30:52 +08:00
{ ISO15_REQ_DATARATE_HIGH , ISO15693_MAGIC_WRITE , 0x09 , 0x41 , uid [ 3 ] , uid [ 2 ] , uid [ 1 ] , uid [ 0 ] , 0x00 , 0x00 }
2024-04-22 15:04:01 +08:00
} ;
uint8_t buf [ ISO15693_MAX_RESPONSE_LENGTH ] = { 0x00 } ;
uint32_t start_time = 0 ;
uint32_t eof_time = 0 ;
uint16_t recvlen = 0 ;
int res = PM3_SUCCESS ;
2024-04-22 21:41:59 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
2024-04-22 22:55:54 +08:00
AddCrc15 ( cmd [ i ] , 8 ) ;
2024-04-22 15:04:01 +08:00
res = SendDataTag (
cmd [ i ] ,
sizeof ( cmd [ i ] ) ,
( i = = 0 ) ? true : false ,
true ,
buf ,
sizeof ( buf ) ,
start_time ,
ISO15693_READER_TIMEOUT_WRITE ,
& eof_time ,
& recvlen
) ;
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
}
reply_ng ( CMD_HF_ISO15693_CSETUID_V2 , res , NULL , 0 ) ;
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
static void init_password_15693_Slix ( uint8_t * buffer , const uint8_t * pwd , const uint8_t * rnd ) {
2021-05-04 15:40:30 +08:00
memcpy ( buffer , pwd , 4 ) ;
2021-05-06 03:04:48 +08:00
if ( rnd ) {
buffer [ 0 ] ^ = rnd [ 0 ] ;
buffer [ 1 ] ^ = rnd [ 1 ] ;
buffer [ 2 ] ^ = rnd [ 0 ] ;
buffer [ 3 ] ^ = rnd [ 1 ] ;
}
2021-05-04 15:40:30 +08:00
}
2023-01-28 12:46:40 +08:00
static bool get_rnd_15693_Slix ( uint32_t start_time , uint32_t * eof_time , uint8_t * rnd ) {
2021-05-04 15:40:30 +08:00
// 0x04, == NXP from manufacture id list.
2021-05-06 03:04:48 +08:00
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , ISO15693_GET_RANDOM_NUMBER , 0x04 , 0x00 , 0x00 } ;
AddCrc15 ( c , 3 ) ;
2021-05-04 15:40:30 +08:00
2021-05-06 03:04:48 +08:00
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-24 00:37:40 +08:00
uint16_t recvlen = 0 ;
2023-01-28 12:46:40 +08:00
int res = SendDataTag ( c , sizeof ( c ) , true , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
2022-03-24 00:37:40 +08:00
if ( res ! = PM3_SUCCESS & & recvlen ! = 5 ) {
2021-05-06 03:04:48 +08:00
return false ;
}
2021-05-04 15:40:30 +08:00
2021-05-06 03:04:48 +08:00
if ( rnd ) {
memcpy ( rnd , & recvbuf [ 1 ] , 2 ) ;
}
return true ;
2021-05-04 15:40:30 +08:00
}
2023-08-15 13:45:48 +08:00
static uint32_t disable_privacy_15693_Slix ( uint32_t start_time , uint32_t * eof_time , uint8_t pass_id , const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
2021-05-06 03:04:48 +08:00
uint8_t rnd [ 2 ] ;
2023-01-28 12:46:40 +08:00
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
2021-05-06 03:04:48 +08:00
return PM3_ETIMEOUT ;
}
2021-05-04 15:40:30 +08:00
// 0x04, == NXP from manufacture id list.
2023-01-28 12:46:40 +08:00
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , ISO15693_SET_PASSWORD , 0x04 , pass_id , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
init_password_15693_Slix ( & c [ 4 ] , password , rnd ) ;
2021-05-06 03:04:48 +08:00
AddCrc15 ( c , 8 ) ;
2021-05-04 15:40:30 +08:00
2021-05-06 03:04:48 +08:00
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
2022-03-24 00:37:40 +08: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-06 03:04:48 +08:00
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2021-05-04 15:40:30 +08:00
}
2024-05-14 18:40:26 +08:00
static uint32_t set_pass_15693_Slix ( uint32_t start_time , uint32_t * eof_time , uint8_t pass_id , const uint8_t * password , const uint8_t * uid ) {
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
// 0x04, == NXP from manufacture id list.
2023-01-29 11:59:50 +08:00
uint8_t c [ ] = { ( ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS ) , ISO15693_SET_PASSWORD , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , pass_id , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2023-01-28 12:46:40 +08:00
init_password_15693_Slix ( & c [ 12 ] , password , rnd ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
memcpy ( & c [ 3 ] , uid , 8 ) ;
AddCrc15 ( c , 16 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t recvlen = 0 ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
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 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
}
2023-08-15 13:45:48 +08:00
static uint32_t set_privacy_15693_Slix ( uint32_t start_time , uint32_t * eof_time , const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
// 0x04, == NXP from manufacture id list.
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , 0xBA , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
init_password_15693_Slix ( & c [ 3 ] , password , rnd ) ;
AddCrc15 ( c , 7 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
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 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
}
2023-08-15 13:45:48 +08:00
static uint32_t disable_eas_15693_Slix ( uint32_t start_time , uint32_t * eof_time , const uint8_t * password , bool usepwd ) {
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t uid [ 8 ] ;
get_uid_slix ( start_time , eof_time , uid ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
2023-01-29 11:59:50 +08:00
if ( usepwd ) {
int res_setpass = set_pass_15693_Slix ( start_time , eof_time , 0x10 , password , uid ) ;
if ( res_setpass ! = PM3_SUCCESS ) {
return PM3_EWRONGANSWER ;
}
}
// 0x04, == NXP from manufacture id list.
2023-01-28 12:46:40 +08:00
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , 0xA3 , 0x04 , 0x00 , 0x00 } ;
AddCrc15 ( c , 3 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
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 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
}
2023-08-15 13:45:48 +08:00
static uint32_t enable_eas_15693_Slix ( uint32_t start_time , uint32_t * eof_time , const uint8_t * password , bool usepwd ) {
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t uid [ 8 ] ;
get_uid_slix ( start_time , eof_time , uid ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
2023-01-29 11:59:50 +08:00
if ( usepwd ) {
int res_setpass = set_pass_15693_Slix ( start_time , eof_time , 0x10 , password , uid ) ;
if ( res_setpass ! = PM3_SUCCESS ) {
return PM3_EWRONGANSWER ;
}
2023-01-28 12:46:40 +08:00
}
// 0x04, == NXP from manufacture id list.
uint8_t c [ ] = { ISO15_REQ_DATARATE_HIGH , 0xA2 , 0x04 , 0x00 , 0x00 } ;
//init_password_15693_Slix(&c[3], password, rnd);
AddCrc15 ( c , 3 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
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 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
}
2024-05-14 18:40:26 +08:00
static uint32_t write_password_15693_Slix ( uint32_t start_time , uint32_t * eof_time , uint8_t pwd_id , const uint8_t * password , const uint8_t * uid ) {
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
uint8_t new_pwd_cmd [ ] = { ( ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS ) , ISO15693_WRITE_PASSWORD , 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , pwd_id , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
memcpy ( & new_pwd_cmd [ 3 ] , uid , 8 ) ;
memcpy ( & new_pwd_cmd [ 12 ] , password , 4 ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
AddCrc15 ( new_pwd_cmd , 16 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t recvlen = 0 ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
int res_wrp = SendDataTag ( new_pwd_cmd , sizeof ( new_pwd_cmd ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res_wrp ! = PM3_SUCCESS & & recvlen ! = 3 ) {
return PM3_EWRONGANSWER ;
}
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
return PM3_SUCCESS ;
}
2023-08-15 13:45:48 +08:00
static uint32_t pass_protect_EASAFI_15693_Slix ( uint32_t start_time , uint32_t * eof_time , bool set_option_flag , const uint8_t * password ) {
2023-01-29 11:59:50 +08:00
uint8_t flags ;
if ( set_option_flag )
flags = ISO15_REQ_DATARATE_HIGH | ISO15_REQ_OPTION ;
else
flags = ISO15_REQ_DATARATE_HIGH ;
uint8_t uid [ 8 ] ;
get_uid_slix ( start_time , eof_time , uid ) ;
uint8_t rnd [ 2 ] ;
if ( get_rnd_15693_Slix ( start_time , eof_time , rnd ) = = false ) {
return PM3_ETIMEOUT ;
}
2023-01-28 12:46:40 +08:00
int res_setpass = set_pass_15693_Slix ( start_time , eof_time , 0x10 , password , uid ) ;
2023-01-29 11:59:50 +08:00
if ( res_setpass ! = PM3_SUCCESS ) {
return PM3_EWRONGANSWER ;
}
uint8_t new_pass_protect_cmd [ ] = { flags , ISO15693_PASSWORD_PROTECT_EAS , 0x04 , 0x00 , 0x00 } ;
AddCrc15 ( new_pass_protect_cmd , 3 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t recvlen = 0 ;
int res = SendDataTag ( new_pass_protect_cmd , sizeof ( new_pass_protect_cmd ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS & & recvlen ! = 3 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
}
2023-08-15 13:45:48 +08:00
static uint32_t write_afi_15693 ( uint32_t start_time , uint32_t * eof_time , const uint8_t * password , bool usepwd , uint8_t * uid , bool use_uid , uint8_t afi ) {
2023-01-29 11:59:50 +08:00
if ( ! use_uid ) {
int res_getuid = get_uid_slix ( start_time , eof_time , uid ) ;
if ( res_getuid ! = PM3_SUCCESS ) {
return res_getuid ;
}
}
if ( usepwd ) {
int res_setpass = set_pass_15693_Slix ( start_time , eof_time , 0x10 , password , uid ) ;
if ( res_setpass ! = PM3_SUCCESS ) {
return PM3_EWRONGANSWER ;
}
}
uint8_t cmd [ ] = { ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS , ISO15693_WRITE_AFI , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
memcpy ( & cmd [ 2 ] , uid , 8 ) ;
cmd [ 10 ] = afi ;
AddCrc15 ( cmd , 11 ) ;
start_time = * eof_time + DELAY_ISO15693_VICC_TO_VCD_READER ;
uint8_t recvbuf [ ISO15693_MAX_RESPONSE_LENGTH ] ;
uint16_t recvlen = 0 ;
int res = SendDataTag ( cmd , sizeof ( cmd ) , false , true , recvbuf , sizeof ( recvbuf ) , start_time , ISO15693_READER_TIMEOUT_WRITE , eof_time , & recvlen ) ;
if ( res ! = PM3_SUCCESS | | recvlen ! = 3 ) {
return PM3_EWRONGANSWER ;
}
return PM3_SUCCESS ;
2023-01-28 12:46:40 +08:00
}
2023-08-15 13:45:48 +08:00
void WritePasswordSlixIso15693 ( const uint8_t * old_password , const uint8_t * new_password , uint8_t pwd_id ) {
2023-01-29 11:59:50 +08:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
int res = PM3_EFAILED ;
uint8_t uid [ 8 ] ;
get_uid_slix ( start_time , & eof_time , uid ) ;
res = set_pass_15693_Slix ( start_time , & eof_time , pwd_id , old_password , uid ) ;
if ( res ! = PM3_SUCCESS ) {
reply_ng ( CMD_HF_ISO15693_SLIX_WRITE_PWD , res , NULL , 0 ) ;
switch_off ( ) ;
return ;
}
res = write_password_15693_Slix ( start_time , & eof_time , pwd_id , new_password , uid ) ;
2023-01-28 12:46:40 +08:00
reply_ng ( CMD_HF_ISO15693_SLIX_WRITE_PWD , res , NULL , 0 ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
switch_off ( ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
}
2023-08-15 13:45:48 +08:00
void DisablePrivacySlixIso15693 ( const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
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 = disable_privacy_15693_Slix ( start_time , & eof_time , 0x04 , password ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_DISABLE_PRIVACY , res , NULL , 0 ) ;
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
void EnablePrivacySlixIso15693 ( const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
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_privacy_15693_Slix ( start_time , & eof_time , password ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_ENABLE_PRIVACY , res , NULL , 0 ) ;
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
void DisableEAS_AFISlixIso15693 ( const uint8_t * password , bool usepwd ) {
2021-05-06 03:04:48 +08:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
2022-02-19 01:23:53 +08:00
// Password identifier Password byte
// 0x04 Privacy
// 0x08 Destroy SLIX-L
// 0x10 EAS/AFI
2023-01-28 12:46:40 +08:00
int res = disable_eas_15693_Slix ( start_time , & eof_time , password , usepwd ) ;
2023-01-29 11:59:50 +08:00
2023-01-28 12:46:40 +08:00
reply_ng ( CMD_HF_ISO15693_SLIX_DISABLE_EAS , res , NULL , 0 ) ;
2021-05-04 15:40:30 +08:00
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
void EnableEAS_AFISlixIso15693 ( const uint8_t * password , bool usepwd ) {
2022-02-19 01:23:53 +08:00
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
2023-01-28 12:46:40 +08:00
int res = enable_eas_15693_Slix ( start_time , & eof_time , password , usepwd ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_ENABLE_EAS , res , NULL , 0 ) ;
2022-02-19 01:23:53 +08:00
switch_off ( ) ;
}
2021-05-04 15:40:30 +08:00
2023-08-15 13:45:48 +08:00
void PassProtextEASSlixIso15693 ( const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
int res = pass_protect_EASAFI_15693_Slix ( start_time , & eof_time , false , password ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_PASS_PROTECT_EAS , res , NULL , 0 ) ;
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
void PassProtectAFISlixIso15693 ( const uint8_t * password ) {
2023-01-28 12:46:40 +08:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
int res = pass_protect_EASAFI_15693_Slix ( start_time , & eof_time , true , password ) ;
reply_ng ( CMD_HF_ISO15693_SLIX_PASS_PROTECT_AFI , res , NULL , 0 ) ;
switch_off ( ) ;
}
2023-08-15 13:45:48 +08:00
void WriteAFIIso15693 ( const uint8_t * password , bool use_pwd , uint8_t * uid , bool use_uid , uint8_t afi ) {
2023-01-28 12:46:40 +08:00
LED_D_ON ( ) ;
Iso15693InitReader ( ) ;
StartCountSspClk ( ) ;
uint32_t start_time = 0 , eof_time = 0 ;
int res = write_afi_15693 ( start_time , & eof_time , password , use_pwd , uid , use_uid , afi ) ;
reply_ng ( CMD_HF_ISO15693_WRITE_AFI , res , NULL , 0 ) ;
switch_off ( ) ;
2023-01-29 11:59:50 +08:00
}