mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-19 04:49:38 -07:00
Merge pull request #216 from marshmellow42/master
EM4x05/EM4x69 command rewrite and improvements
This commit is contained in:
commit
2d0717853d
17 changed files with 748 additions and 184 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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... }"},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
//**************** 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;
|
||||
}
|
||||
|
||||
int CmdReadWordPWD(const char *Cmd)
|
||||
{
|
||||
int Word = -1; //default to invalid word
|
||||
int Password = 0xFFFFFFFF; //default to blank password
|
||||
UsbCommand c;
|
||||
// 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 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);
|
||||
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("%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);
|
||||
|
||||
sscanf(Cmd, "%d %x", &Word, &Password);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 ) {
|
||||
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 CmdWriteWord(const char *Cmd)
|
||||
{
|
||||
int Word = 16; //default to invalid block
|
||||
int Data = 0xFFFFFFFF; //default to blank data
|
||||
UsbCommand c;
|
||||
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);
|
||||
|
||||
sscanf(Cmd, "%x %d", &Data, &Word);
|
||||
|
||||
if (Word > 15) {
|
||||
PrintAndLog("Word must be between 0 and 15");
|
||||
return 1;
|
||||
if ( pwd != 1 ) {
|
||||
usePwd = true;
|
||||
}
|
||||
|
||||
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);
|
||||
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 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;
|
||||
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 %x", &Data, &Word, &Password);
|
||||
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
|
||||
|
||||
if (Word > 15) {
|
||||
PrintAndLog("Word must be between 0 and 15");
|
||||
addr = param_get8ex(Cmd, 0, 16, 10);
|
||||
data = param_get32ex(Cmd, 1, 0, 16);
|
||||
pwd = param_get32ex(Cmd, 2, 1, 16);
|
||||
|
||||
|
||||
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 and password %08X", Word, Data, Password);
|
||||
uint16_t flag = (addr << 8 ) | usePwd;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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 ( pwd != 1 ) {
|
||||
usePwd = true;
|
||||
}
|
||||
|
||||
// read word 0 (chip info)
|
||||
// block 0 can be read even without a password.
|
||||
if ( !EM4x05Block0Test(&wordData) )
|
||||
return -1;
|
||||
|
||||
uint8_t chipType = (wordData >> 1) & 0xF;
|
||||
uint8_t cap = (wordData >> 5) & 3;
|
||||
uint16_t custCode = (wordData >> 9) & 0x3FF;
|
||||
|
||||
// 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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
121
common/lfdemod.c
121
common/lfdemod.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue