]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge pull request #216 from marshmellow42/master
authorpwpiwi <pwpiwi@users.noreply.github.com>
Wed, 22 Feb 2017 16:38:56 +0000 (17:38 +0100)
committerGitHub <noreply@github.com>
Wed, 22 Feb 2017 16:38:56 +0000 (17:38 +0100)
EM4x05/EM4x69 command rewrite and improvements

17 files changed:
CHANGELOG.md
armsrc/appmain.c
armsrc/apps.h
armsrc/lfops.c
armsrc/lfsampling.c
armsrc/lfsampling.h
client/cmddata.h
client/cmdlf.c
client/cmdlfawid.c
client/cmdlfem4x.c
client/cmdlfem4x.h
client/cmdlfpresco.c
client/graph.c
client/util.c
client/util.h
common/lfdemod.c
common/lfdemod.h

index a7c5fcbf42986a21f36fc89d25166ee5f79453cb..936fbbd07710768713d582e47f89bf9459ba07e7 100644 (file)
@@ -5,6 +5,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 ## [unreleased][unreleased]
 
 ### Added
+- Added EM4x05/EM4x69 chip detection to lf search (marshmellow) 
+- Added lf em 4x05dump command to read and output all the blocks of the chip (marshmellow)
+- Added lf em 4x05info command to read and display information about the chip (marshmellow)
 - Added lf cotag read, and added it to lf search (iceman)
 - Added hitag2 read UID only and added that to lf search (marshmellow)
 - Added lf pyramid commands (iceman)
@@ -38,6 +41,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added option c to 'hf list' (mark CRC bytes) (piwi)
 
 ### Changed
+- small changes to lf psk and fsk demods to improve results when the trace begins with noise or the chip isn't broadcasting yet (marshmellow)
+- NOTE CHANGED ALL `lf em4x em*` cmds to simpler `lf em ` - example: `lf em4x em410xdemod` is now `lf em 410xdemod`
+- Renamed and rebuilt `lf em readword` && readwordpwd to `lf em 4x05readword` - it now demods and outputs the read block (marshmellow/iceman)
+- Renamed and rebuilt `lf em writeword` && writewordpwd to `lf em 4x05writeword` - it now also reads validation output from the tag (marshmellow/iceman)
 - Fixed bug in lf sim and continuous demods not turning off antenna when finished
 - Fixed bug(s) in hf iclass write
 - Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow)
index ec133c7a81551dc4752679a9d3805f1f865c252e..0385517242cb6b215518328a270e7fd07cc9dc72 100644 (file)
@@ -1017,10 +1017,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
                        WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]);
                        break;
                case CMD_EM4X_READ_WORD:
-                       EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]);
+                       EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]);
                        break;
                case CMD_EM4X_WRITE_WORD:
-                       EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
+                       EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]);
                        break;
                case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
                        CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
index cbe3b239e1b27533cff0e764eb430a5c59839936..8d51335b2d5dada50363d70c403657a58a9086fb 100644 (file)
@@ -88,7 +88,7 @@ void T55xxWakeUp(uint32_t Pwd);
 void TurnReadLFOn();
 //void T55xxReadTrace(void);
 void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
-void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
+void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd);
 void Cotag(uint32_t arg0);
 
 /// iso14443.h
index 0a8ce3a9ff459b9a6ff0b4963b79ca6572687e3e..d79c75a0bf68784a3fcbc46ad5ac3ef158e64f08 100644 (file)
@@ -684,7 +684,7 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream)
                for (i=0; i<size; i++){
                        askSimBit(BitStream[i]^invert, &n, clk, encoding);
                }
-               if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for biphase phase)
+               if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for ask/raw || biphase phase)
                        for (i=0; i<size; i++){
                                askSimBit(BitStream[i]^invert^1, &n, clk, encoding);
                        }
@@ -1358,7 +1358,7 @@ void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t
        //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7)
        data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (7 << T55x7_MAXBLOCK_SHIFT);
        //TODO add selection of chip for Q5 or T55x7
-       // data[0] = (((32-2)/2)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
+       // data[0] = (((32-2)>>1)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
        WriteT55xx(data, 0, 8);
        //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data)
        //      T5567WriteBlock(0x603E10E2,0);
@@ -1367,7 +1367,7 @@ void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t
 // clone viking tag to T55xx
 void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5) {
        uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), block1, block2};
-       if (Q5) data[0] = (32 << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
+       if (Q5) data[0] = ( ((32-2)>>1) << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
        // Program the data blocks for supplied ID and the block 0 config
        WriteT55xx(data, 0, 3);
        LED_D_OFF();
@@ -1571,8 +1571,6 @@ void SendForward(uint8_t fwd_bit_count) {
        fwd_write_ptr = forwardLink_data;
        fwd_bit_sz = fwd_bit_count;
 
-       LED_D_ON();
-
        // Set up FPGA, 125kHz
        LFSetupFPGAForADC(95, true);
 
@@ -1580,9 +1578,9 @@ void SendForward(uint8_t fwd_bit_count) {
        fwd_bit_sz--; //prepare next bit modulation
        fwd_write_ptr++;
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
-       SpinDelayUs(55*8); //55 cycles off (8us each)for 4305
+       SpinDelayUs(56*8); //55 cycles off (8us each)for 4305  /another reader has 37 here...
        FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
-       SpinDelayUs(16*8); //16 cycles on (8us each)
+       SpinDelayUs(18*8); //16 cycles on (8us each)  // another reader has 18 here
 
        // now start writting
        while(fwd_bit_sz-- > 0) { //prepare next bit modulation
@@ -1591,9 +1589,9 @@ void SendForward(uint8_t fwd_bit_count) {
                else {
                        //These timings work for 4469/4269/4305 (with the 55*8 above)
                        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
-                       SpinDelayUs(23*8); //16-4 cycles off (8us each)
+                       SpinDelayUs(23*8); //16-4 cycles off (8us each) //23  //one reader goes as high as 25 here
                        FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
-                       SpinDelayUs(9*8); //16 cycles on (8us each)
+                       SpinDelayUs(16*8); //16 cycles on (8us each) //9  // another reader goes to 17 here
                }
        }
 }
@@ -1615,13 +1613,11 @@ void EM4xLogin(uint32_t Password) {
 void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
 
        uint8_t fwd_bit_count;
-       uint8_t *dest = BigBuf_get_addr();
-       uint16_t bufferlength = BigBuf_max_traceLen();
-       uint32_t i = 0;
 
        // Clear destination buffer before sending the command
        BigBuf_Clear_ext(false);
 
+       LED_A_ON();
        //If password mode do login
        if (PwdMode == 1) EM4xLogin(Pwd);
 
@@ -1629,36 +1625,28 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
        fwd_bit_count = Prepare_Cmd( FWD_CMD_READ );
        fwd_bit_count += Prepare_Addr( Address );
 
-       // Connect the A/D to the peak-detected low-frequency path.
-       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
-       // Now set up the SSC to get the ADC samples that are now streaming at us.
-       FpgaSetupSsc();
-
        SendForward(fwd_bit_count);
-
+       SpinDelayUs(400);
        // Now do the acquisition
-       i = 0;
-       for(;;) {
-               if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
-                       AT91C_BASE_SSC->SSC_THR = 0x43;
-               }
-               if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
-                       dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-                       i++;
-                       if (i >= bufferlength) break;
-               }
-       }
+       DoPartialAcquisition(20, true, 6000);
+       
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
+       LED_A_OFF();
        cmd_send(CMD_ACK,0,0,0,0,0);
-       LED_D_OFF();
 }
 
-void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
-
+void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
+       
+       bool PwdMode = (flag & 0xF);
+       uint8_t Address = (flag >> 8) & 0xFF;
        uint8_t fwd_bit_count;
 
+       //clear buffer now so it does not interfere with timing later
+       BigBuf_Clear_ext(false);
+
+       LED_A_ON();
        //If password mode do login
-       if (PwdMode == 1) EM4xLogin(Pwd);
+       if (PwdMode) EM4xLogin(Pwd);
 
        forward_ptr = forwardLink_data;
        fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE );
@@ -1668,9 +1656,15 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode
        SendForward(fwd_bit_count);
 
        //Wait for write to complete
-       SpinDelay(20);
+       //SpinDelay(10);
+
+       SpinDelayUs(6500);
+       //Capture response if one exists
+       DoPartialAcquisition(20, true, 6000);
+
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
-       LED_D_OFF();
+       LED_A_OFF();
+       cmd_send(CMD_ACK,0,0,0,0,0);
 }
 /*
 Reading a COTAG.
index 72aabe00fda46318b1959d93c5150e626a1a8d9a..aff31e9eaf28d86db3663bb2a6e7341c051b0e07 100644 (file)
@@ -119,11 +119,11 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
  * @param silent - is true, now outputs are made. If false, dbprints the status
  * @return the number of bits occupied by the samples.
  */
-uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent)
+uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize)
 {
        //.
        uint8_t *dest = BigBuf_get_addr();
-    int bufsize = BigBuf_max_traceLen();
+       bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
 
        //memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow)
 
@@ -213,7 +213,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
  */
 uint32_t DoAcquisition_default(int trigger_threshold, bool silent)
 {
-       return DoAcquisition(1,8,0,trigger_threshold,silent);
+       return DoAcquisition(1,8,0,trigger_threshold,silent,0);
 }
 uint32_t DoAcquisition_config( bool silent)
 {
@@ -221,7 +221,12 @@ uint32_t DoAcquisition_config( bool silent)
                                  ,config.bits_per_sample
                                  ,config.averaging
                                  ,config.trigger_threshold
-                                 ,silent);
+                                 ,silent
+                                 ,0);
+}
+
+uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size) {
+       return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size);
 }
 
 uint32_t ReadLF(bool activeField, bool silent)
index ba4fc3f7fdc150174b52ebcdde38b8991f7b413a..cd774c155f007cef3a81d38216987b1b38b4f76f 100644 (file)
@@ -24,9 +24,11 @@ uint32_t SampleLF(bool silent);
 * Initializes the FPGA for snoop-mode (field off), and acquires the samples.
 * @return number of bits sampled
 **/
-
 uint32_t SnoopLF();
 
+// adds sample size to default options
+uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size);
+
 /**
  * @brief Does sample acquisition, ignoring the config values set in the sample_config.
  * This method is typically used by tag-specific readers who just wants to read the samples
index 9b9f2da92d2945879a74e483b5a4790bd8e212f0..c45a162da6b3a4b1800cef180e449338561e3ade 100644 (file)
@@ -22,6 +22,7 @@ command_t * CmdDataCommands();
 int CmdData(const char *Cmd);
 void printDemodBuff(void);
 void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx);
+int CmdPrintDemodBuff(const char *Cmd);
 int CmdAskEM410xDemod(const char *Cmd);
 int CmdVikingDemod(const char *Cmd);
 int CmdG_Prox_II_Demod(const char *Cmd);
index 34104518f9df43b3680cea1314968575c4c0f99d..206d5355807b2ad20515deb101e2e3dab8eb0e0d 100644 (file)
@@ -1078,9 +1078,29 @@ int CmdVchDemod(const char *Cmd)
        return 0;
 }
 
+
+//by marshmellow
+int CheckChipType(char cmdp) {
+       uint32_t wordData = 0;
+
+       //check for em4x05/em4x69 chips first
+       save_restoreGB(1);
+       if ((!offline && (cmdp != '1')) && EM4x05Block0Test(&wordData)) {
+               PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nTry lf em 4x05... commands\n");
+               save_restoreGB(0);
+               return 1;
+       }
+
+       //TODO check for t55xx chip...
+
+       save_restoreGB(0);
+       return 1;
+}
+
 //by marshmellow
 int CmdLFfind(const char *Cmd)
 {
+       uint32_t wordData = 0;
        int ans=0;
        size_t minLength = 1000;
        char cmdp = param_getchar(Cmd, 0);
@@ -1115,7 +1135,12 @@ int CmdLFfind(const char *Cmd)
        // only run if graphbuffer is just noise as it should be for hitag/cotag
        if (graphJustNoise(GraphBuffer, testLen)) {
                // only run these tests if we are in online mode 
-               if (!offline && (cmdp != '1')){
+               if (!offline && (cmdp != '1')) {
+                       // test for em4x05 in reader talk first mode.
+                       if (EM4x05Block0Test(&wordData)) {
+                               PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n");
+                               return 1;
+                       }
                        ans=CmdLFHitagReader("26");
                        if (ans==0) {
                                return 1;
@@ -1132,49 +1157,49 @@ int CmdLFfind(const char *Cmd)
        ans=CmdFSKdemodIO("");
        if (ans>0) {
                PrintAndLog("\nValid IO Prox ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdFSKdemodPyramid("");
        if (ans>0) {
                PrintAndLog("\nValid Pyramid ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdFSKdemodParadox("");
        if (ans>0) {
                PrintAndLog("\nValid Paradox ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdFSKdemodAWID("");
        if (ans>0) {
                PrintAndLog("\nValid AWID ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdFSKdemodHID("");
        if (ans>0) {
                PrintAndLog("\nValid HID Prox ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdAskEM410xDemod("");
        if (ans>0) {
                PrintAndLog("\nValid EM410x ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdG_Prox_II_Demod("");
        if (ans>0) {
                PrintAndLog("\nValid G Prox II ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdFDXBdemodBI("");
        if (ans>0) {
                PrintAndLog("\nValid FDX-B ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=EM4x50Read("", false);
@@ -1186,24 +1211,25 @@ int CmdLFfind(const char *Cmd)
        ans=CmdVikingDemod("");
        if (ans>0) {
                PrintAndLog("\nValid Viking ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }       
 
        ans=CmdIndalaDecode("");
        if (ans>0) {
                PrintAndLog("\nValid Indala ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        ans=CmdPSKNexWatch("");
        if (ans>0) {
                PrintAndLog("\nValid NexWatch ID Found!");
-               return 1;
+               return CheckChipType(cmdp);
        }
 
        PrintAndLog("\nNo Known Tags Found!\n");
        if (testRaw=='u' || testRaw=='U'){
-               //test unknown tag formats (raw mode)
+               ans=CheckChipType(cmdp);
+               //test unknown tag formats (raw mode)0
                PrintAndLog("\nChecking for Unknown tags:\n");
                ans=AutoCorrelate(4000, FALSE, FALSE);
                if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
@@ -1239,7 +1265,7 @@ static command_t CommandTable[] =
        {"help",        CmdHelp,            1, "This help"},
        {"awid",        CmdLFAWID,          1, "{ AWID RFIDs...    }"},
        {"cotag",       CmdLFCOTAG,         1, "{ COTAG RFIDs...   }"},
-       {"em4x",        CmdLFEM4X,          1, "{ EM4X RFIDs...    }"},
+       {"em",          CmdLFEM4X,          1, "{ EM4X RFIDs...    }"},
        {"hid",         CmdLFHID,           1, "{ HID RFIDs...     }"},
        {"hitag",       CmdLFHitag,         1, "{ Hitag tags and transponders... }"},
        {"io",          CmdLFIO,            1, "{ ioProx tags...   }"},
index 309f41180223cc80f04857c05167491b26bf1cea..1ace6bea23a0efb22db405842b1fda691a2c100f 100644 (file)
@@ -140,7 +140,7 @@ int CmdAWIDClone(const char *Cmd) {
        if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_awid_clone();
 
        if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q')
-               blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 50<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
+               blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | ((50-2)>>1)<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
 
        if ((fc & 0xFF) != fc) {
                fc &= 0xFF;
index aa0fc856e002b20e2c3e882341bff765b1d74416..0788b13852a2d17592382267403fda4efdd25703 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmdparser.h"
 #include "cmddata.h"
 #include "cmdlf.h"
+#include "cmdmain.h"
 #include "cmdlfem4x.h"
 #include "lfdemod.h"
 
@@ -71,9 +72,9 @@ int CmdEM410xSim(const char *Cmd)
        uint8_t uid[5] = {0x00};
 
        if (cmdp == 'h' || cmdp == 'H') {
-               PrintAndLog("Usage:  lf em4x em410xsim <UID> <clock>");
+               PrintAndLog("Usage:  lf em 410xsim <UID> <clock>");
                PrintAndLog("");
-               PrintAndLog("     sample: lf em4x em410xsim 0F0368568B");
+               PrintAndLog("     sample: lf em 410xsim 0F0368568B");
                return 0;
        }
        /* clock is 64 in EM410x tags */
@@ -227,6 +228,7 @@ int CmdEM410xWrite(const char *Cmd)
        return 0;
 }
 
+//**************** Start of EM4x50 Code ************************
 bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
 {
        if (rows*cols>size) return false;
@@ -285,7 +287,7 @@ uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool
        }
        return code;
 }
-/* Read the transmitted data of an EM4x50 tag
+/* Read the transmitted data of an EM4x50 tag from the graphbuffer
  * Format:
  *
  *  XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
@@ -498,116 +500,497 @@ int CmdEM4x50Read(const char *Cmd)
        return EM4x50Read(Cmd, true);
 }
 
-int CmdReadWord(const char *Cmd)
-{
-       int Word = -1; //default to invalid word
-       UsbCommand c;
-       
-       sscanf(Cmd, "%d", &Word);
-       
-       if ( (Word > 15) | (Word < 0) ) {
-               PrintAndLog("Word must be between 0 and 15");
-               return 1;
+//**************** 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;
        }
-       
-       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;
+       setGraphBuf(got, sizeof(got));
+       return true;
+}
+
+bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) {
+       // em4x05/em4x69 command response 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 or less if not a read command
+       size_t size = (readCmd) ? 20 : 11;
+       // sanity check
+       size = (size > DemodBufferLen) ? DemodBufferLen : size;
+       // 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);
-       return 0;
+       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 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 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("%s Address %02d | %08X", (addr>13) ? "Lock":" Got",addr,wordData);
+       else
+               PrintAndLog("Read Address %02d | failed",addr);
+
+       return success;
+}
+
+int CmdEM4x05ReadWord(const char *Cmd) {
+       uint8_t addr;
+       uint32_t pwd;
+       bool usePwd = false;
+       uint8_t ctmp = param_getchar(Cmd, 0);
+       if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_read();
+
+       addr = param_get8ex(Cmd, 0, 50, 10);
+       // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+       pwd =  param_get32ex(Cmd, 1, 1, 16);
        
-       if ( (Word > 15) | (Word < 0) ) {
-               PrintAndLog("Word must be between 0 and 15");
+       if ( (addr > 15) ) {
+               PrintAndLog("Address must be between 0 and 15");
                return 1;
        }
+       if ( pwd == 1 ) {
+               PrintAndLog("Reading address %02u", addr);
+       }       else {
+               usePwd = true;
+               PrintAndLog("Reading address %02u | password %08X", addr, pwd);
+       }
+
+       return EM4x05ReadWord(addr, pwd, usePwd);
+}
+
+int usage_lf_em_dump(void) {
+       PrintAndLog("Dump EM4x05/EM4x69.  Tag must be on antenna. ");
+       PrintAndLog("");
+       PrintAndLog("Usage:  lf em 4x05dump [h] <pwd>");
+       PrintAndLog("Options:");
+       PrintAndLog("       h         - this help");
+       PrintAndLog("       pwd       - password (hex) (optional)");
+       PrintAndLog("samples:");
+       PrintAndLog("      lf em 4x05dump");
+       PrintAndLog("      lf em 4x05dump 11223344");
+       return 0;
+}
+
+int CmdEM4x05dump(const char *Cmd) {
+       uint8_t addr = 0;
+       uint32_t pwd;
+       bool usePwd = false;
+       uint8_t ctmp = param_getchar(Cmd, 0);
+       if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
+
+       // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+       pwd = param_get32ex(Cmd, 0, 1, 16);
        
-       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);
+       if ( pwd != 1 ) {
+               usePwd = true;
+       }
+       int success = 1;
+       for (; addr < 16; addr++) {
+               if (addr == 2) {
+                       if (usePwd) {
+                               PrintAndLog(" PWD Address %02u | %08X",addr,pwd);
+                       } else {
+                               PrintAndLog(" PWD Address 02 | cannot read");
+                       }
+               } else {
+                       success &= EM4x05ReadWord(addr, pwd, usePwd);
+               }
+       }
+
+       return success;
+}
+
+
+int usage_lf_em_write(void) {
+       PrintAndLog("Write EM4x05/EM4x69.  Tag must be on antenna. ");
+       PrintAndLog("");
+       PrintAndLog("Usage:  lf em 4x05writeword [h] <address> <data> <pwd>");
+       PrintAndLog("Options:");
+       PrintAndLog("       h         - this help");
+       PrintAndLog("       address   - memory address to write to. (0-15)");
+       PrintAndLog("       data      - data to write (hex)");  
+       PrintAndLog("       pwd       - password (hex) (optional)");
+       PrintAndLog("samples:");
+       PrintAndLog("      lf em 4x05writeword 1");
+       PrintAndLog("      lf em 4x05writeword 1 deadc0de 11223344");
        return 0;
 }
 
-int CmdWriteWord(const char *Cmd)
-{
-       int Word = 16; //default to invalid block
-       int Data = 0xFFFFFFFF; //default to blank data
-       UsbCommand c;
+int CmdEM4x05WriteWord(const char *Cmd) {
+       uint8_t ctmp = param_getchar(Cmd, 0);
+       if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write();
        
-       sscanf(Cmd, "%x %d", &Data, &Word);
+       bool usePwd = false;
+               
+       uint8_t addr = 16; // default to invalid address
+       uint32_t data = 0xFFFFFFFF; // default to blank data
+       uint32_t pwd = 0xFFFFFFFF; // default to blank password
+       
+       addr = param_get8ex(Cmd, 0, 16, 10);
+       data = param_get32ex(Cmd, 1, 0, 16);
+       pwd =  param_get32ex(Cmd, 2, 1, 16);
        
-       if (Word > 15) {
-               PrintAndLog("Word must be between 0 and 15");
+       
+       if ( (addr > 15) ) {
+               PrintAndLog("Address must be between 0 and 15");
                return 1;
        }
+       if ( pwd == 1 )
+               PrintAndLog("Writing address %d data %08X", addr, data);        
+       else {
+               usePwd = true;
+               PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);               
+       }
        
-       PrintAndLog("Writing word %d with data %08X", Word, Data);
+       uint16_t flag = (addr << 8 ) | usePwd;
        
-       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;
+       UsbCommand c = {CMD_EM4X_WRITE_WORD, {flag, data, pwd}};
+       clearCommandBuffer();
        SendCommand(&c);
-       return 0;
+       UsbCommand resp;        
+       if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
+               PrintAndLog("Error occurred, device did not respond during write operation.");
+               return -1;
+       }
+       if ( !downloadSamplesEM() ) {
+               return -1;
+       }
+       //check response for 00001010 for write confirmation!   
+       //attempt demod:
+       uint32_t dummy = 0;
+       int result = demodEM4x05resp(&dummy,false);
+       if (result == 1) {
+               PrintAndLog("Write Verified");
+       } else {
+               PrintAndLog("Write could not be verified");
+       }
+       return result;
 }
 
-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);
+void printEM4x05config(uint32_t wordData) {
+       uint16_t datarate = (((wordData & 0x3F)+1)*2);
+       uint8_t encoder = ((wordData >> 6) & 0xF);
+       char enc[14];
+       memset(enc,0,sizeof(enc));
+
+       uint8_t PSKcf = (wordData >> 10) & 0x3;
+       char cf[10];
+       memset(cf,0,sizeof(cf));
+       uint8_t delay = (wordData >> 12) & 0x3;
+       char cdelay[33];
+       memset(cdelay,0,sizeof(cdelay));
+       uint8_t LWR = (wordData >> 14) & 0xF; //last word read
+
+       switch (encoder) {
+               case 0: snprintf(enc,sizeof(enc),"NRZ"); break;
+               case 1: snprintf(enc,sizeof(enc),"Manchester"); break;
+               case 2: snprintf(enc,sizeof(enc),"Biphase"); break;
+               case 3: snprintf(enc,sizeof(enc),"Miller"); break;
+               case 4: snprintf(enc,sizeof(enc),"PSK1"); break;
+               case 5: snprintf(enc,sizeof(enc),"PSK2"); break;
+               case 6: snprintf(enc,sizeof(enc),"PSK3"); break;
+               case 7: snprintf(enc,sizeof(enc),"Unknown"); break;
+               case 8: snprintf(enc,sizeof(enc),"FSK1"); break;
+               case 9: snprintf(enc,sizeof(enc),"FSK2"); break;
+               default: snprintf(enc,sizeof(enc),"Unknown"); break;
+       }
+
+       switch (PSKcf) {
+               case 0: snprintf(cf,sizeof(cf),"RF/2"); break;
+               case 1: snprintf(cf,sizeof(cf),"RF/8"); break;
+               case 2: snprintf(cf,sizeof(cf),"RF/4"); break;
+               case 3: snprintf(cf,sizeof(cf),"unknown"); break;
+       }
+
+       switch (delay) {
+               case 0: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
+               case 1: snprintf(cdelay, sizeof(cdelay),"BP/8 or 1/8th bit period delay"); break;
+               case 2: snprintf(cdelay, sizeof(cdelay),"BP/4 or 1/4th bit period delay"); break;
+               case 3: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
+       }
+       PrintAndLog("ConfigWord: %08X (Word 4)\n", wordData);
+       PrintAndLog("Config Breakdown:", wordData);
+       PrintAndLog(" Data Rate:  %02u | RF/%u", wordData & 0x3F, datarate);
+       PrintAndLog("   Encoder:   %u | %s", encoder, enc);
+       PrintAndLog("    PSK CF:   %u | %s", PSKcf, cf);
+       PrintAndLog("     Delay:   %u | %s", delay, cdelay);
+       PrintAndLog(" LastWordR:  %02u | Address of last word for default read", LWR);
+       PrintAndLog(" ReadLogin:   %u | Read Login is %s", (wordData & 0x40000)>>18, (wordData & 0x40000) ? "Required" : "Not Required");       
+       PrintAndLog("   ReadHKL:   %u | Read Housekeeping Words Login is %s", (wordData & 0x80000)>>19, (wordData & 0x80000) ? "Required" : "Not Required");    
+       PrintAndLog("WriteLogin:   %u | Write Login is %s", (wordData & 0x100000)>>20, (wordData & 0x100000) ? "Required" : "Not Required");    
+       PrintAndLog("  WriteHKL:   %u | Write Housekeeping Words Login is %s", (wordData & 0x200000)>>21, (wordData & 0x200000) ? "Required" : "Not Required"); 
+       PrintAndLog("    R.A.W.:   %u | Read After Write is %s", (wordData & 0x400000)>>22, (wordData & 0x400000) ? "On" : "Off");
+       PrintAndLog("   Disable:   %u | Disable Command is %s", (wordData & 0x800000)>>23, (wordData & 0x800000) ? "Accepted" : "Not Accepted");
+       PrintAndLog("    R.T.F.:   %u | Reader Talk First is %s", (wordData & 0x1000000)>>24, (wordData & 0x1000000) ? "Enabled" : "Disabled");
+       PrintAndLog("    Pigeon:   %u | Pigeon Mode is %s\n", (wordData & 0x4000000)>>26, (wordData & 0x4000000) ? "Enabled" : "Disabled");
+}
+
+void printEM4x05info(uint8_t chipType, uint8_t cap, uint16_t custCode, uint32_t serial) {
+       switch (chipType) {
+               case 9: PrintAndLog("\n Chip Type:   %u | EM4305", chipType); break;
+               case 4: PrintAndLog(" Chip Type:   %u | Unknown", chipType); break;
+               case 2: PrintAndLog(" Chip Type:   %u | EM4469", chipType); break;
+               //add more here when known
+               default: PrintAndLog(" Chip Type:   %u Unknown", chipType); break;
+       }
+
+       switch (cap) {
+               case 3: PrintAndLog("  Cap Type:   %u | 330pF",cap); break;
+               case 2: PrintAndLog("  Cap Type:   %u | %spF",cap, (chipType==2)? "75":"210"); break;
+               case 1: PrintAndLog("  Cap Type:   %u | 250pF",cap); break;
+               case 0: PrintAndLog("  Cap Type:   %u | no resonant capacitor",cap); break;
+               default: PrintAndLog("  Cap Type:   %u | unknown",cap); break;
+       }
+
+       PrintAndLog(" Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default": "Unknown");
+       if (serial != 0) {
+               PrintAndLog("\n  Serial #: %08X\n", serial);
+       }
+}
+
+void printEM4x05ProtectionBits(uint32_t wordData) {
+       for (uint8_t i = 0; i < 15; i++) {
+               PrintAndLog("      Word:  %02u | %s", i, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
+               if (i==14) {
+                       PrintAndLog("      Word:  %02u | %s", i+1, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
+               }
+       }
+}
+
+//quick test for EM4x05/EM4x69 tag
+bool EM4x05Block0Test(uint32_t *wordData) {
+       if (EM4x05ReadWord_ext(0,0,false,wordData) == 1) {
+               return true;
+       }
+       return false;
+}
+
+int CmdEM4x05info(const char *Cmd) {
+       //uint8_t addr = 0;
+       uint32_t pwd;
+       uint32_t wordData = 0;
+       bool usePwd = false;
+       uint8_t ctmp = param_getchar(Cmd, 0);
+       if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
+
+       // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
+       pwd = param_get32ex(Cmd, 0, 1, 16);
        
-       if (Word > 15) {
-               PrintAndLog("Word must be between 0 and 15");
-               return 1;
+       if ( pwd != 1 ) {
+               usePwd = true;
        }
+
+       // read word 0 (chip info)
+       // block 0 can be read even without a password.
+       if ( !EM4x05Block0Test(&wordData) ) 
+               return -1;
        
-       PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
+       uint8_t chipType = (wordData >> 1) & 0xF;
+       uint8_t cap = (wordData >> 5) & 3;
+       uint16_t custCode = (wordData >> 9) & 0x3FF;
        
-       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;
+       // read word 1 (serial #) doesn't need pwd
+       wordData = 0;
+       if (EM4x05ReadWord_ext(1, 0, false, &wordData) != 1) {
+               //failed, but continue anyway...
+       }
+       printEM4x05info(chipType, cap, custCode, wordData);
+
+       // read word 4 (config block) 
+       // needs password if one is set
+       wordData = 0;
+       if ( EM4x05ReadWord_ext(4, pwd, usePwd, &wordData) != 1 ) {
+               //failed
+               return 0;
+       }
+       printEM4x05config(wordData);
+
+       // read word 14 and 15 to see which is being used for the protection bits
+       wordData = 0;
+       if ( EM4x05ReadWord_ext(14, pwd, usePwd, &wordData) != 1 ) {
+               //failed
+               return 0;
+       }
+       // if status bit says this is not the used protection word
+       if (!(wordData & 0x8000)) {
+               if ( EM4x05ReadWord_ext(15, pwd, usePwd, &wordData) != 1 ) {
+                       //failed
+                       return 0;
+               }
+       }
+       if (!(wordData & 0x8000)) {
+               //something went wrong
+               return 0;
+       }
+       printEM4x05ProtectionBits(wordData);
+
+       return 1;
 }
 
+
 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 in GraphBuffer"},
-       {"em410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- 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, 0, "<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"},
+       {"410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},  
+       {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
+       {"410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
+       {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
+       {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
+       {"410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
+       {"4x05dump", CmdEM4x05dump, 0, "(pwd) -- Read EM4x05/EM4x69 all word data"},
+       {"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"},
+       {"4x05readword", CmdEM4x05ReadWord, 0, "<Word> (pwd) -- Read EM4x05/EM4x69 word data"},
+       {"4x05writeword", CmdEM4x05WriteWord, 0, "<Word> <data> (pwd) -- Write EM4x05/EM4x69 word data"},
+       {"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"},
        {NULL, NULL, 0, NULL}
 };
 
index 400536d30b117a85071af7f035e9ffa0ff6e6921..7faf6f49f4c7892cf9c5e0383e0bd625c72cafef 100644 (file)
@@ -18,11 +18,14 @@ int CmdEM410xWatch(const char *Cmd);
 int CmdEM410xWatchnSpoof(const char *Cmd);
 int CmdEM410xWrite(const char *Cmd);
 int CmdEM4x50Read(const char *Cmd);
-int CmdLFEM4X(const char *Cmd);
-int CmdReadWord(const char *Cmd);
-int CmdReadWordPWD(const char *Cmd);
-int CmdWriteWord(const char *Cmd);
-int CmdWriteWordPWD(const char *Cmd);
 int EM4x50Read(const char *Cmd, bool verbose);
+int CmdLFEM4X(const char *Cmd);
+bool EM4x05Block0Test(uint32_t *wordData);
+int CmdEM4x05info(const char *Cmd);
+int CmdEM4x05WriteWord(const char *Cmd);
+int CmdEM4x05dump(const char *Cmd);
+int CmdEM4x05ReadWord(const char *Cmd);
+int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData);
+
 
 #endif
index abae165d20dc58036a61c0792c0556db6d8cf2d4..c6dbd7561f42a6ed307ab4ff36e74182be63ad6b 100644 (file)
@@ -178,7 +178,7 @@ int CmdPrescoClone(const char *Cmd) {
        if (GetWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == -1) return usage_lf_presco_clone();
 
        if (Q5)
-               blocks[0] = T5555_MODULATION_MANCHESTER | 32<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
+               blocks[0] = T5555_MODULATION_MANCHESTER | ((32-2)>>1)<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
 
        if ((sitecode & 0xFF) != sitecode) {
                sitecode &= 0xFF;
index d216a8f20abdd5b557d0058675dd2c114de3d837..f40f093a38f4996f21e1b02f3393488932bfb59f 100644 (file)
@@ -14,6 +14,7 @@
 #include "ui.h"
 #include "graph.h"
 #include "lfdemod.h"
+#include "cmddata.h" //for g_debugmode
 
 int GraphBuffer[MAX_GRAPH_TRACE_LEN];
 int GraphTraceLen;
@@ -255,7 +256,7 @@ uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose)
        if (size==0) return 0;
        uint16_t ans = countFC(BitStream, size, 1); 
        if (ans==0) {
-               if (verbose) PrintAndLog("DEBUG: No data found");
+               if (verbose || g_debugMode) PrintAndLog("DEBUG: No data found");
                return 0;
        }
        *fc1 = (ans >> 8) & 0xFF;
@@ -263,7 +264,7 @@ uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose)
 
        *rf1 = detectFSKClk(BitStream, size, *fc1, *fc2);
        if (*rf1==0) {
-               if (verbose) PrintAndLog("DEBUG: Clock detect error");
+               if (verbose || g_debugMode) PrintAndLog("DEBUG: Clock detect error");
                return 0;
        }
        return 1;
index e4add6c09e0112390ce332f2d7052ea56899973c..374ae397a3415d9b8c916cc3573357c36193e89c 100644 (file)
@@ -110,6 +110,23 @@ void print_hex(const uint8_t * data, const size_t len)
        printf("\n");
 }
 
+void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
+
+       int rownum = 0;
+       printf("[%02d] | ", rownum);
+       for (int i = 0; i < len; ++i) {
+
+               printf("%02X ", data[i]);
+               
+               // check if a line break is needed
+               if ( breaks > 0 && !((i+1) % breaks) && (i+1 < len) ) {
+                       ++rownum;
+                       printf("\n[%02d] | ", rownum);
+               }
+       }
+       printf("\n");
+}
+
 char *sprint_hex(const uint8_t *data, const size_t len) {
        
        int maxLen = ( len > 1024/3) ? 1024/3 : len;
@@ -139,7 +156,7 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea
 
        size_t in_index = 0;
        // loop through the out_index to make sure we don't go too far
-       for (size_t out_index=0; out_index < max_len; out_index++) {
+       for (size_t out_index=0; out_index < max_len-1; out_index++) {
                // set character - (should be binary but verify it isn't more than 1 digit)
                if (data[in_index]<10)
                        sprintf(tmp++, "%u", (unsigned int) data[in_index]);
@@ -158,6 +175,41 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea
 char *sprint_bin(const uint8_t *data, const size_t len) {
        return sprint_bin_break(data, len, 0);
 }
+
+char *sprint_hex_ascii(const uint8_t *data, const size_t len) {
+       static char buf[1024];
+       char *tmp = buf;
+       memset(buf, 0x00, 1024);
+       size_t max_len = (len > 1010) ? 1010 : len;
+
+       sprintf(tmp, "%s| ", sprint_hex(data, max_len) );
+       
+       size_t i = 0;
+       size_t pos = (max_len * 3)+2;
+       while(i < max_len){
+               char c = data[i];
+               if ( (c < 32) || (c == 127))
+                       c = '.';
+               sprintf(tmp+pos+i, "%c",  c);
+               ++i;
+       }
+       return buf;
+}
+
+char *sprint_ascii(const uint8_t *data, const size_t len) {
+       static char buf[1024];
+       char *tmp = buf;
+       memset(buf, 0x00, 1024);
+       size_t max_len = (len > 1010) ? 1010 : len;
+       size_t i = 0;
+       while(i < max_len){
+               char c = data[i];
+               tmp[i] = ((c < 32) || (c == 127)) ? '.' : c;
+               ++i;
+       }
+       return buf;
+}
+
 void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
 {
        while (len--) {
@@ -184,6 +236,15 @@ void num_to_bytebits(uint64_t      n, size_t len, uint8_t *dest) {
        }
 }
 
+//least significant bit first
+void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
+       for(int i = 0 ; i < len ; ++i) {
+               dest[i] =  n & 1;
+               n >>= 1;
+       }
+}
+
+
 // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
 // to
 // hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
@@ -200,6 +261,16 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS
        return tmp;
 }
 
+// takes a uint8_t src array, for len items and reverses the byte order in blocksizes (8,16,32,64), 
+// returns: the dest array contains the reordered src array.
+void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest){
+       for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
+               for (size_t i = 0; i < blockSize; i++){
+                       dest[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)];
+               }
+       }
+}
+
 //assumes little endian
 char * printBits(size_t const size, void const * const ptr)
 {
@@ -332,8 +403,6 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base)
                return strtoull(&line[bg], NULL, base);
        else
                return deflt;
-
-       return 0;
 }
 
 int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt)
@@ -490,6 +559,7 @@ void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length)
     *(target)= GetParity(source + length / 2, ODD, length / 2);
 }
 
+// xor two arrays together for len items.  The dst array contains the new xored values.
 void xor(unsigned char *dst, unsigned char *src, size_t len) {
    for( ; len > 0; len--,dst++,src++)
        *dst ^= *src;
index 1b6b2fb1d1435e5702b89f5dc861df111711c8aa..8c0ed950db3f38df1600aad2ca281fa3ad876148 100644 (file)
@@ -13,7 +13,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-#include <time.h>
+#include <time.h>    //time, gmtime
 #include "data.h"    //for FILE_PATH_SIZE
 
 #ifndef ROTR
@@ -42,12 +42,16 @@ void print_hex(const uint8_t * data, const size_t len);
 char * sprint_hex(const uint8_t * data, const size_t len);
 char * sprint_bin(const uint8_t * data, const size_t len);
 char * sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
+char * sprint_hex_ascii(const uint8_t *data, const size_t len);
+char * sprint_ascii(const uint8_t *data, const size_t len);
 
 void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
 uint64_t bytes_to_num(uint8_t* src, size_t len);
 void num_to_bytebits(uint64_t  n, size_t len, uint8_t *dest);
+void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
 char * printBits(size_t const size, void const * const ptr);
 uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
+void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
 
 char param_getchar(const char *line, int paramnum);
 int param_getptr(const char *line, int *bg, int *en, int paramnum);
index 8324c440f4c19f918159215ff6dc94b397596f80..e9f19311c8b6c248d0ffcdabd1b4e1bc3c04f1c9 100644 (file)
@@ -62,7 +62,7 @@ uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType)
        for (uint8_t i = 0; i < bitLen; i++){
                ans ^= ((bits >> i) & 1);
        }
-       //PrintAndLog("DEBUG: ans: %d, ptype: %d",ans,pType);
+       if (g_debugMode) prnt("DEBUG: ans: %d, ptype: %d, bits: %08X",ans,pType,bits);
        return (ans == pType);
 }
 
@@ -73,11 +73,13 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p
 {
        uint32_t parityWd = 0;
        size_t j = 0, bitCnt = 0;
-       for (int word = 0; word < (bLen); word+=pLen){
-               for (int bit=0; bit < pLen; bit++){
+       for (int word = 0; word < (bLen); word+=pLen) {
+               for (int bit=0; bit < pLen; bit++) {
                        parityWd = (parityWd << 1) | BitStream[startIdx+word+bit];
                        BitStream[j++] = (BitStream[startIdx+word+bit]);
                }
+               if (word+pLen >= bLen) break;
+
                j--; // overwrite parity with next data
                // if parity fails then return 0
                switch (pType) {
@@ -148,6 +150,9 @@ uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits)
 //search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length
 uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx)
 {
+       // Sanity check.  If preamble length is bigger than bitstream length.
+       if ( *size <= pLen ) return 0;
+
        uint8_t foundCnt=0;
        for (int idx=0; idx < *size - pLen; idx++){
                if (memcmp(BitStream+idx, preamble, pLen) == 0){
@@ -165,6 +170,49 @@ uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_
        return 0;
 }
 
+// search for given preamble in given BitStream and return success=1 or fail=0 and startIndex (where it was found)
+// does not look for a repeating preamble
+// em4x05/4x69 only sends preamble once, so look for it once in the first pLen bits
+// leave it generic so it could be reused later...
+bool onePreambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t size, size_t *startIdx) {
+       // Sanity check.  If preamble length is bigger than bitstream length.
+       if ( size <= pLen ) return false;
+       for (size_t idx = 0; idx < size - pLen; idx++) {
+               if (memcmp(BitStream+idx, preamble, pLen) == 0) {
+                       if (g_debugMode) prnt("DEBUG: preamble found at %u", idx);
+                       *startIdx = idx;
+                       return true;
+               }
+       }
+       return false;
+}
+
+// find start of modulating data (for fsk and psk) in case of beginning noise or slow chip startup.
+size_t findModStart(uint8_t dest[], size_t size, uint8_t threshold_value, uint8_t expWaveSize) {
+       size_t i = 0;
+       size_t waveSizeCnt = 0;
+       uint8_t thresholdCnt = 0;
+       bool isAboveThreshold = dest[i++] >= threshold_value;
+       for (; i < size-20; i++ ) {
+               if(dest[i] < threshold_value && isAboveThreshold) {
+                       thresholdCnt++;
+                       if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;                     
+                       isAboveThreshold = false;
+                       waveSizeCnt = 0;
+               } else if (dest[i] >= threshold_value && !isAboveThreshold) {
+                       thresholdCnt++;
+                       if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;                     
+                       isAboveThreshold = true;
+                       waveSizeCnt = 0;
+               } else {
+                       waveSizeCnt++;
+               }
+               if (thresholdCnt > 10) break;
+       }
+       if (g_debugMode == 2) prnt("DEBUG: threshold Count reached at %u, count: %u",i, thresholdCnt);
+       return i;
+}
+
 //by marshmellow
 //takes 1s and 0s and searches for EM410x format - output EM ID
 uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo)
@@ -474,7 +522,6 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
 {
        size_t last_transition = 0;
        size_t idx = 1;
-       //uint32_t maxVal=0;
        if (fchigh==0) fchigh=10;
        if (fclow==0) fclow=8;
        //set the threshold close to 0 (graph) or 128 std to avoid static
@@ -482,19 +529,22 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
        size_t preLastSample = 0;
        size_t LastSample = 0;
        size_t currSample = 0;
-       // sync to first lo-hi transition, and threshold
+       if ( size < 1024 ) return 0; // not enough samples
+
+       //find start of modulating data in trace 
+       idx = findModStart(dest, size, threshold_value, fchigh);
 
        // Need to threshold first sample
-       // skip 160 samples to allow antenna/samples to settle
-       if(dest[160] < threshold_value) dest[0] = 0;
+       if(dest[idx] < threshold_value) dest[0] = 0;
        else dest[0] = 1;
-
+       idx++;
+       
        size_t numBits = 0;
        // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
        // or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere
        // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
        //  (could also be fc/5 && fc/7 for fsk1 = 4-9)
-       for(idx = 161; idx < size-20; idx++) {
+       for(; idx < size-20; idx++) {
                // threshold current value
 
                if (dest[idx] < threshold_value) dest[idx] = 0;
@@ -509,13 +559,14 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
                                //do nothing with extra garbage
                        } else if (currSample < (fchigh-1)) {           //6-8 = 8 sample waves  (or 3-6 = 5)
                                //correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5)
-                               if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample     == 0 )){
+                               if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1))){
                                        dest[numBits-1]=1;
                                }
                                dest[numBits++]=1;
 
-                       } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage 
-                               //do nothing with beginning garbage
+                       } else if (currSample > (fchigh+1) && numBits < 3) { //12 + and first two bit = unusable garbage
+                               //do nothing with beginning garbage and reset..  should be rare..
+                               numBits = 0; 
                        } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's)
                                dest[numBits++]=1;
                        } else {                                        //9+ = 10 sample waves (or 6+ = 7)
@@ -1292,7 +1343,10 @@ uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fc
                        continue;               
                // else new peak 
                // if we got less than the small fc + tolerance then set it to the small fc
-               if (fcCounter < fcLow+fcTol) 
+               // if it is inbetween set it to the last counter
+               if (fcCounter < fcHigh && fcCounter > fcLow)
+                       fcCounter = lastFCcnt;
+               else if (fcCounter < fcLow+fcTol) 
                        fcCounter = fcLow;
                else //set it to the large fc
                        fcCounter = fcHigh;
@@ -1358,7 +1412,7 @@ uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fc
                }
        }
 
-       if (ii<0) return 0; // oops we went too far
+       if (ii<2) return 0; // oops we went too far
 
        return clk[ii];
 }
@@ -1372,10 +1426,10 @@ uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj)
        uint8_t fcLens[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        uint16_t fcCnts[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        uint8_t fcLensFnd = 0;
-       uint8_t lastFCcnt=0;
+       uint8_t lastFCcnt = 0;
        uint8_t fcCounter = 0;
        size_t i;
-       if (size == 0) return 0;
+       if (size < 180) return 0;
 
        // prime i to first up transition
        for (i = 160; i < size-20; i++)
@@ -1462,27 +1516,37 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
 
        size_t numBits=0;
        uint8_t curPhase = *invert;
-       size_t i, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
-       uint8_t fc=0, fullWaveLen=0, tol=1;
-       uint16_t errCnt=0, waveLenCnt=0;
-       fc = countFC(dest, *size, 0);
+       size_t i=0, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
+       uint16_t fc=0, fullWaveLen=0, tol=1;
+       uint16_t errCnt=0, waveLenCnt=0, errCnt2=0;
+       fc = countFC(dest, *size, 1);
+       uint8_t fc2 = fc >> 8;
+       if (fc2 == 10) return -1; //fsk found - quit
+       fc = fc & 0xFF;
        if (fc!=2 && fc!=4 && fc!=8) return -1;
        //PrintAndLog("DEBUG: FC: %d",fc);
        *clock = DetectPSKClock(dest, *size, *clock);
        if (*clock == 0) return -1;
-       int avgWaveVal=0, lastAvgWaveVal=0;
+
+       //find start of modulating data in trace 
+       uint8_t threshold_value = 123; //-5
+       i = findModStart(dest, *size, threshold_value, fc);
+
        //find first phase shift
-       for (i=0; i<loopCnt; i++){
+       int avgWaveVal=0, lastAvgWaveVal=0;
+       waveStart = i;
+       for (; i<loopCnt; i++) {
+               // find peak 
                if (dest[i]+fc < dest[i+1] && dest[i+1] >= dest[i+2]){
                        waveEnd = i+1;
-                       //PrintAndLog("DEBUG: waveEnd: %d",waveEnd);
+                       if (g_debugMode == 2) prnt("DEBUG PSK: waveEnd: %u, waveStart: %u",waveEnd, waveStart);
                        waveLenCnt = waveEnd-waveStart;
-                       if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+2)){ //not first peak and is a large wave but not out of whack
+                       if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+3)){ //not first peak and is a large wave but not out of whack
                                lastAvgWaveVal = avgWaveVal/(waveLenCnt);
                                firstFullWave = waveStart;
                                fullWaveLen=waveLenCnt;
-                               //if average wave value is > graph 0 then it is an up wave or a 1
-                               if (lastAvgWaveVal > 123) curPhase ^= 1;  //fudge graph 0 a little 123 vs 128
+                               //if average wave value is > graph 0 then it is an up wave or a 1 (could cause inverting)
+                               if (lastAvgWaveVal > threshold_value) curPhase ^= 1;
                                break;
                        } 
                        waveStart = i+1;
@@ -1503,7 +1567,7 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
        //set start of wave as clock align
        lastClkBit = firstFullWave;
        if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen);  
-       if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
+       if (g_debugMode==2) prnt("DEBUG PSK: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
        waveStart = 0;
        dest[numBits++] = curPhase; //set first read bit
        for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){
@@ -1534,6 +1598,9 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
                                } else if (i+1 > lastClkBit + *clock + tol + fc){
                                        lastClkBit += *clock; //no phase shift but clock bit
                                        dest[numBits++] = curPhase;
+                               } else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often)
+                                       errCnt2++;
+                                       if(errCnt2 > 101) return errCnt2;
                                }
                                avgWaveVal = 0;
                                waveStart = i+1;
index b988c1bf6d6ab0a81ac0b47ae8ae48fa363d4416..9c5c83fbf42d27b1c624ea136f56594632ddbc2b 100644 (file)
@@ -39,6 +39,7 @@ int      manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert);
 int      nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert);
 uint8_t  parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType);
 uint8_t  preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx);
+bool     onePreambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t size, size_t *startIdx);
 int      pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert);
 void     psk2TOpsk1(uint8_t *BitStream, size_t size);
 void     psk1TOpsk2(uint8_t *BitStream, size_t size);
Impressum, Datenschutz