1 //-----------------------------------------------------------------------------
3 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
4 // at your option, any later version. See the LICENSE.txt file for the text of
6 //-----------------------------------------------------------------------------
7 // Low frequency FDX-A FECAVA Destron tag commands
8 //-----------------------------------------------------------------------------
9 #include "cmdlfdestron.h"
10 #include <ctype.h> // tolower
11 #include <string.h> // memcpy
12 #include "commonutil.h" // ARRAYLEN
14 #include "cmdparser.h" // command_t
19 #include "lfdemod.h" // preamble test
20 #include "protocols.h" // t55xx defines
21 #include "cmdlft55xx.h" // clone..
22 #include "cmdlf.h" // cmdlfconfig
24 #include "cliparser.h" // cli parse input
25 #include "cmdlfem4x05.h" // EM defines
27 #define DESTRON_FRAME_SIZE 96
28 #define DESTRON_PREAMBLE_SIZE 16
30 static int CmdHelp(const char *Cmd
);
32 int demodDestron(bool verbose
) {
33 (void) verbose
; // unused so far
35 if (FSKrawDemod(0, 0, 0, 0, false) != PM3_SUCCESS
) {
36 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: FSK Demod failed");
40 size_t size
= DemodBufferLen
;
41 int ans
= detectDestron(DemodBuffer
, &size
);
44 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: too few bits found");
46 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: preamble not found");
48 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: Size not correct: %zu", size
);
50 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: ans: %d", ans
);
55 setDemodBuff(DemodBuffer
, DESTRON_FRAME_SIZE
, ans
);
56 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
58 uint8_t bits
[DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
] = {0};
59 size_t bitlen
= DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
;
60 memcpy(bits
, DemodBuffer
+ DESTRON_PREAMBLE_SIZE
, DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
);
63 uint16_t errCnt
= manrawdecode(bits
, &bitlen
, 0, &alignPos
);
65 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: Manchester decoding errors: %d", ans
);
69 uint8_t data
[5] = {0};
70 uint8_t parity_err
= 0;
71 for (int i
= 0; i
< sizeof(data
); i
++) {
72 data
[i
] = bytebits_to_byte(bits
+ i
* 8, 8);
73 parity_err
+= oddparity8(data
[i
]);
77 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: parity errors: %d", parity_err
);
80 PrintAndLogEx(SUCCESS
, "FDX-A FECAVA Destron: " _GREEN_("%s"), sprint_hex_inrow(data
, 5));
84 static int CmdDestronDemod(const char *Cmd
) {
85 CLIParserContext
*ctx
;
86 CLIParserInit(&ctx
, "lf destron demod",
87 "Try to find Destron preamble, if found decode / descramble data",
95 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
97 return demodDestron(true);
100 static int CmdDestronReader(const char *Cmd
) {
101 CLIParserContext
*ctx
;
102 CLIParserInit(&ctx
, "lf destron reader",
103 "read a Destron tag",
104 "lf destron reader -@ -> continuous reader mode"
109 arg_lit0("@", NULL
, "optional - continuous reader mode"),
112 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
113 bool cm
= arg_get_lit(ctx
, 1);
117 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
121 lf_read(false, 16000);
123 } while (cm
&& !kbd_enter_pressed());
128 static int CmdDestronClone(const char *Cmd
) {
129 CLIParserContext
*ctx
;
130 CLIParserInit(&ctx
, "lf destron clone",
131 "clone a Destron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
132 "lf destron clone --uid 1A2B3C4D5E\n"
133 "lf destron clone --q5 --uid 1A2B3C4D5E -> encode for Q5/T5555 tag\n"
134 "lf destron clone --em --uid 1A2B3C4D5E -> encode for EM4305/4469"
139 arg_strx1("u", "uid", "<hex>", "5 bytes max"),
140 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
141 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
145 //TODO add selection of chip for Q5 or T55x7
146 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
150 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
151 bool q5
= arg_get_lit(ctx
, 2);
152 bool em
= arg_get_lit(ctx
, 3);
156 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
161 PrintAndLogEx(FAILED
, "Uid is max 5 bytes. (got %u)", datalen
);
165 uint32_t blocks
[4] = {0};
166 blocks
[0] = T55x7_BITRATE_RF_50
| T55x7_MODULATION_FSK2
| 3 << T55x7_MAXBLOCK_SHIFT
;
167 char cardtype
[16] = {"T55x7"};
170 blocks
[0] = T5555_FIXED
| T5555_MODULATION_FSK2
| T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT
;
171 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
176 blocks
[0] = EM4305_DESTRON_CONFIG_BLOCK
;
177 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
180 uint8_t data_ex
[12 + 24] = {0}; // ManchesterEncode need extra room
181 for (int i
= 0; i
< datalen
; i
++) {
182 data_ex
[i
+ 1] = ~(data
[i
] | (oddparity8(data
[i
]) << 7));
185 // manchester encode it
186 for (int i
= 0; i
< 3; i
++) {
187 blocks
[i
+ 1] = manchesterEncode2Bytes((data_ex
[i
* 2] << 8) + data_ex
[i
* 2 + 1]);
190 blocks
[1] = (blocks
[1] & 0xFFFF) | 0xAAE20000;
192 PrintAndLogEx(INFO
, "Preparing to clone Destron tag to " _YELLOW_("%s") " with ID: " _YELLOW_("%s")
194 , sprint_hex_inrow(data
, datalen
)
198 print_blocks(blocks
, ARRAYLEN(blocks
));
201 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
203 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
205 PrintAndLogEx(SUCCESS
, "Done");
206 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf destron reader`") " to verify");
210 static int CmdDestronSim(const char *Cmd
) {
211 CLIParserContext
*ctx
;
212 CLIParserInit(&ctx
, "lf destron sim",
213 "Try to find Destron preamble, if found decode / descramble data",
221 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
223 PrintAndLogEx(INFO
, " To be implemented, feel free to contribute!");
227 static command_t CommandTable
[] = {
228 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
229 {"demod", CmdDestronDemod
, AlwaysAvailable
, "demodulate an Destron tag from the GraphBuffer"},
230 {"reader", CmdDestronReader
, IfPm3Lf
, "attempt to read and extract tag data"},
231 {"clone", CmdDestronClone
, IfPm3Lf
, "clone Destron tag to T55x7"},
232 {"sim", CmdDestronSim
, IfPm3Lf
, "simulate Destron tag"},
233 {NULL
, NULL
, NULL
, NULL
}
236 static int CmdHelp(const char *Cmd
) {
237 (void)Cmd
; // Cmd is not used so far
238 CmdsHelp(CommandTable
);
242 int CmdLFDestron(const char *Cmd
) {
243 clearCommandBuffer();
244 return CmdsParse(CommandTable
, Cmd
);
247 // find Destron preamble in already demoded data
248 int detectDestron(uint8_t *dest
, size_t *size
) {
250 //make sure buffer has data
254 size_t found_size
= *size
;
255 size_t start_idx
= 0;
257 uint8_t preamble
[DESTRON_PREAMBLE_SIZE
] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0};
259 // preamble not found
260 if (!preambleSearch(dest
, preamble
, sizeof(preamble
), &found_size
, &start_idx
)) {
263 PrintAndLogEx(DEBUG
, "DEBUG: detectDestron FSK found preamble");
266 // wrong demoded size
270 return (int)start_idx
;
273 int readDestronUid(void) {
274 return (CmdDestronReader("") == PM3_SUCCESS
);