#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlfem4x.h"
+#include "lfdemod.h"
char *global_em410xId;
static int CmdHelp(const char *Cmd);
{
char cmdp = param_getchar(Cmd, 0);
int findone = (cmdp == '1') ? 1 : 0;
- UsbCommand c={CMD_EM410X_DEMOD};
- c.arg[0]=findone;
- SendCommand(&c);
- return 0;
+ UsbCommand c={CMD_EM410X_DEMOD};
+ c.arg[0]=findone;
+ SendCommand(&c);
+ return 0;
}
/* Read the ID of an EM410x tag.
*/
int CmdEM410xRead(const char *Cmd)
{
- uint32_t hi=0;
- uint64_t lo=0;
-
- if(!AskEm410xDemod("", &hi, &lo)) return 0;
- PrintAndLog("EM410x pattern found: ");
- printEM410x(hi, lo);
- if (hi){
- PrintAndLog ("EM410x XL pattern found");
- return 0;
- }
- char id[12] = {0x00};
- sprintf(id, "%010llx",lo);
-
- global_em410xId = id;
- return 1;
+ uint32_t hi=0;
+ uint64_t lo=0;
+
+ if(!AskEm410xDemod("", &hi, &lo)) return 0;
+ PrintAndLog("EM410x pattern found: ");
+ printEM410x(hi, lo);
+ if (hi){
+ PrintAndLog ("EM410x XL pattern found");
+ return 0;
+ }
+ char id[12] = {0x00};
+ sprintf(id, "%010llx",lo);
+
+ global_em410xId = id;
+ return 1;
}
// emulate an EM410X tag
PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X", uid[0],uid[1],uid[2],uid[3],uid[4]);
PrintAndLog("Press pm3-button to about simulation");
- /* clock is 64 in EM410x tags */
- int clock = 64;
-
- /* clear our graph */
- ClearGraph(0);
-
- /* write 9 start bits */
- for (i = 0; i < 9; i++)
- AppendGraph(0, clock, 1);
-
- /* for each hex char */
- parity[0] = parity[1] = parity[2] = parity[3] = 0;
- for (i = 0; i < 10; i++)
- {
- /* read each hex char */
- sscanf(&Cmd[i], "%1x", &n);
- for (j = 3; j >= 0; j--, n/= 2)
- binary[j] = n % 2;
-
- /* append each bit */
- AppendGraph(0, clock, binary[0]);
- AppendGraph(0, clock, binary[1]);
- AppendGraph(0, clock, binary[2]);
- AppendGraph(0, clock, binary[3]);
-
- /* append parity bit */
- AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
-
- /* keep track of column parity */
- parity[0] ^= binary[0];
- parity[1] ^= binary[1];
- parity[2] ^= binary[2];
- parity[3] ^= binary[3];
- }
-
- /* parity columns */
- AppendGraph(0, clock, parity[0]);
- AppendGraph(0, clock, parity[1]);
- AppendGraph(0, clock, parity[2]);
- AppendGraph(0, clock, parity[3]);
-
- /* stop bit */
- AppendGraph(1, clock, 0);
+ /* clock is 64 in EM410x tags */
+ int clock = 64;
+
+ /* clear our graph */
+ ClearGraph(0);
+
+ /* write 9 start bits */
+ for (i = 0; i < 9; i++)
+ AppendGraph(0, clock, 1);
+
+ /* for each hex char */
+ parity[0] = parity[1] = parity[2] = parity[3] = 0;
+ for (i = 0; i < 10; i++)
+ {
+ /* read each hex char */
+ sscanf(&Cmd[i], "%1x", &n);
+ for (j = 3; j >= 0; j--, n/= 2)
+ binary[j] = n % 2;
+
+ /* append each bit */
+ AppendGraph(0, clock, binary[0]);
+ AppendGraph(0, clock, binary[1]);
+ AppendGraph(0, clock, binary[2]);
+ AppendGraph(0, clock, binary[3]);
+
+ /* append parity bit */
+ AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
+
+ /* keep track of column parity */
+ parity[0] ^= binary[0];
+ parity[1] ^= binary[1];
+ parity[2] ^= binary[2];
+ parity[3] ^= binary[3];
+ }
+
+ /* parity columns */
+ AppendGraph(0, clock, parity[0]);
+ AppendGraph(0, clock, parity[1]);
+ AppendGraph(0, clock, parity[2]);
+ AppendGraph(0, clock, parity[3]);
+
+ /* stop bit */
+ AppendGraph(1, clock, 0);
- CmdLFSim("0"); //240 start_gap.
- return 0;
+ CmdLFSim("0"); //240 start_gap.
+ return 0;
}
/* Function is equivalent of lf read + data samples + em410xread
return 0;
}
+//currently only supports manchester modulations
int CmdEM410xWatchnSpoof(const char *Cmd)
{
CmdEM410xWatch(Cmd);
return 0;
}
+bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
+{
+ if (rows*cols>size) return false;
+ uint8_t colP=0;
+ //assume last row is a parity row and do not test
+ for (uint8_t colNum = 0; colNum < cols-1; colNum++) {
+ for (uint8_t rowNum = 0; rowNum < rows; rowNum++) {
+ colP ^= BitStream[(rowNum*cols)+colNum];
+ }
+ if (colP != pType) return false;
+ }
+ return true;
+}
+
+bool EM_ByteParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
+{
+ if (rows*cols>size) return false;
+ uint8_t rowP=0;
+ //assume last row is a parity row and do not test
+ for (uint8_t rowNum = 0; rowNum < rows-1; rowNum++) {
+ for (uint8_t colNum = 0; colNum < cols; colNum++) {
+ rowP ^= BitStream[(rowNum*cols)+colNum];
+ }
+ if (rowP != pType) return false;
+ }
+ return true;
+}
+
+uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest)
+{
+ if (size<45) return 0;
+ uint32_t code = bytebits_to_byte(BitStream,8);
+ code = code<<8 | bytebits_to_byte(BitStream+9,8);
+ code = code<<8 | bytebits_to_byte(BitStream+18,8);
+ code = code<<8 | bytebits_to_byte(BitStream+27,8);
+ if (verbose || g_debugMode){
+ for (uint8_t i = 0; i<5; i++){
+ if (i == 4) PrintAndLog("");
+ PrintAndLog("%d%d%d%d%d%d%d%d %d -> 0x%02x",
+ BitStream[i*9],
+ BitStream[i*9+1],
+ BitStream[i*9+2],
+ BitStream[i*9+3],
+ BitStream[i*9+4],
+ BitStream[i*9+5],
+ BitStream[i*9+6],
+ BitStream[i*9+7],
+ BitStream[i*9+8],
+ bytebits_to_byte(BitStream+i*9,8)
+ );
+ }
+ if (pTest)
+ PrintAndLog("Parity Passed");
+ else
+ PrintAndLog("Parity Failed");
+ }
+ //PrintAndLog("Code: %08x",code);
+ return code;
+}
/* Read the transmitted data of an EM4x50 tag
* Format:
*
* is stored in the blocks defined in the control word First and Last
* Word Read values. UID is stored in block 32.
*/
+int EM4x50Read(const char *Cmd, bool verbose)
+{
+ uint8_t fndClk[]={0,8,16,32,40,50,64};
+ int clk = 0;
+ int invert = 0;
+ sscanf(Cmd, "%i %i", &clk, &invert);
+ int tol = 0;
+ int i, j, startblock, skip, block, start, end, low, high, minClk;
+ bool complete= false;
+ int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
+ save_restoreGB(1);
+ uint32_t Code[6];
+ char tmp[6];
+
+ char tmp2[20];
+ high= low= 0;
+ memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
+
+ // first get high and low values
+ for (i = 0; i < GraphTraceLen; i++)
+ {
+ if (GraphBuffer[i] > high)
+ high = GraphBuffer[i];
+ else if (GraphBuffer[i] < low)
+ low = GraphBuffer[i];
+ }
+
+ // populate a buffer with pulse lengths
+ i= 0;
+ j= 0;
+ minClk= 255;
+ while (i < GraphTraceLen)
+ {
+ // measure from low to low
+ while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
+ ++i;
+ start= i;
+ while ((GraphBuffer[i] < high) && (i<GraphTraceLen))
+ ++i;
+ while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
+ ++i;
+ if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
+ break;
+ }
+ tmpbuff[j++]= i - start;
+ if (i-start < minClk) minClk = i-start;
+ }
+ // set clock
+ if (!clk){
+ for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
+ tol = fndClk[clkCnt]/8;
+ if (fndClk[clkCnt]-tol >= minClk) {
+ clk=fndClk[clkCnt];
+ break;
+ }
+ }
+ }
+
+ // look for data start - should be 2 pairs of LW (pulses of clk*3,clk*2)
+ start= -1;
+ skip= 0;
+ for (i= 0; i < j - 4 ; ++i)
+ {
+ skip += tmpbuff[i];
+ if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol)
+ if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol)
+ if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol)
+ if (tmpbuff[i+3] >= clk-tol)
+ {
+ start= i + 4;
+ break;
+ }
+ }
+ startblock= i + 4;
+
+ // skip over the remainder of LW
+ skip += tmpbuff[i+1] + tmpbuff[i+2] + clk + clk/8;
+
+ int phaseoff = tmpbuff[i+3]-clk;
+
+ // now do it again to find the end
+ end = skip;
+ for (i += 3; i < j - 4 ; ++i)
+ {
+ end += tmpbuff[i];
+ if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3 + tol)
+ if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2 + tol)
+ if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3 + tol)
+ if (tmpbuff[i+3] >= clk-tol)
+ {
+ complete= true;
+ break;
+ }
+ }
+ end = i;
+ // report back
+ if (verbose || g_debugMode) {
+ if (start >= 0) {
+ PrintAndLog("\nNote: should print 45 bits then 0177 (end of block)");
+ PrintAndLog(" for each block");
+ PrintAndLog(" Also, sometimes the demod gets out of sync and ");
+ PrintAndLog(" inverts the output - when this happens the 0177");
+ PrintAndLog(" will be 3 extra 1's at the end");
+ PrintAndLog(" 'data askedge' command may fix that");
+ } else {
+ PrintAndLog("No data found!");
+ PrintAndLog("Try again with more samples.");
+ return 0;
+ }
+ if (!complete)
+ {
+ PrintAndLog("*** Warning!");
+ PrintAndLog("Partial data - no end found!");
+ PrintAndLog("Try again with more samples.");
+ }
+ } else if (start < 0) return 0;
+ start=skip;
+ snprintf(tmp2, sizeof(tmp2),"%d %d 1000 %d", clk, invert, clk*47);
+ // get rid of leading crap
+ snprintf(tmp, sizeof(tmp),"%i",skip);
+ CmdLtrim(tmp);
+ bool pTest;
+ bool AllPTest=true;
+ // now work through remaining buffer printing out data blocks
+ block = 0;
+ i = startblock;
+ while (block < 6)
+ {
+ if (verbose || g_debugMode) PrintAndLog("\nBlock %i:", block);
+ skip = phaseoff;
+
+ // look for LW before start of next block
+ for ( ; i < j - 4 ; ++i)
+ {
+ skip += tmpbuff[i];
+ if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol)
+ if (tmpbuff[i+1] >= clk-tol)
+ break;
+ }
+ skip += clk;
+ phaseoff = tmpbuff[i+1]-clk;
+ i += 2;
+ if (ASKmanDemod(tmp2, false, false)<1) return 0;
+ //set DemodBufferLen to just one block
+ DemodBufferLen = skip/clk;
+ //test parities
+ pTest = EM_ByteParityTest(DemodBuffer,DemodBufferLen,5,9,0);
+ pTest &= EM_EndParityTest(DemodBuffer,DemodBufferLen,5,9,0);
+ AllPTest &= pTest;
+ //get output
+ Code[block]=OutputEM4x50_Block(DemodBuffer,DemodBufferLen,verbose, pTest);
+ if (g_debugMode) PrintAndLog("\nskipping %d samples, bits:%d",start, skip/clk);
+ //skip to start of next block
+ snprintf(tmp,sizeof(tmp),"%i",skip);
+ CmdLtrim(tmp);
+ block++;
+ if (i>=end) break; //in case chip doesn't output 6 blocks
+ }
+ //print full code:
+ if (verbose || g_debugMode || AllPTest){
+ PrintAndLog("Found data at sample: %i - using clock: %i",skip,clk);
+ //PrintAndLog("\nSummary:");
+ end=block;
+ for (block=0; block<end; block++){
+ PrintAndLog("Block %d: %08x",block,Code[block]);
+ }
+ if (AllPTest)
+ PrintAndLog("Parities Passed");
+ else
+ PrintAndLog("Parities Failed");
+ }
+
+ //restore GraphBuffer
+ save_restoreGB(0);
+ return (int)AllPTest;
+}
+
int CmdEM4x50Read(const char *Cmd)
{
- int i, j, startblock, skip, block, start, end, low, high;
- bool complete= false;
- int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
- char tmp[6];
-
- high= low= 0;
- memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
-
- /* first get high and low values */
- for (i = 0; i < GraphTraceLen; i++)
- {
- if (GraphBuffer[i] > high)
- high = GraphBuffer[i];
- else if (GraphBuffer[i] < low)
- low = GraphBuffer[i];
- }
-
- /* populate a buffer with pulse lengths */
- i= 0;
- j= 0;
- while (i < GraphTraceLen)
- {
- // measure from low to low
- while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
- ++i;
- start= i;
- while ((GraphBuffer[i] < high) && (i<GraphTraceLen))
- ++i;
- while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
- ++i;
- if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
- break;
- }
- tmpbuff[j++]= i - start;
- }
-
- /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
- start= -1;
- skip= 0;
- for (i= 0; i < j - 4 ; ++i)
- {
- skip += tmpbuff[i];
- if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
- if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
- if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
- if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
- {
- start= i + 3;
- break;
- }
- }
- startblock= i + 3;
-
- /* skip over the remainder of the LW */
- skip += tmpbuff[i+1]+tmpbuff[i+2];
- while (skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)
- ++skip;
- skip += 8;
-
- /* now do it again to find the end */
- end= start;
- for (i += 3; i < j - 4 ; ++i)
- {
- end += tmpbuff[i];
- if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
- if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
- if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
- if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
- {
- complete= true;
- break;
- }
- }
-
- if (start >= 0)
- PrintAndLog("Found data at sample: %i",skip);
- else
- {
- PrintAndLog("No data found!");
- PrintAndLog("Try again with more samples.");
- return 0;
- }
-
- if (!complete)
- {
- PrintAndLog("*** Warning!");
- PrintAndLog("Partial data - no end found!");
- PrintAndLog("Try again with more samples.");
- }
-
- /* get rid of leading crap */
- sprintf(tmp,"%i",skip);
- CmdLtrim(tmp);
-
- /* now work through remaining buffer printing out data blocks */
- block= 0;
- i= startblock;
- while (block < 6)
- {
- PrintAndLog("Block %i:", block);
- // mandemod routine needs to be split so we can call it for data
- // just print for now for debugging
- CmdManchesterDemod("i 64");
- skip= 0;
- /* look for LW before start of next block */
- for ( ; i < j - 4 ; ++i)
- {
- skip += tmpbuff[i];
- if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
- if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
- break;
- }
- while (GraphBuffer[skip] > low)
- ++skip;
- skip += 8;
- sprintf(tmp,"%i",skip);
- CmdLtrim(tmp);
- start += skip;
- block++;
- }
- return 0;
+ return EM4x50Read(Cmd, true);
}
int CmdEM410xWrite(const char *Cmd)
{
- uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
- int card = 0xFF; // invalid card value
+ uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
+ int card = 0xFF; // invalid card value
unsigned int clock = 0; // invalid clock value
sscanf(Cmd, "%" PRIx64 " %d %d", &id, &card, &clock);
return 0;
}
- UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
- SendCommand(&c);
+ UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
+ SendCommand(&c);
- return 0;
+ return 0;
}
int CmdReadWord(const char *Cmd)
{
int Word = -1; //default to invalid word
- UsbCommand c;
-
- sscanf(Cmd, "%d", &Word);
-
+ UsbCommand c;
+
+ sscanf(Cmd, "%d", &Word);
+
if ( (Word > 15) | (Word < 0) ) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
- }
-
- PrintAndLog("Reading word %d", Word);
-
- c.cmd = CMD_EM4X_READ_WORD;
- c.d.asBytes[0] = 0x0; //Normal mode
- c.arg[0] = 0;
- c.arg[1] = Word;
- c.arg[2] = 0;
- SendCommand(&c);
- return 0;
+ PrintAndLog("Word must be between 0 and 15");
+ return 1;
+ }
+
+ PrintAndLog("Reading word %d", Word);
+
+ c.cmd = CMD_EM4X_READ_WORD;
+ c.d.asBytes[0] = 0x0; //Normal mode
+ c.arg[0] = 0;
+ c.arg[1] = Word;
+ c.arg[2] = 0;
+ SendCommand(&c);
+ return 0;
}
int CmdReadWordPWD(const char *Cmd)
{
int Word = -1; //default to invalid word
- int Password = 0xFFFFFFFF; //default to blank password
- UsbCommand c;
-
- sscanf(Cmd, "%d %x", &Word, &Password);
-
+ int Password = 0xFFFFFFFF; //default to blank password
+ UsbCommand c;
+
+ sscanf(Cmd, "%d %x", &Word, &Password);
+
if ( (Word > 15) | (Word < 0) ) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
- }
-
- PrintAndLog("Reading word %d with password %08X", Word, Password);
-
- c.cmd = CMD_EM4X_READ_WORD;
- c.d.asBytes[0] = 0x1; //Password mode
- c.arg[0] = 0;
- c.arg[1] = Word;
- c.arg[2] = Password;
- SendCommand(&c);
- return 0;
+ PrintAndLog("Word must be between 0 and 15");
+ return 1;
+ }
+
+ PrintAndLog("Reading word %d with password %08X", Word, Password);
+
+ c.cmd = CMD_EM4X_READ_WORD;
+ c.d.asBytes[0] = 0x1; //Password mode
+ c.arg[0] = 0;
+ c.arg[1] = Word;
+ c.arg[2] = Password;
+ SendCommand(&c);
+ return 0;
}
int CmdWriteWord(const char *Cmd)
{
- int Word = 16; //default to invalid block
- int Data = 0xFFFFFFFF; //default to blank data
- UsbCommand c;
-
- sscanf(Cmd, "%x %d", &Data, &Word);
-
- if (Word > 15) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
- }
-
- PrintAndLog("Writing word %d with data %08X", Word, Data);
-
- c.cmd = CMD_EM4X_WRITE_WORD;
- c.d.asBytes[0] = 0x0; //Normal mode
- c.arg[0] = Data;
- c.arg[1] = Word;
- c.arg[2] = 0;
- SendCommand(&c);
- return 0;
+ int Word = 16; //default to invalid block
+ int Data = 0xFFFFFFFF; //default to blank data
+ UsbCommand c;
+
+ sscanf(Cmd, "%x %d", &Data, &Word);
+
+ if (Word > 15) {
+ PrintAndLog("Word must be between 0 and 15");
+ return 1;
+ }
+
+ PrintAndLog("Writing word %d with data %08X", Word, Data);
+
+ c.cmd = CMD_EM4X_WRITE_WORD;
+ c.d.asBytes[0] = 0x0; //Normal mode
+ c.arg[0] = Data;
+ c.arg[1] = Word;
+ c.arg[2] = 0;
+ SendCommand(&c);
+ return 0;
}
int CmdWriteWordPWD(const char *Cmd)
{
- int Word = 16; //default to invalid word
- int Data = 0xFFFFFFFF; //default to blank data
- int Password = 0xFFFFFFFF; //default to blank password
- UsbCommand c;
-
- sscanf(Cmd, "%x %d %x", &Data, &Word, &Password);
-
- if (Word > 15) {
- PrintAndLog("Word must be between 0 and 15");
- return 1;
- }
-
- PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
-
- c.cmd = CMD_EM4X_WRITE_WORD;
- c.d.asBytes[0] = 0x1; //Password mode
- c.arg[0] = Data;
- c.arg[1] = Word;
- c.arg[2] = Password;
- SendCommand(&c);
- return 0;
+ int Word = 16; //default to invalid word
+ int Data = 0xFFFFFFFF; //default to blank data
+ int Password = 0xFFFFFFFF; //default to blank password
+ UsbCommand c;
+
+ sscanf(Cmd, "%x %d %x", &Data, &Word, &Password);
+
+ if (Word > 15) {
+ PrintAndLog("Word must be between 0 and 15");
+ return 1;
+ }
+
+ PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
+
+ c.cmd = CMD_EM4X_WRITE_WORD;
+ c.d.asBytes[0] = 0x1; //Password mode
+ c.arg[0] = Data;
+ c.arg[1] = Word;
+ c.arg[2] = Password;
+ SendCommand(&c);
+ return 0;
}
static command_t CommandTable[] =
{
- {"help", CmdHelp, 1, "This help"},
- {"em410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
- {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
- {"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
- {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
- {"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
- {"em410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
- {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
- {"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
- {"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
- {"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
- {"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
- {NULL, NULL, 0, NULL}
+ {"help", CmdHelp, 1, "This help"},
+ {"em410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
+ {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
+ {"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
+ {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
+ {"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
+ {"em410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
+ {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
+ {"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
+ {"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
+ {"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
+ {"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
+ {NULL, NULL, 0, NULL}
};
int CmdLFEM4X(const char *Cmd)
{
- CmdsParse(CommandTable, Cmd);
- return 0;
+ CmdsParse(CommandTable, Cmd);
+ return 0;
}
int CmdHelp(const char *Cmd)
{
- CmdsHelp(CommandTable);
- return 0;
+ CmdsHelp(CommandTable);
+ return 0;
}
return 0;
}
+// demodulates strong heavily clipped samples
+int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low)
+{
+ size_t bitCnt=0, smplCnt=0, errCnt=0;
+ uint8_t waveHigh = 0;
+ //PrintAndLog("clk: %d", clk);
+ for (size_t i=0; i < *size; i++){
+ if (BinStream[i] >= high && waveHigh){
+ smplCnt++;
+ } else if (BinStream[i] <= low && !waveHigh){
+ smplCnt++;
+ } else { //transition
+ if ((BinStream[i] >= high && !waveHigh) || (BinStream[i] <= low && waveHigh)){
+ if (smplCnt > clk-(clk/4)-1) { //full clock
+ if (smplCnt > clk + (clk/4)+1) { //too many samples
+ errCnt++;
+ BinStream[bitCnt++]=77;
+ } else if (waveHigh) {
+ BinStream[bitCnt++] = invert;
+ BinStream[bitCnt++] = invert;
+ } else if (!waveHigh) {
+ BinStream[bitCnt++] = invert ^ 1;
+ BinStream[bitCnt++] = invert ^ 1;
+ }
+ waveHigh ^= 1;
+ smplCnt = 0;
+ } else if (smplCnt > (clk/2) - (clk/4)-1) {
+ if (waveHigh) {
+ BinStream[bitCnt++] = invert;
+ } else if (!waveHigh) {
+ BinStream[bitCnt++] = invert ^ 1;
+ }
+ waveHigh ^= 1;
+ smplCnt = 0;
+ } else if (!bitCnt) {
+ //first bit
+ waveHigh = (BinStream[i] >= high);
+ smplCnt = 1;
+ } else {
+ smplCnt++;
+ //transition bit oops
+ }
+ } else { //haven't hit new high or new low yet
+ smplCnt++;
+ }
+ }
+ }
+ *size = bitCnt;
+ return errCnt;
+}
+
//by marshmellow
//takes 3 arguments - clock, invert, maxErr as integers
//attempts to demodulate ask while decoding manchester
int high, low;
if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1) return -2; //just noise
+ // if clean clipped waves detected run alternate demod
+ if (DetectCleanAskWave(BinStream, *size, high, low)) {
+ cleanAskRawDemod(BinStream, size, *clk, *invert, high, low);
+ return manrawdecode(BinStream, size);
+ }
+
+
// PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low);
int lastBit = 0; //set first clock check
uint16_t bitnum = 0; //output counter
if (*clk <= 32) tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely
size_t iii = 0;
//if 0 errors allowed then only try first 2 clock cycles as we want a low tolerance
- if (!maxErr) initLoopMax = *clk * 2;
+ if (!maxErr && initLoopMax > *clk*3) initLoopMax = *clk * 3;
uint16_t errCnt = 0, MaxBits = 512;
uint16_t bestStart = start;
uint16_t bestErrCnt = 0;
if (start <= 0 || start > initLoopMax){
bestErrCnt = maxErr+1;
// loop to find first wave that works
- for (iii=0; iii < initLoopMax; ++iii){
+ for (iii=0; iii < initLoopMax-tol-*clk; ++iii){
// if no peak skip
if (BinStream[iii] < high && BinStream[iii] > low) continue;
if ((i-iii) > (MaxBits * *clk) || errCnt > maxErr) break; //got plenty of bits or too many errors
}
//we got more than 64 good bits and not all errors
- if ((((i-iii)/ *clk) > (64)) && (errCnt<=maxErr)) {
+ if ((((i-iii)/ *clk) > (32)) && (errCnt<=maxErr)) {
//possible good read
if (!errCnt || errCnt < bestErrCnt){
bestStart = iii; //set this as new best run
}
errCnt=0;
}
- if (bestErr<20){
- for (i=bestRun; i < *size-2; i+=2){
- if(BitStream[i] == 1 && (BitStream[i+1] == 0)){
- BitStream[bitnum++]=0;
- } else if((BitStream[i] == 0) && BitStream[i+1] == 1){
- BitStream[bitnum++]=1;
- } else {
- BitStream[bitnum++]=77;
- }
- if(bitnum>MaxBits) break;
+ for (i=bestRun; i < *size-2; i+=2){
+ if(BitStream[i] == 1 && (BitStream[i+1] == 0)){
+ BitStream[bitnum++]=0;
+ } else if((BitStream[i] == 0) && BitStream[i+1] == 1){
+ BitStream[bitnum++]=1;
+ } else {
+ BitStream[bitnum++]=77;
}
- *size=bitnum;
+ if(bitnum>MaxBits) break;
}
+ *size=bitnum;
return bestErr;
}
return;
}
-// demodulates strong heavily clipped samples
-int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low)
-{
- size_t bitCnt=0, smplCnt=0, errCnt=0;
- uint8_t waveHigh = 0;
- //PrintAndLog("clk: %d", clk);
- for (size_t i=0; i < *size; i++){
- if (BinStream[i] >= high && waveHigh){
- smplCnt++;
- } else if (BinStream[i] <= low && !waveHigh){
- smplCnt++;
- } else { //transition
- if ((BinStream[i] >= high && !waveHigh) || (BinStream[i] <= low && waveHigh)){
- if (smplCnt > clk-(clk/4)-1) { //full clock
- if (smplCnt > clk + (clk/4)+1) { //too many samples
- errCnt++;
- BinStream[bitCnt++]=77;
- } else if (waveHigh) {
- BinStream[bitCnt++] = invert;
- BinStream[bitCnt++] = invert;
- } else if (!waveHigh) {
- BinStream[bitCnt++] = invert ^ 1;
- BinStream[bitCnt++] = invert ^ 1;
- }
- waveHigh ^= 1;
- smplCnt = 0;
- } else if (smplCnt > (clk/2) - (clk/4)-1) {
- if (waveHigh) {
- BinStream[bitCnt++] = invert;
- } else if (!waveHigh) {
- BinStream[bitCnt++] = invert ^ 1;
- }
- waveHigh ^= 1;
- smplCnt = 0;
- } else if (!bitCnt) {
- //first bit
- waveHigh = (BinStream[i] >= high);
- smplCnt = 1;
- } else {
- smplCnt++;
- //transition bit oops
- }
- } else { //haven't hit new high or new low yet
- smplCnt++;
- }
- }
- }
- *size = bitCnt;
- return errCnt;
-}
-
//by marshmellow
//takes 3 arguments - clock, invert and maxErr as integers
//attempts to demodulate ask only
size_t MaxBits = 1024;
//if 0 errors allowed then only try first 2 clock cycles as we want a low tolerance
- if (!maxErr) initLoopMax = *clk * 2;
+ if (!maxErr && initLoopMax > *clk*3) initLoopMax = *clk * 3;
//if best start not already found by detectclock
if (start <= 0 || start > initLoopMax){
bestErrCnt = maxErr+1;
//PrintAndLog("DEBUG - lastbit - %d",lastBit);
//loop to find first wave that works
- for (iii=0; iii < initLoopMax; ++iii){
+ for (iii=0; iii < initLoopMax - *clk; ++iii){
if ((BinStream[iii] >= high) || (BinStream[iii] <= low)){
lastBit = iii - *clk;
//loop through to see if this start location works
}
if ((i-iii)>(MaxBits * *clk)) break; //got enough bits
}
- //we got more than 64 good bits and not all errors
- if ((((i-iii)/ *clk) > 64) && (errCnt<=maxErr)) {
+ //we got more than 32 good bits and not all errors
+ if ((((i-iii)/ *clk) > 32) && (errCnt<=maxErr)) {
//possible good read
if (errCnt==0){
bestStart=iii;
size_t i=0;
uint8_t clk[]={8,16,32,40,50,64,100,128,255};
uint8_t loopCnt = 255; //don't need to loop through entire array...
- if (size <= loopCnt) return -1; //not enough samples
+ if (size==0) return -1;
+ if (size <= loopCnt) loopCnt = size-1; //not enough samples
//if we already have a valid clock quit
for (;i<8;++i)
}else{
tol=0;
}
- if (!maxErr) loopCnt=clk[clkCnt]*2;
+ if (!maxErr && loopCnt>clk[clkCnt]*2) loopCnt=clk[clkCnt]*2;
bestErr[clkCnt]=1000;
//try lining up the peaks by moving starting point (try first 256)
- for (ii=0; ii < loopCnt; ii++){
+ for (ii=0; ii < loopCnt-tol-clk[clkCnt]; ii++){
if (dest[ii] < peak && dest[ii] > low) continue;
errCnt=0;