mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-21 13:53:26 -07:00
Merge pull request #54 from Proxmark/lf_recorder
LF: Ability to do longer traces/snoops
This commit is contained in:
commit
1f78a4d305
12 changed files with 650 additions and 174 deletions
110
client/cmddata.c
110
client/cmddata.c
|
@ -21,6 +21,8 @@
|
|||
#include "cmdmain.h"
|
||||
#include "cmddata.h"
|
||||
#include "lfdemod.h"
|
||||
#include "usb_cmd.h"
|
||||
|
||||
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||
uint8_t g_debugMode;
|
||||
int DemodBufferLen;
|
||||
|
@ -569,6 +571,43 @@ int CmdDec(const char *Cmd)
|
|||
RepaintGraphWindow();
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Undecimate - I'd call it 'interpolate', but we'll save that
|
||||
* name until someone does an actual interpolation command, not just
|
||||
* blindly repeating samples
|
||||
* @param Cmd
|
||||
* @return
|
||||
*/
|
||||
int CmdUndec(const char *Cmd)
|
||||
{
|
||||
if(param_getchar(Cmd, 0) == 'h')
|
||||
{
|
||||
PrintAndLog("Usage: data undec [factor]");
|
||||
PrintAndLog("This function performs un-decimation, by repeating each sample N times");
|
||||
PrintAndLog("Options: ");
|
||||
PrintAndLog(" h This help");
|
||||
PrintAndLog(" factor The number of times to repeat each sample.[default:2]");
|
||||
PrintAndLog("Example: 'data undec 3'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t factor = param_get8ex(Cmd, 0,2, 10);
|
||||
//We have memory, don't we?
|
||||
int swap[MAX_GRAPH_TRACE_LEN] = { 0 };
|
||||
uint32_t g_index = 0 ,s_index = 0;
|
||||
while(g_index < GraphTraceLen && s_index < MAX_GRAPH_TRACE_LEN)
|
||||
{
|
||||
int count = 0;
|
||||
for(count = 0; count < factor && s_index+count < MAX_GRAPH_TRACE_LEN; count ++)
|
||||
swap[s_index+count] = GraphBuffer[g_index];
|
||||
s_index+=count;
|
||||
}
|
||||
|
||||
memcpy(GraphBuffer,swap, s_index * sizeof(int));
|
||||
GraphTraceLen = s_index;
|
||||
RepaintGraphWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//shift graph zero up or down based on input + or -
|
||||
|
@ -1491,25 +1530,79 @@ int CmdHpf(const char *Cmd)
|
|||
RepaintGraphWindow();
|
||||
return 0;
|
||||
}
|
||||
typedef struct {
|
||||
uint8_t * buffer;
|
||||
uint32_t numbits;
|
||||
uint32_t position;
|
||||
}BitstreamOut;
|
||||
|
||||
bool _headBit( BitstreamOut *stream)
|
||||
{
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = (stream->position++) & 7; // mask out 00000111
|
||||
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
|
||||
}
|
||||
|
||||
uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b)
|
||||
{
|
||||
int i;
|
||||
uint8_t val = 0;
|
||||
for(i =0 ; i < bits_per_sample; i++)
|
||||
{
|
||||
val |= (_headBit(b) << (7-i));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int CmdSamples(const char *Cmd)
|
||||
{
|
||||
uint8_t got[BIGBUF_SIZE] = {0x00};
|
||||
//If we get all but the last byte in bigbuf,
|
||||
// we don't have to worry about remaining trash
|
||||
// in the last byte in case the bits-per-sample
|
||||
// does not line up on byte boundaries
|
||||
uint8_t got[BIGBUF_SIZE-1] = { 0 };
|
||||
|
||||
int n = strtol(Cmd, NULL, 0);
|
||||
if (n == 0)
|
||||
n = 20000;
|
||||
n = sizeof(got);
|
||||
|
||||
if (n > sizeof(got))
|
||||
n = sizeof(got);
|
||||
|
||||
PrintAndLog("Reading %d samples from device memory\n", n);
|
||||
PrintAndLog("Reading %d bytes from device memory\n", n);
|
||||
GetFromBigBuf(got,n,0);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
for (int j = 0; j < n; j++) {
|
||||
GraphBuffer[j] = ((int)got[j]) - 128;
|
||||
PrintAndLog("Data fetched");
|
||||
UsbCommand response;
|
||||
WaitForResponse(CMD_ACK, &response);
|
||||
uint8_t bits_per_sample = 8;
|
||||
|
||||
//Old devices without this feature would send 0 at arg[0]
|
||||
if(response.arg[0] > 0)
|
||||
{
|
||||
sample_config *sc = (sample_config *) response.d.asBytes;
|
||||
PrintAndLog("Samples @ %d bits/smpl, decimation 1:%d ", sc->bits_per_sample
|
||||
, sc->decimation);
|
||||
bits_per_sample = sc->bits_per_sample;
|
||||
}
|
||||
GraphTraceLen = n;
|
||||
if(bits_per_sample < 8)
|
||||
{
|
||||
PrintAndLog("Unpacking...");
|
||||
BitstreamOut bout = { got, bits_per_sample * n, 0};
|
||||
int j =0;
|
||||
for (j = 0; j * bits_per_sample < n * 8 && j < sizeof(GraphBuffer); j++) {
|
||||
uint8_t sample = getByte(bits_per_sample, &bout);
|
||||
GraphBuffer[j] = ((int) sample )- 128;
|
||||
}
|
||||
GraphTraceLen = j;
|
||||
PrintAndLog("Unpacked %d samples" , j );
|
||||
}else
|
||||
{
|
||||
for (int j = 0; j < n; j++) {
|
||||
GraphBuffer[j] = ((int)got[j]) - 128;
|
||||
}
|
||||
GraphTraceLen = n;
|
||||
}
|
||||
|
||||
RepaintGraphWindow();
|
||||
return 0;
|
||||
}
|
||||
|
@ -2044,7 +2137,8 @@ static command_t CommandTable[] =
|
|||
{"threshold", CmdThreshold, 1, "<threshold> -- Maximize/minimize every value in the graph window depending on threshold"},
|
||||
{"dirthreshold", CmdDirectionalThreshold, 1, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
|
||||
{"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"},
|
||||
{"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},
|
||||
{"undec", CmdUndec, 1, "Un-decimate samples by 2"},
|
||||
{"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
191
client/cmdlf.c
191
client/cmdlf.c
|
@ -356,24 +356,155 @@ int CmdIndalaClone(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int usage_lf_read()
|
||||
{
|
||||
PrintAndLog("Usage: lf read");
|
||||
PrintAndLog("Options: ");
|
||||
PrintAndLog(" h This help");
|
||||
PrintAndLog("This function takes no arguments. ");
|
||||
PrintAndLog("Use 'lf config' to set parameters.");
|
||||
return 0;
|
||||
}
|
||||
int usage_lf_snoop()
|
||||
{
|
||||
PrintAndLog("Usage: lf snoop");
|
||||
PrintAndLog("Options: ");
|
||||
PrintAndLog(" h This help");
|
||||
PrintAndLog("This function takes no arguments. ");
|
||||
PrintAndLog("Use 'lf config' to set parameters.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage_lf_config()
|
||||
{
|
||||
PrintAndLog("Usage: lf config [H|<divisor>] [b <bps>] [d <decim>] [a 0|1]");
|
||||
PrintAndLog("Options: ");
|
||||
PrintAndLog(" h This help");
|
||||
PrintAndLog(" L Low frequency (125 KHz)");
|
||||
PrintAndLog(" H High frequency (134 KHz)");
|
||||
PrintAndLog(" q <divisor> Manually set divisor. 88-> 134KHz, 95-> 125 Hz");
|
||||
PrintAndLog(" b <bps> Sets resolution of bits per sample. Default (max): 8");
|
||||
PrintAndLog(" d <decim> Sets decimation. A value of N saves only 1 in N samples. Default: 1");
|
||||
PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1");
|
||||
PrintAndLog(" t <threshold> Sets trigger threshold. 0 means no threshold");
|
||||
PrintAndLog("Examples:");
|
||||
PrintAndLog(" lf config b 8 L");
|
||||
PrintAndLog(" Samples at 125KHz, 8bps.");
|
||||
PrintAndLog(" lf config H b 4 d 3");
|
||||
PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with ");
|
||||
PrintAndLog(" a resolution of 4 bits per sample.");
|
||||
PrintAndLog(" lf read");
|
||||
PrintAndLog(" Performs a read (active field)");
|
||||
PrintAndLog(" lf snoop");
|
||||
PrintAndLog(" Performs a snoop (no active field)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdLFSetConfig(const char *Cmd)
|
||||
{
|
||||
|
||||
uint8_t divisor = 0;//Frequency divisor
|
||||
uint8_t bps = 0; // Bits per sample
|
||||
uint8_t decimation = 0; //How many to keep
|
||||
bool averaging = 1; // Defaults to true
|
||||
bool errors = FALSE;
|
||||
int trigger_threshold =-1;//Means no change
|
||||
uint8_t unsigned_trigg = 0;
|
||||
|
||||
uint8_t cmdp =0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00)
|
||||
{
|
||||
PrintAndLog("working %c", param_getchar(Cmd, cmdp));
|
||||
switch(param_getchar(Cmd, cmdp))
|
||||
{
|
||||
case 'h':
|
||||
return usage_lf_config();
|
||||
case 'H':
|
||||
divisor = 88;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'L':
|
||||
divisor = 95;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'q':
|
||||
errors |= param_getdec(Cmd,cmdp+1,&divisor);
|
||||
cmdp+=2;
|
||||
break;
|
||||
case 't':
|
||||
errors |= param_getdec(Cmd,cmdp+1,&unsigned_trigg);
|
||||
cmdp+=2;
|
||||
if(!errors) trigger_threshold = unsigned_trigg;
|
||||
break;
|
||||
case 'b':
|
||||
errors |= param_getdec(Cmd,cmdp+1,&bps);
|
||||
cmdp+=2;
|
||||
break;
|
||||
case 'd':
|
||||
errors |= param_getdec(Cmd,cmdp+1,&decimation);
|
||||
cmdp+=2;
|
||||
break;
|
||||
case 'a':
|
||||
averaging = param_getchar(Cmd,cmdp+1) == '1';
|
||||
cmdp+=2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = 1;
|
||||
break;
|
||||
}
|
||||
if(errors) break;
|
||||
}
|
||||
if(cmdp == 0)
|
||||
{
|
||||
errors = 1;// No args
|
||||
}
|
||||
|
||||
//Validations
|
||||
if(errors)
|
||||
{
|
||||
return usage_lf_config();
|
||||
}
|
||||
//Bps is limited to 8, so fits in lower half of arg1
|
||||
if(bps >> 8) bps = 8;
|
||||
|
||||
sample_config config = {
|
||||
decimation,bps,averaging,divisor,trigger_threshold
|
||||
};
|
||||
//Averaging is a flag on high-bit of arg[1]
|
||||
UsbCommand c = {CMD_SET_LF_SAMPLING_CONFIG};
|
||||
memcpy(c.d.asBytes,&config,sizeof(sample_config));
|
||||
SendCommand(&c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdLFRead(const char *Cmd)
|
||||
{
|
||||
UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
|
||||
|
||||
// 'h' means higher-low-frequency, 134 kHz
|
||||
if(*Cmd == 'h') {
|
||||
c.arg[0] = 1;
|
||||
} else if (*Cmd == '\0') {
|
||||
c.arg[0] = 0;
|
||||
} else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) {
|
||||
PrintAndLog("Samples 1: 'lf read'");
|
||||
PrintAndLog(" 2: 'lf read h'");
|
||||
PrintAndLog(" 3: 'lf read <divisor>'");
|
||||
return 0;
|
||||
}
|
||||
SendCommand(&c);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
return 0;
|
||||
uint8_t cmdp =0;
|
||||
if(param_getchar(Cmd, cmdp) == 'h')
|
||||
{
|
||||
return usage_lf_read();
|
||||
}
|
||||
//And ship it to device
|
||||
UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
|
||||
SendCommand(&c);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdLFSnoop(const char *Cmd)
|
||||
{
|
||||
uint8_t cmdp =0;
|
||||
if(param_getchar(Cmd, cmdp) == 'h')
|
||||
{
|
||||
return usage_lf_snoop();
|
||||
}
|
||||
|
||||
UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES};
|
||||
SendCommand(&c);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ChkBitstream(const char *str)
|
||||
|
@ -450,33 +581,6 @@ int CmdLFSimManchester(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdLFSnoop(const char *Cmd)
|
||||
{
|
||||
UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES};
|
||||
|
||||
// 'h' means higher-low-frequency, 134 kHz
|
||||
c.arg[0] = 0;
|
||||
c.arg[1] = -1;
|
||||
|
||||
if (*Cmd == 'l') {
|
||||
sscanf(Cmd, "l %"lli, &c.arg[1]);
|
||||
} else if(*Cmd == 'h') {
|
||||
c.arg[0] = 1;
|
||||
sscanf(Cmd, "h %"lli, &c.arg[1]);
|
||||
} else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) {
|
||||
PrintAndLog("usage 1: snoop");
|
||||
PrintAndLog(" 2: snoop <l|h> [trigger threshold]");
|
||||
PrintAndLog(" 3: snoop <divisor> [trigger threshold]");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Sample: lf snoop l 200");
|
||||
PrintAndLog(" : lf snoop 95 200");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SendCommand(&c);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdVchDemod(const char *Cmd)
|
||||
{
|
||||
|
@ -624,12 +728,13 @@ static command_t CommandTable[] =
|
|||
{"help", CmdHelp, 1, "This help"},
|
||||
{"cmdread", CmdLFCommandRead, 0, "<off period> <'0' period> <'1' period> <command> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"},
|
||||
{"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
|
||||
{"config", CmdLFSetConfig, 0, "Set config for LF sampling, bit/sample, decimation, frequency"},
|
||||
{"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},
|
||||
{"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
|
||||
{"io", CmdLFIO, 1, "{ ioProx tags... }"},
|
||||
{"indalademod", CmdIndalaDemod, 1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
|
||||
{"indalaclone", CmdIndalaClone, 0, "<UID> ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"},
|
||||
{"read", CmdLFRead, 0, "['h' or <divisor>] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134, alternatively: f=12MHz/(divisor+1))"},
|
||||
{"read", CmdLFRead, 0, "Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"},
|
||||
{"search", CmdLFfind, 1, "Read and Search for valid known tag (in offline mode it you can load first then search)"},
|
||||
{"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
|
||||
{"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
|
||||
|
|
|
@ -23,7 +23,9 @@ void setGraphBuf(uint8_t *buff, size_t size);
|
|||
bool HasGraphData();
|
||||
void DetectHighLowInGraph(int *high, int *low, bool addFuzz);
|
||||
|
||||
#define MAX_GRAPH_TRACE_LEN (1024*128)
|
||||
// Max graph trace len: 40000 (bigbuf) * 8 (at 1 bit per sample)
|
||||
#define MAX_GRAPH_TRACE_LEN (40000 * 8 )
|
||||
|
||||
extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
|
||||
extern int GraphTraceLen;
|
||||
#endif
|
||||
|
|
|
@ -213,6 +213,7 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char param_getchar(const char *line, int paramnum)
|
||||
{
|
||||
int bg, en;
|
||||
|
@ -227,6 +228,36 @@ uint8_t param_get8(const char *line, int paramnum)
|
|||
return param_get8ex(line, paramnum, 10, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a decimal integer (actually, 0-254, not 255)
|
||||
* @param line
|
||||
* @param paramnum
|
||||
* @return -1 if error
|
||||
*/
|
||||
uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination)
|
||||
{
|
||||
uint8_t val = param_get8ex(line, paramnum, 255, 10);
|
||||
printf("read %i", (int8_t ) val);
|
||||
if( (int8_t) val == -1) return 1;
|
||||
(*destination) = val;
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Checks if param is decimal
|
||||
* @param line
|
||||
* @param paramnum
|
||||
* @return
|
||||
*/
|
||||
uint8_t param_isdec(const char *line, int paramnum)
|
||||
{
|
||||
int bg, en;
|
||||
//TODO, check more thorougly
|
||||
if (!param_getptr(line, &bg, &en, paramnum)) return 1;
|
||||
// return strtoul(&line[bg], NULL, 10) & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base)
|
||||
{
|
||||
int bg, en;
|
||||
|
|
|
@ -49,6 +49,8 @@ uint8_t param_get8(const char *line, int paramnum);
|
|||
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
|
||||
uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base);
|
||||
uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
|
||||
uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination);
|
||||
uint8_t param_isdec(const char *line, int paramnum);
|
||||
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
|
||||
int param_getstr(const char *line, int paramnum, char * str);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue