2017-01-05 08:51:47 +08:00
//-----------------------------------------------------------------------------
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
2017-07-30 15:17:48 +08:00
// Low frequency fdx-b tag commands
// Differential Biphase, rf/32, 128 bits (known)
2017-01-05 08:51:47 +08:00
//-----------------------------------------------------------------------------
2020-10-12 04:38:52 +08:00
# include "cmdlffdxb.h"
2017-01-05 08:51:47 +08:00
2019-08-08 22:57:33 +08:00
# include <inttypes.h>
# include <string.h>
# include <stdlib.h>
2019-10-30 22:44:57 +08:00
# include <ctype.h> // tolower
2019-08-08 22:57:33 +08:00
# include "cmdparser.h" // command_t
# include "comms.h"
# include "commonutil.h"
# include "ui.h" // PrintAndLog
# include "cmddata.h"
# include "cmdlf.h" // lf read
# include "crc16.h" // for checksum crc-16_ccitt
# include "protocols.h" // for T55xx config register definitions
# include "lfdemod.h" // parityTest
2019-09-16 17:11:54 +08:00
# include "cmdlft55xx.h" // verifywrite
2019-08-08 22:57:33 +08:00
2017-01-05 08:51:47 +08:00
/*
2019-03-10 06:35:06 +08:00
FDX - B ISO11784 / 85 demod ( aka animal tag ) BIPHASE , inverted , rf / 32 , with preamble of 00000000001 ( 128 bits )
8 databits + 1 parity ( 1 )
CIITT 16 checksum
NATIONAL CODE , ICAR database
COUNTRY CODE ( ISO3166 ) or http : //cms.abvma.ca/uploads/ManufacturersISOsandCountryCodes.pdf
FLAG ( animal / non - animal )
38 IDbits
10 country code
1 extra app bit
14 reserved bits
1 animal bit
16 ccitt CRC chksum over 64 bit ID CODE .
24 appli bits .
sample : 985121004515220 [ 37FF 65 B88EF94 ]
2017-01-05 08:51:47 +08:00
*/
static int CmdHelp ( const char * Cmd ) ;
2020-10-12 04:38:52 +08:00
static int usage_lf_fdxb_clone ( void ) {
2020-08-28 17:14:42 +08:00
PrintAndLogEx ( NORMAL , " Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag. " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( NORMAL , " Usage: lf fdxb clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5> " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( NORMAL , " h : This help " ) ;
PrintAndLogEx ( NORMAL , " c <country> : (dec) Country code " ) ;
PrintAndLogEx ( NORMAL , " n <national> : (dec) National code " ) ;
PrintAndLogEx ( NORMAL , " e <extended> : (hex) Extended data " ) ;
PrintAndLogEx ( NORMAL , " s : Set animal bit " ) ;
PrintAndLogEx ( NORMAL , " <Q5> : Specify writing to Q5/T5555 tag " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( NORMAL , _YELLOW_ ( " lf fdxb clone c 999 n 112233 s " ) ) ;
PrintAndLogEx ( NORMAL , _YELLOW_ ( " lf fdxb clone c 999 n 112233 e 16a " ) ) ;
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2017-01-05 08:51:47 +08:00
}
2020-10-12 04:38:52 +08:00
static int usage_lf_fdxb_read ( void ) {
2020-09-17 08:43:46 +08:00
PrintAndLogEx ( NORMAL , " Read FDX-B animal tag " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( NORMAL , " Usage: lf fdxb read [h] [@] " ) ;
2020-09-17 08:43:46 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h : This help " ) ;
PrintAndLogEx ( NORMAL , " @ : run continuously until a key is pressed (optional) " ) ;
PrintAndLogEx ( NORMAL , " Note that the continuous mode is less verbose " ) ;
return PM3_SUCCESS ;
}
2020-10-12 04:38:52 +08:00
static int usage_lf_fdxb_sim ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Enables simulation of FDX-B animal tag " ) ;
PrintAndLogEx ( NORMAL , " Simulation runs until the button is pressed or another USB command is issued. " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( NORMAL , " Usage: lf fdxb sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5> " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( NORMAL , " h : This help " ) ;
PrintAndLogEx ( NORMAL , " c <country> : (dec) Country code " ) ;
PrintAndLogEx ( NORMAL , " n <national> : (dec) National code " ) ;
PrintAndLogEx ( NORMAL , " e <extended> : (hex) Extended data " ) ;
PrintAndLogEx ( NORMAL , " s : Set animal bit " ) ;
PrintAndLogEx ( NORMAL , " <Q5> : Specify writing to Q5/T5555 tag " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( NORMAL , _YELLOW_ ( " lf fdxb sim c 999 n 112233 s " ) ) ;
PrintAndLogEx ( NORMAL , _YELLOW_ ( " lf fdxb sim c 999 n 112233 e 16a " ) ) ;
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2017-01-05 08:51:47 +08:00
}
2017-07-30 15:17:48 +08:00
2019-03-09 15:59:13 +08:00
// clearing the topbit needed for the preambl detection.
2020-09-09 18:19:26 +08:00
static void verify_values ( uint64_t * animalid , uint32_t * countryid , uint32_t * extended , uint8_t * is_animal ) {
2019-10-31 15:39:11 +08:00
if ( ( * animalid & 0x3FFFFFFFFF ) ! = * animalid ) {
* animalid & = 0x3FFFFFFFFF ;
2020-05-20 17:13:21 +08:00
PrintAndLogEx ( INFO , " Animal ID truncated to 38bits: " _YELLOW_ ( " % " PRIx64 ) , * animalid ) ;
2019-03-10 06:35:06 +08:00
}
2020-09-09 18:19:26 +08:00
if ( ( * countryid & 0x3FF ) ! = * countryid ) {
* countryid & = 0x3FF ;
2020-05-20 17:13:21 +08:00
PrintAndLogEx ( INFO , " Country ID truncated to 10bits: " _YELLOW_ ( " %03d " ) , * countryid ) ;
2019-03-10 06:35:06 +08:00
}
2020-09-09 18:19:26 +08:00
if ( ( * extended & 0xFFF ) ! = * extended ) {
* extended & = 0xFFF ;
2020-05-20 17:13:21 +08:00
PrintAndLogEx ( INFO , " Extended truncated to 24bits: " _YELLOW_ ( " 0x%03X " ) , * extended ) ;
}
2020-09-09 18:19:26 +08:00
* is_animal & = 0x01 ;
2020-05-20 17:13:21 +08:00
}
static inline uint32_t bitcount ( uint32_t a ) {
# if defined __GNUC__
return __builtin_popcountl ( a ) ;
# else
a = a - ( ( a > > 1 ) & 0x55555555 ) ;
a = ( a & 0x33333333 ) + ( ( a > > 2 ) & 0x33333333 ) ;
return ( ( ( a + ( a > > 4 ) ) & 0x0f0f0f0f ) * 0x01010101 ) > > 24 ;
# endif
2017-01-05 08:51:47 +08:00
}
2017-07-30 15:17:48 +08:00
// FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits)
// 8 databits + 1 parity (1)
// CIITT 16 chksum
// NATIONAL CODE, ICAR database
// COUNTRY CODE (ISO3166) or http://cms.abvma.ca/uploads/ManufacturersISOsandCountryCodes.pdf
// FLAG (animal/non-animal)
/*
2019-03-09 15:59:13 +08:00
38 IDbits
10 country code
2017-07-30 15:17:48 +08:00
1 extra app bit
14 reserved bits
1 animal bit
16 ccitt CRC chksum over 64 bit ID CODE .
24 appli bits .
- - sample : 985121004515220 [ 37FF 65 B88EF94 ]
*/
2019-04-12 07:55:25 +08:00
/*
static int CmdFDXBdemodBI ( const char * Cmd ) {
2019-04-10 18:23:40 +08:00
( void ) Cmd ; // Cmd is not used so far
2017-07-30 15:17:48 +08:00
2019-03-10 06:35:06 +08:00
int clk = 32 ;
2019-03-27 22:35:43 +08:00
int invert = 1 , errCnt = 0 , offset = 0 , maxErr = 100 ;
2019-03-10 06:35:06 +08:00
uint8_t bs [ MAX_DEMOD_BUF_LEN ] ;
size_t size = getFromGraphBuf ( bs ) ;
errCnt = askdemod ( bs , & size , & clk , & invert , maxErr , 0 , 0 ) ;
2019-03-10 07:00:59 +08:00
if ( errCnt < 0 | | errCnt > maxErr ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDXB no data or error found %d, clock: %d " , errCnt , clk ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
errCnt = BiphaseRawDecode ( bs , & size , & offset , 1 ) ;
2019-03-10 07:00:59 +08:00
if ( errCnt < 0 | | errCnt > maxErr ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDXB BiphaseRawDecode: %d " , errCnt ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
int preambleIndex = detectFDXB ( bs , & size ) ;
2019-03-10 07:00:59 +08:00
if ( preambleIndex < 0 ) {
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDXB preamble not found :: %d " , preambleIndex ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( size ! = 128 ) {
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDXB incorrect data length found " ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-04-07 03:46:00 +08:00
setDemodBuff ( bs , 128 , preambleIndex ) ;
2019-03-10 06:35:06 +08:00
// remove marker bits (1's every 9th digit after preamble) (pType = 2)
size = removeParity ( bs , preambleIndex + 11 , 9 , 2 , 117 ) ;
2019-03-10 07:00:59 +08:00
if ( size ! = 104 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDXB error removeParity:: %d " , size ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " \n FDX-B / ISO 11784/5 Animal Tag ID Found: " ) ;
//got a good demod
2019-03-10 07:00:59 +08:00
uint64_t NationalCode = ( ( uint64_t ) ( bytebits_to_byteLSBF ( bs + 32 , 6 ) ) < < 32 ) | bytebits_to_byteLSBF ( bs , 32 ) ;
uint32_t countryCode = bytebits_to_byteLSBF ( bs + 38 , 10 ) ;
2019-03-10 06:35:06 +08:00
uint8_t dataBlockBit = bs [ 48 ] ;
2019-03-10 07:00:59 +08:00
uint32_t reservedCode = bytebits_to_byteLSBF ( bs + 49 , 14 ) ;
2019-03-10 06:35:06 +08:00
uint8_t animalBit = bs [ 63 ] ;
2019-04-08 16:45:55 +08:00
uint32_t crc_16 = bytebits_to_byteLSBF ( bs + 64 , 16 ) ;
2019-03-10 07:00:59 +08:00
uint32_t extended = bytebits_to_byteLSBF ( bs + 80 , 24 ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
uint64_t rawid = ( ( uint64_t ) bytebits_to_byte ( bs , 32 ) < < 32 ) | bytebits_to_byte ( bs + 32 , 32 ) ;
2019-03-10 06:35:06 +08:00
uint8_t raw [ 8 ] ;
num_to_bytes ( rawid , 8 , raw ) ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " Raw ID Hex: %s " , sprint_hex ( raw , 8 ) ) ;
2019-03-10 06:35:06 +08:00
uint16_t calcCrc = crc16_kermit ( raw , 8 ) ;
PrintAndLogEx ( SUCCESS , " Animal ID: %04u-%012 " PRIu64 , countryCode , NationalCode ) ;
PrintAndLogEx ( SUCCESS , " National Code: %012 " PRIu64 , NationalCode ) ;
PrintAndLogEx ( SUCCESS , " CountryCode: %04u " , countryCode ) ;
PrintAndLogEx ( SUCCESS , " Reserved/RFU: %u " , reservedCode ) ;
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( SUCCESS , " Animal Tag: %s " , animalBit ? _YELLOW_ ( " True " ) : " False " ) ;
PrintAndLogEx ( SUCCESS , " Has extended data: %s [0x%X] " , dataBlockBit ? _YELLOW_ ( " True " ) : " False " , extended ) ;
2019-04-12 16:55:09 +08:00
PrintAndLogEx ( SUCCESS , " CRC: 0x%04X - [%04X] - %s " , crc_16 , calcCrc , ( calcCrc = = crc_16 ) ? _GREEN_ ( " Passed " ) : _RED_ ( " Fail " ) ) ;
2019-03-10 06:35:06 +08:00
if ( g_debugMode ) {
PrintAndLogEx ( DEBUG , " Start marker %d; Size %d " , preambleIndex , size ) ;
char * bin = sprint_bin_break ( bs , size , 16 ) ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( DEBUG , " DEBUG BinStream: \n %s " , bin ) ;
2019-03-10 06:35:06 +08:00
}
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2017-07-30 15:17:48 +08:00
}
2019-04-12 07:55:25 +08:00
*/
2017-07-30 15:17:48 +08:00
2020-10-12 07:34:48 +08:00
// For the country part:
// wget -q -O - "https://en.wikipedia.org/w/index.php?title=List_of_ISO_3166_country_codes&action=raw" | awk '/id=/{match($0, /\[\[([^\]|]*)/, a); name=a[1];getline;getline;getline;getline;getline;match($0, /numeric#([0-9]*)/, a);num=a[1]; if (num != "") {printf " { %3u, \"%s\" },\n", num, name}}'
// Beware the bottom of the list contains also Manufacturers list
const fdxbCountryMapping_t fdxbCountryMapping [ ] = {
{ 4 , " Afghanistan " } ,
{ 8 , " Albania " } ,
{ 12 , " Algeria " } ,
{ 16 , " American Samoa " } ,
{ 20 , " Andorra " } ,
{ 24 , " Angola " } ,
{ 660 , " Anguilla " } ,
{ 10 , " Antarctica " } ,
{ 28 , " Antigua and Barbuda " } ,
{ 32 , " Argentina " } ,
{ 51 , " Armenia " } ,
{ 533 , " Aruba " } ,
{ 40 , " Austria " } ,
{ 31 , " Azerbaijan " } ,
{ 44 , " The Bahamas " } ,
{ 48 , " Bahrain " } ,
{ 50 , " Bangladesh " } ,
{ 52 , " Barbados " } ,
{ 112 , " Belarus " } ,
{ 56 , " Belgium " } ,
{ 84 , " Belize " } ,
{ 204 , " Benin " } ,
{ 60 , " Bermuda " } ,
{ 64 , " Bhutan " } ,
{ 68 , " Bolivia " } ,
{ 535 , " Bonaire " } ,
{ 70 , " Bosnia and Herzegovina " } ,
{ 72 , " Botswana " } ,
{ 74 , " Bouvet Island " } ,
{ 76 , " Brazil " } ,
{ 86 , " British Indian Ocean Territory " } ,
{ 100 , " Bulgaria " } ,
{ 854 , " Burkina Faso " } ,
{ 132 , " Cape Verde " } ,
{ 116 , " Cambodia " } ,
{ 120 , " Cameroon " } ,
{ 124 , " Canada " } ,
{ 140 , " Central African Republic " } ,
{ 148 , " Chad " } ,
{ 152 , " Chile " } ,
{ 156 , " China " } ,
{ 170 , " Colombia " } ,
{ 174 , " Comoros " } ,
{ 180 , " Democratic Republic of the Congo " } ,
{ 178 , " Republic of the Congo " } ,
{ 184 , " Cook Islands " } ,
{ 384 , " Ivory Coast " } ,
{ 191 , " Croatia " } ,
{ 192 , " Cuba " } ,
{ 531 , " Curaçao " } ,
{ 196 , " Cyprus " } ,
{ 203 , " Czech Republic " } ,
{ 262 , " Djibouti " } ,
{ 212 , " Dominica " } ,
{ 214 , " Dominican Republic " } ,
{ 818 , " Egypt " } ,
{ 222 , " El Salvador " } ,
{ 232 , " Eritrea " } ,
{ 233 , " Estonia " } ,
{ 748 , " Eswatini " } ,
{ 231 , " Ethiopia " } ,
{ 238 , " Falkland Islands " } ,
{ 234 , " Faroe Islands " } ,
{ 242 , " Fiji " } ,
{ 246 , " Finland " } ,
{ 250 , " France " } ,
{ 254 , " French Guiana " } ,
{ 258 , " French Polynesia " } ,
{ 260 , " French Southern Territories " } ,
{ 266 , " Gabon " } ,
{ 270 , " The Gambia " } ,
{ 268 , " Georgia (country) " } ,
{ 276 , " Germany " } ,
{ 288 , " Ghana " } ,
{ 292 , " Gibraltar " } ,
{ 304 , " Greenland " } ,
{ 308 , " Grenada " } ,
{ 312 , " Guadeloupe " } ,
{ 316 , " Guam " } ,
{ 320 , " Guatemala " } ,
{ 831 , " Bailiwick of Guernsey " } ,
{ 324 , " Guinea " } ,
{ 624 , " Guinea-Bissau " } ,
{ 328 , " Guyana " } ,
{ 332 , " Haiti " } ,
{ 336 , " Holy See " } ,
{ 340 , " Honduras " } ,
{ 344 , " Hong Kong " } ,
{ 348 , " Hungary " } ,
{ 352 , " Iceland " } ,
{ 356 , " India " } ,
{ 360 , " Indonesia " } ,
{ 364 , " Iran (Islamic Republic of) " } ,
{ 368 , " Iraq " } ,
{ 372 , " Republic of Ireland " } ,
{ 833 , " Isle of Man " } ,
{ 376 , " Israel " } ,
{ 380 , " Italy " } ,
{ 832 , " Jersey " } ,
{ 400 , " Jordan " } ,
{ 398 , " Kazakhstan " } ,
{ 404 , " Kenya " } ,
{ 296 , " Kiribati " } ,
{ 408 , " North Korea " } ,
{ 410 , " South Korea " } ,
{ 414 , " Kuwait " } ,
{ 417 , " Kyrgyzstan " } ,
{ 418 , " Laos " } ,
{ 428 , " Latvia " } ,
{ 422 , " Lebanon " } ,
{ 426 , " Lesotho " } ,
{ 430 , " Liberia " } ,
{ 434 , " Libya " } ,
{ 438 , " Liechtenstein " } ,
{ 440 , " Lithuania " } ,
{ 442 , " Luxembourg " } ,
{ 446 , " Macau " } ,
{ 807 , " North Macedonia " } ,
{ 450 , " Madagascar " } ,
{ 454 , " Malawi " } ,
{ 458 , " Malaysia " } ,
{ 462 , " Maldives " } ,
{ 466 , " Mali " } ,
{ 470 , " Malta " } ,
{ 584 , " Marshall Islands " } ,
{ 474 , " Martinique " } ,
{ 478 , " Mauritania " } ,
{ 480 , " Mauritius " } ,
{ 175 , " Mayotte " } ,
{ 484 , " Mexico " } ,
{ 583 , " Federated States of Micronesia " } ,
{ 498 , " Moldova " } ,
{ 492 , " Monaco " } ,
{ 496 , " Mongolia " } ,
{ 499 , " Montenegro " } ,
{ 500 , " Montserrat " } ,
{ 504 , " Morocco " } ,
{ 508 , " Mozambique " } ,
{ 104 , " Myanmar " } ,
{ 516 , " Namibia " } ,
{ 520 , " Nauru " } ,
{ 524 , " Nepal " } ,
{ 528 , " Kingdom of the Netherlands " } ,
{ 540 , " New Caledonia " } ,
{ 554 , " New Zealand " } ,
{ 558 , " Nicaragua " } ,
{ 562 , " Niger " } ,
{ 566 , " Nigeria " } ,
{ 570 , " Niue " } ,
{ 574 , " Norfolk Island " } ,
{ 578 , " Norway " } ,
{ 512 , " Oman " } ,
{ 586 , " Pakistan " } ,
{ 585 , " Palau " } ,
{ 275 , " State of Palestine " } ,
{ 591 , " Panama " } ,
{ 598 , " Papua New Guinea " } ,
{ 600 , " Paraguay " } ,
{ 608 , " Philippines " } ,
{ 612 , " Pitcairn Islands " } ,
{ 616 , " Poland " } ,
{ 620 , " Portugal " } ,
{ 630 , " Puerto Rico " } ,
{ 634 , " Qatar " } ,
{ 638 , " Réunion " } ,
{ 642 , " Romania " } ,
{ 643 , " Russia " } ,
{ 646 , " Rwanda " } ,
{ 654 , " Saint Helena " } ,
{ 659 , " Saint Kitts and Nevis " } ,
{ 662 , " Saint Lucia " } ,
{ 663 , " Collectivity of Saint Martin " } ,
{ 666 , " Saint Pierre and Miquelon " } ,
{ 670 , " Saint Vincent and the Grenadines " } ,
{ 882 , " Samoa " } ,
{ 674 , " San Marino " } ,
{ 678 , " São Tomé and Príncipe " } ,
{ 682 , " Saudi Arabia " } ,
{ 688 , " Serbia " } ,
{ 690 , " Seychelles " } ,
{ 694 , " Sierra Leone " } ,
{ 702 , " Singapore " } ,
{ 703 , " Slovakia " } ,
{ 705 , " Slovenia " } ,
{ 90 , " Solomon Islands " } ,
{ 706 , " Somalia " } ,
{ 710 , " South Africa " } ,
{ 239 , " South Georgia and the South Sandwich Islands " } ,
{ 724 , " Spain " } ,
{ 144 , " Sri Lanka " } ,
{ 729 , " Sudan " } ,
{ 740 , " Suriname " } ,
{ 744 , " Svalbard " } ,
{ 752 , " Sweden " } ,
{ 756 , " Switzerland " } ,
{ 760 , " Syria " } ,
{ 158 , " Taiwan " } ,
{ 762 , " Tajikistan " } ,
{ 834 , " Tanzania " } ,
{ 764 , " Thailand " } ,
{ 626 , " East Timor " } ,
{ 768 , " Togo " } ,
{ 772 , " Tokelau " } ,
{ 776 , " Tonga " } ,
{ 780 , " Trinidad and Tobago " } ,
{ 788 , " Tunisia " } ,
{ 792 , " Turkey " } ,
{ 795 , " Turkmenistan " } ,
{ 796 , " Turks and Caicos Islands " } ,
{ 798 , " Tuvalu " } ,
{ 800 , " Uganda " } ,
{ 804 , " Ukraine " } ,
{ 784 , " United Arab Emirates " } ,
{ 826 , " United Kingdom " } ,
{ 581 , " United States Minor Outlying Islands " } ,
{ 840 , " United States " } ,
{ 860 , " Uzbekistan " } ,
{ 548 , " Vanuatu " } ,
{ 704 , " Vietnam " } ,
{ 92 , " British Virgin Islands " } ,
{ 850 , " United States Virgin Islands " } ,
{ 732 , " Western Sahara " } ,
{ 887 , " Yemen " } ,
{ 894 , " Zambia " } ,
{ 716 , " Zimbabwe " } ,
// Manufacturers list:
{ 952 , " JECTA " } ,
{ 953 , " Cromasa Identificacion electronica S.A. " } ,
{ 955 , " Reseaumatique " } ,
{ 956 , " Trovan Ltd. (ACK Reunite) " } ,
{ 958 , " Pet ID " } ,
{ 959 , " Global ID Technologies " } ,
{ 961 , " Mannings I.A.I.D. " } ,
{ 963 , " Korth Eletro Mecanica LTDA " } ,
{ 965 , " 4D Technology Co. Ltd " } ,
{ 966 , " PetCode " } ,
{ 967 , " Rfdynamics / M4S ID in Canada " } ,
{ 968 , " AEG / EIDAP in Canada " } ,
{ 972 , " Planet ID " } ,
{ 975 , " Sokymat " } ,
{ 977 , " AVID " } ,
{ 978 , " Ordicam " } ,
{ 981 , " Microfindr, Datamars, Found Animals, Crystal Tag, Banfield, Bayer resQ, Peeva " } ,
{ 982 , " 24 Pet Watch (Allflex) " } ,
{ 985 , " HomeAgain (Destron Fearing/Digital Angel) " } ,
{ 991 , " Peeva " } ,
{ 999 , " Test range " } ,
{ 0 , " N/A " } // must be the last entry
} ;
static const char * mapFDBX ( uint16_t countryCode ) {
uint16_t i = 0 ;
while ( fdxbCountryMapping [ i ] . code > 0 ) {
if ( countryCode = = fdxbCountryMapping [ i ] . code ) {
return fdxbCountryMapping [ i ] . desc ;
}
i + + ;
}
return fdxbCountryMapping [ i ] . desc ;
}
2017-01-05 08:51:47 +08:00
//see ASKDemod for what args are accepted
2019-03-09 15:59:13 +08:00
//almost the same demod as cmddata.c/CmdFDXBdemodBI
2020-10-12 04:38:52 +08:00
int demodFDXB ( bool verbose ) {
2019-03-10 06:35:06 +08:00
//Differential Biphase / di-phase (inverted biphase)
//get binary from ask wave
2020-09-28 17:50:20 +08:00
if ( ASKbiphaseDemod ( 0 , 32 , 1 , 100 , false ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B ASKbiphaseDemod failed " ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
size_t size = DemodBufferLen ;
int preambleIndex = detectFDXB ( DemodBuffer , & size ) ;
2019-03-10 07:00:59 +08:00
if ( preambleIndex < 0 ) {
2019-03-10 06:35:06 +08:00
if ( preambleIndex = = - 1 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B too few bits found " ) ;
else if ( preambleIndex = = - 2 )
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B preamble not found " ) ;
else if ( preambleIndex = = - 3 )
2019-10-10 03:36:29 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B Size not correct: %zu " , size ) ;
2019-03-10 06:35:06 +08:00
else
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B ans: %d " , preambleIndex ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
// set and leave DemodBuffer intact
2019-04-07 03:46:00 +08:00
setDemodBuff ( DemodBuffer , 128 , preambleIndex ) ;
2019-03-10 07:00:59 +08:00
setClockGrid ( g_DemodClock , g_DemodStartIdx + ( preambleIndex * g_DemodClock ) ) ;
2020-09-09 18:19:26 +08:00
2020-09-12 06:31:17 +08:00
2019-03-10 06:35:06 +08:00
// remove marker bits (1's every 9th digit after preamble) (pType = 2)
size = removeParity ( DemodBuffer , 11 , 9 , 2 , 117 ) ;
2019-03-10 07:00:59 +08:00
if ( size ! = 104 ) {
2019-10-10 00:03:56 +08:00
PrintAndLogEx ( DEBUG , " DEBUG: Error - FDX-B error removeParity: %zu " , size ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
//got a good demod
2020-09-09 18:19:26 +08:00
uint8_t offset ;
2020-10-12 06:20:51 +08:00
// ISO: bits 27..64
2019-03-10 07:00:59 +08:00
uint64_t NationalCode = ( ( uint64_t ) ( bytebits_to_byteLSBF ( DemodBuffer + 32 , 6 ) ) < < 32 ) | bytebits_to_byteLSBF ( DemodBuffer , 32 ) ;
2020-09-09 18:19:26 +08:00
offset = 38 ;
2020-10-12 06:20:51 +08:00
// ISO: bits 17..26
2020-09-09 18:19:26 +08:00
uint16_t countryCode = bytebits_to_byteLSBF ( DemodBuffer + offset , 10 ) ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
offset + = 10 ;
2020-10-12 06:20:51 +08:00
// ISO: bits 16
2020-09-09 18:19:26 +08:00
uint8_t dataBlockBit = DemodBuffer [ offset ] ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
offset + + ;
2020-10-12 06:20:51 +08:00
// ISO: bits 15
uint8_t rudiBit = DemodBuffer [ offset ] ;
2020-09-12 06:31:17 +08:00
2020-10-12 06:20:51 +08:00
offset + + ;
// ISO: bits 10..14
uint32_t reservedCode = bytebits_to_byteLSBF ( DemodBuffer + offset , 5 ) ;
offset + = 5 ;
// ISO: bits 5..9
uint32_t userInfo = bytebits_to_byteLSBF ( DemodBuffer + offset , 5 ) ;
offset + = 5 ;
// ISO: bits 2..4
uint32_t replacementNr = bytebits_to_byteLSBF ( DemodBuffer + offset , 3 ) ;
offset + = 3 ;
2020-09-09 18:19:26 +08:00
uint8_t animalBit = DemodBuffer [ offset ] ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
offset + + ;
uint16_t crc = bytebits_to_byteLSBF ( DemodBuffer + offset , 16 ) ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
offset + = 16 ;
2020-09-12 06:31:17 +08:00
uint32_t extended = bytebits_to_byteLSBF ( DemodBuffer + offset , 24 ) ;
2020-09-09 18:19:26 +08:00
2019-03-10 07:00:59 +08:00
uint64_t rawid = ( uint64_t ) ( bytebits_to_byte ( DemodBuffer , 32 ) ) < < 32 | bytebits_to_byte ( DemodBuffer + 32 , 32 ) ;
2019-03-10 06:35:06 +08:00
uint8_t raw [ 8 ] ;
num_to_bytes ( rawid , 8 , raw ) ;
2020-09-17 08:43:46 +08:00
if ( ! verbose ) {
PROMPT_CLEARLINE ;
PrintAndLogEx ( SUCCESS , " Animal ID " _GREEN_ ( " %04u-%012 " PRIu64 ) , countryCode , NationalCode ) ;
return PM3_SUCCESS ;
}
2020-06-26 19:17:41 +08:00
PrintAndLogEx ( SUCCESS , " FDX-B / ISO 11784/5 Animal " ) ;
2020-10-12 07:34:48 +08:00
PrintAndLogEx ( SUCCESS , " Animal ID " _GREEN_ ( " %03u-%012 " PRIu64 ) , countryCode , NationalCode ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( SUCCESS , " National Code " _GREEN_ ( " %012 " PRIu64 ) " (0x% " PRIX64 " ) " , NationalCode , NationalCode ) ;
2020-10-12 07:34:48 +08:00
PrintAndLogEx ( SUCCESS , " Country Code " _GREEN_ ( " %03u " ) " - %s " , countryCode , mapFDBX ( countryCode ) ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( SUCCESS , " Reserved/RFU %u (0x%04X) " , reservedCode , reservedCode ) ;
PrintAndLogEx ( SUCCESS , " Animal bit set? %s " , animalBit ? _YELLOW_ ( " True " ) : " False " ) ;
PrintAndLogEx ( SUCCESS , " Data block? %s [value 0x%X] " , dataBlockBit ? _YELLOW_ ( " True " ) : " False " , extended ) ;
2020-10-12 06:20:51 +08:00
PrintAndLogEx ( SUCCESS , " RUDI bit? %s " , rudiBit ? _YELLOW_ ( " True " ) " (advanced transponder) " : " False " ) ;
PrintAndLogEx ( SUCCESS , " User Info? %u %s " , userInfo , userInfo = = 0 ? " (RFU) " : " " ) ;
PrintAndLogEx ( SUCCESS , " Replacement No? %u %s " , replacementNr , replacementNr = = 0 ? " (RFU) " : " " ) ;
2019-10-30 22:44:57 +08:00
uint8_t c [ ] = { 0 , 0 } ;
compute_crc ( CRC_11784 , raw , sizeof ( raw ) , & c [ 0 ] , & c [ 1 ] ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( SUCCESS , " CRC-16 0x%04X (%s) " , crc , ( crc = = ( c [ 1 ] < < 8 | c [ 0 ] ) ) ? _GREEN_ ( " ok " ) : _RED_ ( " fail " ) ) ;
// iceman: crc doesn't protect the extended data?
2020-06-26 19:17:41 +08:00
PrintAndLogEx ( SUCCESS , " Raw " _GREEN_ ( " %s " ) , sprint_hex ( raw , 8 ) ) ;
2019-03-10 06:35:06 +08:00
if ( g_debugMode ) {
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( DEBUG , " Start marker %d; Size %zu " , preambleIndex , size ) ;
2019-03-10 06:35:06 +08:00
char * bin = sprint_bin_break ( DemodBuffer , size , 16 ) ;
PrintAndLogEx ( DEBUG , " DEBUG bin stream: \n %s " , bin ) ;
}
2020-05-20 17:13:21 +08:00
uint8_t bt_par = ( extended & 0x100 ) > > 8 ;
2020-06-08 09:15:10 +08:00
uint8_t bt_temperature = extended & 0xff ;
uint8_t bt_calc_parity = ( bitcount ( bt_temperature ) & 0x1 ) ? 0 : 1 ;
2020-05-20 17:13:21 +08:00
uint8_t is_bt_temperature = ( bt_calc_parity = = bt_par ) & & ! ( extended & 0xe00 ) ;
if ( is_bt_temperature ) {
float bt_F = 74 + bt_temperature * 0.2 ;
float bt_C = ( bt_F - 32 ) / 1.8 ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( SUCCESS , " Bio-Thermo detected " ) ;
PrintAndLogEx ( INFO , " temperature " _GREEN_ ( " %.1f " ) " F / " _GREEN_ ( " %.1f " ) " C " , bt_F , bt_C ) ;
}
2019-03-10 06:35:06 +08:00
// set block 0 for later
//g_DemodConfig = T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT;
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2017-01-05 08:51:47 +08:00
}
2020-10-12 04:38:52 +08:00
static int CmdFdxBDemod ( const char * Cmd ) {
2020-05-20 17:13:21 +08:00
( void ) Cmd ; // Cmd is not used so far
2020-10-12 04:38:52 +08:00
return demodFDXB ( true ) ;
2020-05-20 17:13:21 +08:00
}
2020-10-12 04:38:52 +08:00
static int CmdFdxBRead ( const char * Cmd ) {
2020-09-05 06:12:38 +08:00
sample_config config ;
memset ( & config , 0 , sizeof ( sample_config ) ) ;
int retval = lf_getconfig ( & config ) ;
if ( retval ! = PM3_SUCCESS ) {
PrintAndLogEx ( ERR , " failed to get current device LF config " ) ;
return retval ;
}
2020-09-17 08:43:46 +08:00
bool errors = false ;
bool continuous = false ;
uint8_t cmdp = 0 ;
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 & & ! errors ) {
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' h ' :
2020-10-12 04:38:52 +08:00
return usage_lf_fdxb_read ( ) ;
2020-09-17 08:43:46 +08:00
case ' @ ' :
continuous = true ;
cmdp + + ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' " , param_getchar ( Cmd , cmdp ) ) ;
errors = true ;
break ;
}
}
//Validations
2020-10-12 04:38:52 +08:00
if ( errors ) return usage_lf_fdxb_read ( ) ;
2020-09-05 06:12:38 +08:00
int16_t tmp_div = config . divisor ;
if ( tmp_div ! = LF_DIVISOR_134 ) {
config . divisor = LF_DIVISOR_134 ;
config . verbose = false ;
retval = lf_config ( & config ) ;
if ( retval ! = PM3_SUCCESS ) {
PrintAndLogEx ( ERR , " failed to change LF configuration " ) ;
return retval ;
}
}
2020-09-17 08:43:46 +08:00
if ( continuous ) {
PrintAndLogEx ( INFO , " Press " _GREEN_ ( " Enter " ) " to exit " ) ;
2020-09-05 06:12:38 +08:00
}
2020-09-17 08:43:46 +08:00
int ret = PM3_SUCCESS ;
do {
retval = lf_read ( false , 10000 ) ;
if ( retval ! = PM3_SUCCESS ) {
PrintAndLogEx ( ERR , " failed to get LF read from device " ) ;
return retval ;
}
2020-10-12 04:38:52 +08:00
ret = demodFDXB ( ! continuous ) ; // be verbose only if not in continuous mode
2020-09-17 08:43:46 +08:00
if ( kbd_enter_pressed ( ) ) {
break ;
}
PrintAndLogEx ( INPLACE , " " ) ;
} while ( continuous ) ;
2020-09-05 06:12:38 +08:00
if ( tmp_div ! = LF_DIVISOR_134 ) {
config . divisor = tmp_div ;
retval = lf_config ( & config ) ;
if ( retval ! = PM3_SUCCESS ) {
PrintAndLogEx ( ERR , " failed to restore LF configuration " ) ;
return retval ;
}
}
2020-09-17 08:43:46 +08:00
return ret ;
2017-01-05 08:51:47 +08:00
}
2020-10-12 04:38:52 +08:00
static int CmdFdxBClone ( const char * Cmd ) {
2017-01-05 08:51:47 +08:00
2020-09-09 18:19:26 +08:00
uint32_t country_code = 0 , extended = 0 ;
uint64_t national_code = 0 ;
uint8_t is_animal = 0 , cmdp = 0 ;
bool errors = false , has_extended = false , q5 = false ;
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 & & ! errors ) {
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' h ' :
2020-10-12 04:38:52 +08:00
return usage_lf_fdxb_clone ( ) ;
2020-09-09 18:19:26 +08:00
case ' c ' : {
country_code = param_get32ex ( Cmd , cmdp + 1 , 0 , 10 ) ;
cmdp + = 2 ;
break ;
}
case ' n ' : {
national_code = param_get64ex ( Cmd , cmdp + 1 , 0 , 10 ) ;
cmdp + = 2 ;
break ;
}
case ' e ' : {
extended = param_get32ex ( Cmd , cmdp + 1 , 0 , 16 ) ;
has_extended = true ;
cmdp + = 2 ;
break ;
}
case ' s ' : {
is_animal = 1 ;
cmdp + + ;
break ;
}
case ' q ' : {
q5 = true ;
cmdp + + ;
break ;
}
default : {
PrintAndLogEx ( WARNING , " Unknown parameter '%c' " , param_getchar ( Cmd , cmdp ) ) ;
errors = true ;
break ;
}
}
}
2020-10-12 04:38:52 +08:00
if ( errors | | strlen ( Cmd ) = = 0 ) return usage_lf_fdxb_clone ( ) ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
verify_values ( & national_code , & country_code , & extended , & is_animal ) ;
2019-03-10 06:35:06 +08:00
2020-09-10 20:01:38 +08:00
PrintAndLogEx ( INFO , " Country code % " PRIu32 , country_code ) ;
PrintAndLogEx ( INFO , " National code % " PRIu64 , national_code ) ;
2020-09-12 06:31:17 +08:00
PrintAndLogEx ( INFO , " Set animal bit %c " , ( is_animal ) ? ' Y ' : ' N ' ) ;
PrintAndLogEx ( INFO , " Set data block bit %c " , ( has_extended ) ? ' Y ' : ' N ' ) ;
2020-09-10 20:01:38 +08:00
PrintAndLogEx ( INFO , " Extended data 0x% " PRIX32 , extended ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( INFO , " RFU 0 " ) ;
2019-03-10 06:35:06 +08:00
2019-09-27 03:44:27 +08:00
uint8_t * bits = calloc ( 128 , sizeof ( uint8_t ) ) ;
2020-10-12 04:38:52 +08:00
if ( getFDXBBits ( national_code , country_code , is_animal , has_extended , extended , bits ) ! = PM3_SUCCESS ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Error with tag bitstream generation. " ) ;
2019-09-27 03:44:27 +08:00
free ( bits ) ;
2019-05-22 20:57:08 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-09-27 03:44:27 +08:00
uint32_t blocks [ 5 ] = { T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 < < T55x7_MAXBLOCK_SHIFT , 0 , 0 , 0 , 0 } ;
2019-10-13 06:48:26 +08:00
2019-03-10 06:35:06 +08:00
//Q5
2020-08-28 17:14:42 +08:00
if ( q5 )
2020-08-28 16:11:11 +08:00
blocks [ 0 ] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE ( 32 ) | 4 < < T5555_MAXBLOCK_SHIFT ;
2019-03-10 06:35:06 +08:00
// convert from bit stream to block data
2019-09-27 03:44:27 +08:00
blocks [ 1 ] = bytebits_to_byte ( bits , 32 ) ;
blocks [ 2 ] = bytebits_to_byte ( bits + 32 , 32 ) ;
blocks [ 3 ] = bytebits_to_byte ( bits + 64 , 32 ) ;
blocks [ 4 ] = bytebits_to_byte ( bits + 96 , 32 ) ;
2019-03-10 06:35:06 +08:00
2019-09-27 03:44:27 +08:00
free ( bits ) ;
2019-10-13 06:48:26 +08:00
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( INFO , " Preparing to clone FDX-B to " _YELLOW_ ( " %s " ) " with animal ID: " _GREEN_ ( " %04u-% " PRIu64 ) , ( q5 ) ? " Q5/T5555 " : " T55x7 " , country_code , national_code ) ;
2019-09-27 03:44:27 +08:00
print_blocks ( blocks , ARRAYLEN ( blocks ) ) ;
2019-09-16 17:11:54 +08:00
2020-03-02 20:59:41 +08:00
int res = clone_t55xx_tag ( blocks , ARRAYLEN ( blocks ) ) ;
PrintAndLogEx ( SUCCESS , " Done " ) ;
2020-10-12 04:38:52 +08:00
PrintAndLogEx ( HINT , " Hint: try " _YELLOW_ ( " `lf fdxb read` " ) " to verify " ) ;
2020-03-02 20:59:41 +08:00
return res ;
2017-01-05 08:51:47 +08:00
}
2020-10-12 04:38:52 +08:00
static int CmdFdxBSim ( const char * Cmd ) {
2017-01-05 08:51:47 +08:00
2020-09-09 18:19:26 +08:00
uint32_t country_code = 0 , extended = 0 ;
uint64_t national_code = 0 ;
uint8_t is_animal = 0 , cmdp = 0 ;
bool errors = false , has_extended = false ;
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 & & ! errors ) {
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' h ' :
2020-10-12 04:38:52 +08:00
return usage_lf_fdxb_sim ( ) ;
2020-09-09 18:19:26 +08:00
case ' c ' : {
country_code = param_get32ex ( Cmd , cmdp + 1 , 0 , 10 ) ;
cmdp + = 2 ;
break ;
}
case ' n ' : {
national_code = param_get64ex ( Cmd , cmdp + 1 , 0 , 10 ) ;
cmdp + = 2 ;
break ;
}
case ' e ' : {
extended = param_get32ex ( Cmd , cmdp + 1 , 0 , 10 ) ;
has_extended = true ;
cmdp + = 2 ;
break ;
}
case ' s ' : {
is_animal = 1 ;
cmdp + + ;
break ;
}
default : {
PrintAndLogEx ( WARNING , " Unknown parameter '%c' " , param_getchar ( Cmd , cmdp ) ) ;
errors = true ;
break ;
}
}
}
2020-10-12 04:38:52 +08:00
if ( errors ) return usage_lf_fdxb_sim ( ) ;
2020-09-12 06:31:17 +08:00
2020-09-09 18:19:26 +08:00
verify_values ( & national_code , & country_code , & extended , & is_animal ) ;
2019-03-09 15:59:13 +08:00
2020-09-10 20:01:38 +08:00
PrintAndLogEx ( INFO , " Country code % " PRIu32 , country_code ) ;
PrintAndLogEx ( INFO , " National code % " PRIu64 , national_code ) ;
2020-09-12 06:31:17 +08:00
PrintAndLogEx ( INFO , " Set animal bit %c " , ( is_animal ) ? ' Y ' : ' N ' ) ;
PrintAndLogEx ( INFO , " Set data block bit %c " , ( has_extended ) ? ' Y ' : ' N ' ) ;
2020-09-10 20:01:38 +08:00
PrintAndLogEx ( INFO , " Extended data 0x% " PRIX32 , extended ) ;
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( INFO , " RFU 0 " ) ;
2019-03-09 15:59:13 +08:00
2020-09-09 18:19:26 +08:00
PrintAndLogEx ( SUCCESS , " Simulating FDX-B animal ID: " _GREEN_ ( " %04u-% " PRIu64 ) , country_code , national_code ) ;
2017-01-05 08:51:47 +08:00
2019-10-31 15:39:11 +08:00
uint8_t * bits = calloc ( 128 , sizeof ( uint8_t ) ) ;
2020-10-12 04:38:52 +08:00
if ( getFDXBBits ( national_code , country_code , is_animal , ( extended > 0 ) , extended , bits ) ! = PM3_SUCCESS ) {
2019-10-31 15:39:11 +08:00
PrintAndLogEx ( ERR , " Error with tag bitstream generation. " ) ;
free ( bits ) ;
return PM3_ESOFT ;
}
2019-05-24 19:06:08 +08:00
// 32, no STT, BIPHASE INVERTED == diphase
2019-10-31 15:39:11 +08:00
lf_asksim_t * payload = calloc ( 1 , sizeof ( lf_asksim_t ) + 128 ) ;
2019-05-24 19:06:08 +08:00
payload - > encoding = 2 ;
payload - > invert = 1 ;
payload - > separator = 0 ;
payload - > clock = 32 ;
2019-10-31 15:39:11 +08:00
memcpy ( payload - > data , bits , 128 ) ;
2019-05-24 19:06:08 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-10-31 15:39:11 +08:00
SendCommandNG ( CMD_LF_ASK_SIMULATE , ( uint8_t * ) payload , sizeof ( lf_asksim_t ) + 128 ) ;
free ( bits ) ;
2019-05-24 19:06:08 +08:00
free ( payload ) ;
2019-06-08 03:40:33 +08:00
2019-05-09 06:08:59 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
WaitForResponse ( CMD_LF_ASK_SIMULATE , & resp ) ;
2019-05-24 19:06:08 +08:00
PrintAndLogEx ( INFO , " Done " ) ;
2019-05-10 02:20:54 +08:00
if ( resp . status ! = PM3_EOPABORTED )
2019-05-09 06:08:59 +08:00
return resp . status ;
2019-10-31 15:39:11 +08:00
2019-05-09 06:08:59 +08:00
return PM3_SUCCESS ;
2017-01-05 08:51:47 +08:00
}
static command_t CommandTable [ ] = {
2019-05-02 06:02:38 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " this help " } ,
2020-10-12 04:38:52 +08:00
{ " demod " , CmdFdxBDemod , AlwaysAvailable , " demodulate a FDX-B ISO11784/85 tag from the GraphBuffer " } ,
{ " read " , CmdFdxBRead , IfPm3Lf , " attempt to read at 134kHz and extract tag data " } ,
{ " clone " , CmdFdxBClone , IfPm3Lf , " clone animal ID tag to T55x7 or Q5/T5555 " } ,
{ " sim " , CmdFdxBSim , IfPm3Lf , " simulate Animal ID tag " } ,
2019-05-02 02:48:15 +08:00
{ NULL , NULL , NULL , NULL }
2017-01-05 08:51:47 +08:00
} ;
2019-04-12 07:55:25 +08:00
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2019-04-12 07:55:25 +08:00
}
2020-10-12 04:38:52 +08:00
int CmdLFFdxB ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2017-01-05 08:51:47 +08:00
}
2019-04-12 07:55:25 +08:00
// Ask/Biphase Demod then try to locate an ISO 11784/85 ID
// BitStream must contain previously askrawdemod and biphasedemoded data
int detectFDXB ( uint8_t * dest , size_t * size ) {
//make sure buffer has enough data
if ( * size < 128 * 2 ) return - 1 ;
size_t startIdx = 0 ;
uint8_t preamble [ ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ;
if ( ! preambleSearch ( dest , preamble , sizeof ( preamble ) , size , & startIdx ) )
return - 2 ; //preamble not found
2020-10-06 16:21:46 +08:00
if ( * size < 128 ) return - 3 ; //wrong demoded size
2019-04-12 07:55:25 +08:00
//return start position
return ( int ) startIdx ;
}
2020-10-12 04:38:52 +08:00
int getFDXBBits ( uint64_t national_code , uint16_t country_code , uint8_t is_animal , uint8_t is_extended , uint32_t extended , uint8_t * bits ) {
2019-04-12 07:55:25 +08:00
// add preamble ten 0x00 and one 0x01
memset ( bits , 0x00 , 10 ) ;
bits [ 10 ] = 1 ;
// 128bits
// every 9th bit is 0x01, but we can just fill the rest with 0x01 and overwrite
memset ( bits , 0x01 , 128 ) ;
// add preamble ten 0x00 and one 0x01
memset ( bits , 0x00 , 10 ) ;
// add reserved
num_to_bytebitsLSBF ( 0x00 , 7 , bits + 66 ) ;
num_to_bytebitsLSBF ( 0x00 > > 7 , 7 , bits + 74 ) ;
// add animal flag - OK
2020-09-09 18:19:26 +08:00
bits [ 81 ] = is_animal ;
2019-04-12 07:55:25 +08:00
// add extended flag - OK
2020-09-09 18:19:26 +08:00
bits [ 65 ] = is_extended ;
2019-04-12 07:55:25 +08:00
// add national code 40bits - OK
2020-09-09 18:19:26 +08:00
num_to_bytebitsLSBF ( national_code > > 0 , 8 , bits + 11 ) ;
num_to_bytebitsLSBF ( national_code > > 8 , 8 , bits + 20 ) ;
num_to_bytebitsLSBF ( national_code > > 16 , 8 , bits + 29 ) ;
num_to_bytebitsLSBF ( national_code > > 24 , 8 , bits + 38 ) ;
num_to_bytebitsLSBF ( national_code > > 32 , 6 , bits + 47 ) ;
2019-04-12 07:55:25 +08:00
// add country code - OK
2020-09-09 18:19:26 +08:00
num_to_bytebitsLSBF ( country_code > > 0 , 2 , bits + 53 ) ;
num_to_bytebitsLSBF ( country_code > > 2 , 8 , bits + 56 ) ;
2019-04-12 07:55:25 +08:00
// add crc-16 - OK
uint8_t raw [ 8 ] ;
for ( uint8_t i = 0 ; i < 8 ; + + i )
raw [ i ] = bytebits_to_byte ( bits + 11 + i * 9 , 8 ) ;
2019-10-30 22:44:57 +08:00
init_table ( CRC_11784 ) ;
2020-10-12 04:38:52 +08:00
uint16_t crc = crc16_fdxb ( raw , 8 ) ;
2019-04-12 07:55:25 +08:00
num_to_bytebitsLSBF ( crc > > 0 , 8 , bits + 83 ) ;
num_to_bytebitsLSBF ( crc > > 8 , 8 , bits + 92 ) ;
// extended data - OK
num_to_bytebitsLSBF ( extended > > 0 , 8 , bits + 101 ) ;
num_to_bytebitsLSBF ( extended > > 8 , 8 , bits + 110 ) ;
num_to_bytebitsLSBF ( extended > > 16 , 8 , bits + 119 ) ;
2020-09-09 18:19:26 +08:00
// 8 16 24 32 40 48 49
// A8 28 0C 92 EA 6F 00 01
// A8 28 0C 92 EA 6F 80 00
2019-05-22 20:57:08 +08:00
return PM3_SUCCESS ;
2017-01-05 08:51:47 +08:00
}
2019-04-12 07:55:25 +08:00