+ return EM4x50Read(Cmd, true);
+}
+
+//**************** Start of EM4x05/EM4x69 Code ************************
+int usage_lf_em_read(void) {
+ PrintAndLog("Read EM4x05/EM4x69. Tag must be on antenna. ");
+ PrintAndLog("");
+ PrintAndLog("Usage: lf em 4x05readword [h] <address> <pwd>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h - this help");
+ PrintAndLog(" address - memory address to read. (0-15)");
+ PrintAndLog(" pwd - password (hex) (optional)");
+ PrintAndLog("samples:");
+ PrintAndLog(" lf em 4x05readword 1");
+ PrintAndLog(" lf em 4x05readword 1 11223344");
+ return 0;
+}
+
+// for command responses from em4x05 or em4x69
+// download samples from device and copy them to the Graphbuffer
+bool downloadSamplesEM() {
+ // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
+ uint8_t got[6000];
+ GetFromBigBuf(got, sizeof(got), 0);
+ if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) {
+ PrintAndLog("command execution time out");
+ return false;
+ }
+ setGraphBuf(got, sizeof(got));
+ return true;
+}
+
+bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) {
+ // em4x05/em4x69 preamble is 00001010
+ // skip first two 0 bits as they might have been missed in the demod
+ uint8_t preamble[] = {0,0,1,0,1,0};
+ size_t startIdx = 0;
+ // set size to 20 to only test first 14 positions for the preamble
+ size_t size = (20 > DemodBufferLen) ? DemodBufferLen : 20;
+
+ //test preamble
+ if ( !onePreambleSearch(DemodBuffer, preamble, sizeof(preamble), size, &startIdx) ) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305 preamble not found :: %d", startIdx);
+ return false;
+ }
+ // if this is a readword command, get the read bytes and test the parities
+ if (readCmd) {
+ if (!EM_EndParityTest(DemodBuffer + startIdx + sizeof(preamble), 45, 5, 9, 0)) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - End Parity check failed");
+ return false;
+ }
+ //test for even parity bits.
+ if ( removeParity(DemodBuffer, startIdx + sizeof(preamble),9,0,44) == 0 ) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - Parity not detected");
+ return false;
+ }
+
+ setDemodBuf(DemodBuffer, 40, 0);
+ *word = bytebits_to_byteLSBF(DemodBuffer, 32);
+ }
+ return true;
+}
+
+// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE
+// should cover 90% of known used configs
+// the rest will need to be manually demoded for now...
+int demodEM4x05resp(uint32_t *word, bool readCmd) {
+ int ans = 0;
+
+ // test for FSK wave (easiest to 99% ID)
+ if (GetFskClock("", false, false)) {
+ //valid fsk clocks found
+ ans = FSKrawDemod("0 0", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: FSK Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ }
+ // PSK clocks should be easy to detect ( but difficult to demod a non-repeating pattern... )
+ ans = GetPskClock("", false, false);
+ if (ans>0) {
+ //try psk1
+ ans = PSKDemod("0 0 6", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ } else {
+ //try psk2
+ psk1TOpsk2(DemodBuffer, DemodBufferLen);
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ //try psk1 inverted
+ ans = PSKDemod("0 1 6", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ } else {
+ //try psk2
+ psk1TOpsk2(DemodBuffer, DemodBufferLen);
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ // manchester is more common than biphase... try first
+ bool stcheck = false;
+ // try manchester - NOTE: ST only applies to T55x7 tags.
+ ans = ASKDemod_ext("0,0,1", false, false, 1, &stcheck);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/Manchester Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ //try biphase
+ ans = ASKbiphaseDemod("0 0 1", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ //try diphase (differential biphase or inverted)
+ ans = ASKbiphaseDemod("0 1 1", false);
+ if (!ans) {
+ if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
+ } else {
+ if (EM4x05testDemodReadData(word, readCmd)) {
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData) {
+ UsbCommand c = {CMD_EM4X_READ_WORD, {addr, pwd, usePwd}};
+ clearCommandBuffer();
+ SendCommand(&c);
+ UsbCommand resp;
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)){
+ PrintAndLog("Command timed out");
+ return -1;
+ }
+ if ( !downloadSamplesEM() ) {
+ return -1;
+ }
+ int testLen = (GraphTraceLen < 1000) ? GraphTraceLen : 1000;
+ if (graphJustNoise(GraphBuffer, testLen)) {
+ PrintAndLog("no tag not found");
+ return -1;
+ }
+ //attempt demod:
+ return demodEM4x05resp(wordData, true);
+}
+
+int EM4x05ReadWord(uint8_t addr, uint32_t pwd, bool usePwd) {
+ uint32_t wordData = 0;
+ int success = EM4x05ReadWord_ext(addr, pwd, usePwd, &wordData);
+ if (success == 1)
+ PrintAndLog(" Got Address %02d | %08X",addr,wordData);
+ else
+ PrintAndLog("Read Address %02d | failed",addr);
+
+ return success;
+}