1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Low frequency ZX8211 tag commands
17 //-----------------------------------------------------------------------------
19 #include "cmdlfzx8211.h"
25 #include "commonutil.h" // ARRAYLEN
27 #include "cmdparser.h" // command_t
33 #include "protocols.h" // for T55xx config register definitions
34 #include "lfdemod.h" // parityTest
35 #include "cmdlft55xx.h" // write verify
36 #include "cliparser.h"
39 static int CmdHelp(const char *Cmd
);
41 // see ASKDemod for what args are accepted
42 int demodzx(bool verbose
) {
43 (void) verbose
; // unused so far
44 buffer_savestate_t saveState
= save_bufferS32(g_GraphBuffer
, g_GraphTraceLen
);
45 saveState
.offset
= g_GridOffset
;
47 // CmdAskEdgeDetect("");
51 if (ASKDemod_ext(64, 0, 0, 0, false, false, false, 1, &st
) != PM3_SUCCESS
) {
52 PrintAndLogEx(DEBUG
, "DEBUG: Error - ZX: ASK/Manchester Demod failed");
53 restore_bufferS32(saveState
, g_GraphBuffer
);
54 g_GridOffset
= saveState
.offset
;
57 size_t size
= g_DemodBufferLen
;
58 int ans
= detectzx(g_DemodBuffer
, &size
);
61 PrintAndLogEx(DEBUG
, "DEBUG: Error - ZX: too few bits found");
63 PrintAndLogEx(DEBUG
, "DEBUG: Error - ZX: preamble not found");
65 PrintAndLogEx(DEBUG
, "DEBUG: Error - ZX: Size not correct: %zu", size
);
67 PrintAndLogEx(DEBUG
, "DEBUG: Error - ZX: ans: %d", ans
);
69 restore_bufferS32(saveState
, g_GraphBuffer
);
70 g_GridOffset
= saveState
.offset
;
73 setDemodBuff(g_DemodBuffer
, 96, ans
);
74 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
77 uint32_t raw1
= bytebits_to_byte(g_DemodBuffer
, 32);
83 PrintAndLogEx(SUCCESS
, "ZX8211 - Card " _GREEN_("%u"), raw1
);
87 static int lf_Zx_read(void) {
89 PacketResponseNG resp
;
92 SendCommandNG(CMD_LF_ZX_READ
, NULL
, 0);
94 if (WaitForResponseTimeout(CMD_LF_ZX_READ
, &resp
, 1000) == false) {
95 PrintAndLogEx(ERR
, "Error occurred, device did not respond during read operation.");
102 static int CmdZxDemod(const char *Cmd
) {
103 CLIParserContext
*ctx
;
104 CLIParserInit(&ctx
, "lf zx demod",
105 "Try to find zx8211 preamble, if found decode / descramble data",
113 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
115 return demodzx(true);
118 static int CmdzxReader(const char *Cmd
) {
119 CLIParserContext
*ctx
;
120 CLIParserInit(&ctx
, "lf zx reader",
122 "lf zx reader -@ -> continuous reader mode"
127 arg_lit0("@", NULL
, "optional - continuous reader mode"),
130 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
131 bool cm
= arg_get_lit(ctx
, 1);
135 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
141 } while (cm
&& !kbd_enter_pressed());
146 static command_t CommandTable
[] = {
147 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
148 {"demod", CmdZxDemod
, AlwaysAvailable
, "demodulate an ZX 8211 tag from the GraphBuffer"},
149 {"reader", CmdzxReader
, IfPm3Lf
, "attempt to read and extract tag data"},
150 {NULL
, NULL
, NULL
, NULL
}
153 static int CmdHelp(const char *Cmd
) {
154 (void)Cmd
; // Cmd is not used so far
155 CmdsHelp(CommandTable
);
159 int CmdLFZx8211(const char *Cmd
) {
160 clearCommandBuffer();
161 return CmdsParse(CommandTable
, Cmd
);
164 int detectzx(uint8_t *dest
, size_t *size
) {
165 if (*size
< 96) return -1; // make sure buffer has data
167 uint8_t preamble
[] = {0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0};
168 if (!preambleSearch(dest
, preamble
, sizeof(preamble
), size
, &startIdx
))
169 return -2; // preamble not found
170 if (*size
!= 96) return -3; // wrong demoded size
171 // return start position
172 return (int)startIdx
;