Merge pull request #2173 from wh201906/lf_sniff_clean

Real-time LF sampling
This commit is contained in:
Iceman 2023-12-01 10:54:10 +01:00 committed by GitHub
commit 17a93a3b1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 900 additions and 231 deletions

View file

@ -851,13 +851,13 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_LF_ACQ_RAW_ADC: { case CMD_LF_ACQ_RAW_ADC: {
struct p { lf_sample_payload_t *payload = (lf_sample_payload_t *)packet->data.asBytes;
uint32_t samples : 31; if (payload->realtime) {
bool verbose : 1; ReadLF_realtime(true);
} PACKED; } else {
struct p *payload = (struct p *)packet->data.asBytes;
uint32_t bits = SampleLF(payload->verbose, payload->samples, true); uint32_t bits = SampleLF(payload->verbose, payload->samples, true);
reply_ng(CMD_LF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits)); reply_ng(CMD_LF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
}
break; break;
} }
case CMD_LF_MOD_THEN_ACQ_RAW_ADC: { case CMD_LF_MOD_THEN_ACQ_RAW_ADC: {
@ -880,14 +880,13 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_LF_SNIFF_RAW_ADC: { case CMD_LF_SNIFF_RAW_ADC: {
struct p { lf_sample_payload_t *payload = (lf_sample_payload_t *)packet->data.asBytes;
uint32_t samples : 31; if (payload->realtime) {
bool verbose : 1; ReadLF_realtime(false);
} PACKED; } else {
struct p *payload = (struct p *)packet->data.asBytes;
uint32_t bits = SniffLF(payload->verbose, payload->samples, true); uint32_t bits = SniffLF(payload->verbose, payload->samples, true);
reply_ng(CMD_LF_SNIFF_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits)); reply_ng(CMD_LF_SNIFF_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
}
break; break;
} }
case CMD_LF_HID_WATCH: { case CMD_LF_HID_WATCH: {

View file

@ -493,7 +493,7 @@ void FpgaDownloadAndGo(int bitstream_version) {
#endif #endif
// Send waiting time extension request as this will take a while // Send waiting time extension request as this will take a while
send_wtx(1500); send_wtx(FPGA_LOAD_WAIT_TIME);
bool verbose = (g_dbglevel > 3); bool verbose = (g_dbglevel > 3);

View file

@ -27,6 +27,7 @@
#include "lfdemod.h" #include "lfdemod.h"
#include "string.h" // memset #include "string.h" // memset
#include "appmain.h" // print stack #include "appmain.h" // print stack
#include "usb_cdc.h" // real-time sampling
/* /*
Default LF config is set to: Default LF config is set to:
@ -228,7 +229,7 @@ void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool
// write the current byte // write the current byte
data.buffer[data.numbits >> 3] |= sample >> bits_offset; data.buffer[data.numbits >> 3] |= sample >> bits_offset;
int numbits = data.numbits + bits_cap; uint32_t numbits = data.numbits + bits_cap;
// write the remaining bits to the next byte // write the remaining bits to the next byte
data.buffer[numbits >> 3] |= sample << (bits_cap); data.buffer[numbits >> 3] |= sample << (bits_cap);
@ -305,7 +306,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
// only every 4000th times, in order to save time when collecting samples. // only every 4000th times, in order to save time when collecting samples.
// interruptible only when logging not yet triggered // interruptible only when logging not yet triggered
if ((checked >= 4000) && trigger_hit == false) { if (trigger_hit == false && (checked >= 4000)) {
if (data_available()) { if (data_available()) {
checked = -1; checked = -1;
break; break;
@ -324,7 +325,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// Test point 8 (TP8) can be used to trigger oscilloscope // (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
if (ledcontrol) LED_D_OFF(); if (ledcontrol) LED_D_OFF();
// threshold either high or low values 128 = center 0. if trigger = 178 // threshold either high or low values 128 = center 0. if trigger = 178
@ -337,9 +338,8 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
} }
continue; continue;
} }
}
trigger_hit = true; trigger_hit = true;
}
if (samples_to_skip > 0) { if (samples_to_skip > 0) {
samples_to_skip--; samples_to_skip--;
@ -370,6 +370,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
} }
return data.numbits; return data.numbits;
} }
/** /**
* @brief Does sample acquisition, ignoring the config values set in the sample_config. * @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 * This method is typically used by tag-specific readers who just wants to read the samples
@ -424,6 +425,123 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol) {
BigBuf_Clear_ext(false); BigBuf_Clear_ext(false);
return ReadLF(true, verbose, sample_size, ledcontrol); return ReadLF(true, verbose, sample_size, ledcontrol);
} }
/**
* Do LF sampling and send samples to the USB
*
* Uses parameters in config. Only bits_per_sample = 8 is working now
*
* @param reader_field - true for reading tags, false for sniffing
* @return sampling result
**/
int ReadLF_realtime(bool reader_field) {
// parameters from config and constants
const uint8_t bits_per_sample = config.bits_per_sample;
const int16_t trigger_threshold = config.trigger_threshold;
int32_t samples_to_skip = config.samples_to_skip;
const uint8_t decimation = config.decimation;
const int8_t size_threshold_table[9] = {0, 64, 64, 60, 64, 60, 60, 56, 64};
const int8_t size_threshold = size_threshold_table[bits_per_sample];
// DoAcquisition() start
uint8_t last_byte = 0;
uint8_t curr_byte = 0;
int return_value = PM3_SUCCESS;
uint32_t sample_buffer_len = AT91C_USB_EP_IN_SIZE;
initSampleBuffer(&sample_buffer_len);
if (sample_buffer_len != AT91C_USB_EP_IN_SIZE) {
return PM3_EFAILED;
}
bool trigger_hit = false;
int16_t checked = 0;
return_value = async_usb_write_start();
if (return_value != PM3_SUCCESS) {
return return_value;
}
BigBuf_Clear_ext(false);
LFSetupFPGAForADC(config.divisor, reader_field);
while (BUTTON_PRESS() == false) {
// only every 4000th times, in order to save time when collecting samples.
// interruptible only when logging not yet triggered
if (trigger_hit == false && (checked >= 4000)) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
WDT_HIT();
if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY)) {
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
LED_D_OFF();
// threshold either high or low values 128 = center 0. if trigger = 178
if (trigger_hit == false) {
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
continue;
}
trigger_hit = true;
}
if (samples_to_skip > 0) {
samples_to_skip--;
continue;
}
logSample(sample, decimation, bits_per_sample, false);
// Write to USB FIFO if byte changed
curr_byte = data.numbits >> 3;
if (curr_byte > last_byte) {
async_usb_write_pushByte(data.buffer[last_byte]);
}
last_byte = curr_byte;
if (samples.total_saved == size_threshold) {
// Request USB transmission and change FIFO bank
if (async_usb_write_requestWrite() == false) {
return_value = PM3_EIO;
break;
}
// Reset sample
last_byte = 0;
data.numbits = 0;
samples.counter = size_threshold;
samples.total_saved = 0;
} else if (samples.total_saved == 1) {
// Check if there is any data from client
if (data_available_fast()) {
break;
}
}
}
}
LED_D_OFF();
return_value = async_usb_write_stop();
// DoAcquisition() end
StopTicks();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return return_value;
}
/** /**
* Initializes the FPGA for sniffer-mode (field off), and acquires the samples. * Initializes the FPGA for sniffer-mode (field off), and acquires the samples.
* @return number of bits sampled * @return number of bits sampled

View file

@ -51,6 +51,16 @@ void doT55x7Acquisition(size_t sample_size, bool ledcontrol);
**/ **/
uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol); uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol);
/**
* Do LF sampling and send samples to the USB
*
* Uses parameters in config. Only bits_per_sample = 8 is working now
*
* @param reader_field - true for reading tags, false for sniffing
* @return sampling result
**/
int ReadLF_realtime(bool reader_field);
/** /**
* Initializes the FPGA for sniff-mode (field off), and acquires the samples. * Initializes the FPGA for sniff-mode (field off), and acquires the samples.
* @return number of bits sampled * @return number of bits sampled

View file

@ -153,7 +153,7 @@ static void zx_get(bool ledcontrol) {
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
(void)sample; (void)sample;
// Test point 8 (TP8) can be used to trigger oscilloscope // (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
if (ledcontrol) LED_D_OFF(); if (ledcontrol) LED_D_OFF();
} }

View file

@ -298,6 +298,8 @@ int BUTTON_HELD(int ms) {
return BUTTON_ERROR; return BUTTON_ERROR;
} }
// This function returns false if no data is available or
// the USB connection is invalid.
bool data_available(void) { bool data_available(void) {
#ifdef WITH_FPC_USART_HOST #ifdef WITH_FPC_USART_HOST
return usb_poll_validate_length() || (usart_rxdata_available() > 0); return usb_poll_validate_length() || (usart_rxdata_available() > 0);
@ -305,3 +307,14 @@ bool data_available(void) {
return usb_poll_validate_length(); return usb_poll_validate_length();
#endif #endif
} }
// This function doesn't check if the USB connection is valid.
// In most of the cases, you should use data_available() unless
// the timing is critical.
bool data_available_fast(void) {
#ifdef WITH_FPC_USART_HOST
return usb_available_length() || (usart_rxdata_available() > 0);
#else
return usb_available_length();
#endif
}

View file

@ -101,5 +101,6 @@ void SpinUp(uint32_t speed);
int BUTTON_CLICKED(int ms); int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms); int BUTTON_HELD(int ms);
bool data_available(void); bool data_available(void);
bool data_available_fast(void);
#endif #endif

View file

@ -564,7 +564,11 @@ static int Cmdmandecoderaw(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; uint8_t *bits = calloc(MAX_DEMOD_BUF_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
// make sure its just binary data 0|1|7 in buffer // make sure its just binary data 0|1|7 in buffer
int high = 0, low = 0; int high = 0, low = 0;
@ -579,6 +583,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
if (high > 7 || low < 0) { if (high > 7 || low < 0) {
PrintAndLogEx(ERR, "Error: please first raw demod then manchester raw decode"); PrintAndLogEx(ERR, "Error: please first raw demod then manchester raw decode");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -587,6 +592,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
uint16_t err_cnt = manrawdecode(bits, &size, invert, &offset); uint16_t err_cnt = manrawdecode(bits, &size, invert, &offset);
if (err_cnt > max_err) { if (err_cnt > max_err) {
PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt); PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -611,6 +617,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
} }
setDemodBuff(bits, size, 0); setDemodBuff(bits, size, 0);
setClockGrid(g_DemodClock * 2, g_DemodStartIdx); setClockGrid(g_DemodClock * 2, g_DemodStartIdx);
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -651,17 +658,27 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; uint8_t *bits = calloc(MAX_DEMOD_BUF_LEN, sizeof(uint8_t));
size_t size = sizeof(bits); if (bits == NULL) {
if (!getDemodBuff(bits, &size)) return PM3_ESOFT; PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = MAX_DEMOD_BUF_LEN;
if (!getDemodBuff(bits, &size)) {
free(bits);
return PM3_ESOFT;
}
int err_cnt = BiphaseRawDecode(bits, &size, &offset, invert); int err_cnt = BiphaseRawDecode(bits, &size, &offset, invert);
if (err_cnt < 0) { if (err_cnt < 0) {
PrintAndLogEx(ERR, "Error during decode " _RED_("%i"), err_cnt); PrintAndLogEx(ERR, "Error during decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
if (err_cnt > max_err) { if (err_cnt > max_err) {
PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt); PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -674,6 +691,7 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
setDemodBuff(bits, size, 0); setDemodBuff(bits, size, 0);
setClockGrid(g_DemodClock * 2, g_DemodStartIdx + g_DemodClock * offset); setClockGrid(g_DemodClock * 2, g_DemodStartIdx + g_DemodClock * offset);
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -681,10 +699,16 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) { int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
//ask raw demod g_GraphBuffer first //ask raw demod g_GraphBuffer first
uint8_t bs[MAX_DEMOD_BUF_LEN]; uint8_t *bs = calloc(MAX_DEMOD_BUF_LEN, sizeof(uint8_t));
size_t size = getFromGraphBuf(bs); if (bs == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBufEx(bs, MAX_DEMOD_BUF_LEN);
if (size == 0) { if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf"); PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf");
free(bs);
return PM3_ESOFT; return PM3_ESOFT;
} }
int startIdx = 0; int startIdx = 0;
@ -692,6 +716,7 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
int errCnt = askdemod_ext(bs, &size, &clk, &invert, maxErr, 0, 0, &startIdx); int errCnt = askdemod_ext(bs, &size, &clk, &invert, maxErr, 0, 0, &startIdx);
if (errCnt < 0 || errCnt > maxErr) { if (errCnt < 0 || errCnt > maxErr) {
PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk); PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk);
free(bs);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -699,10 +724,12 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
errCnt = BiphaseRawDecode(bs, &size, &offset, invert); errCnt = BiphaseRawDecode(bs, &size, &offset, invert);
if (errCnt < 0) { if (errCnt < 0) {
if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt); if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt);
free(bs);
return PM3_ESOFT; return PM3_ESOFT;
} }
if (errCnt > maxErr) { if (errCnt > maxErr) {
if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode too many errors: %d", errCnt); if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode too many errors: %d", errCnt);
free(bs);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -716,6 +743,7 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2)); PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2));
printDemodBuff(offset, false, false, false); printDemodBuff(offset, false, false, false);
} }
free(bs);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1011,7 +1039,11 @@ static int CmdUndecimate(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
//We have memory, don't we? //We have memory, don't we?
int swap[MAX_GRAPH_TRACE_LEN] = {0}; int *swap = calloc(MAX_GRAPH_TRACE_LEN, sizeof(int));
if (swap == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
uint32_t g_index = 0, s_index = 0; uint32_t g_index = 0, s_index = 0;
while (g_index < g_GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) { while (g_index < g_GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) {
int count = 0; int count = 0;
@ -1028,6 +1060,7 @@ static int CmdUndecimate(const char *Cmd) {
memcpy(g_GraphBuffer, swap, s_index * sizeof(int)); memcpy(g_GraphBuffer, swap, s_index * sizeof(int));
g_GraphTraceLen = s_index; g_GraphTraceLen = s_index;
RepaintGraphWindow(); RepaintGraphWindow();
free(swap);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1707,7 +1740,11 @@ int CmdHpf(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
removeSignalOffset(bits, size); removeSignalOffset(bits, size);
// push it back to graph // push it back to graph
@ -1716,6 +1753,7 @@ int CmdHpf(const char *Cmd) {
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1776,35 +1814,48 @@ int getSamplesEx(uint32_t start, uint32_t end, bool verbose, bool ignore_lf_conf
bits_per_sample = sc->bits_per_sample; bits_per_sample = sc->bits_per_sample;
} }
return getSamplesFromBufEx(got, n, bits_per_sample, verbose);;
}
int getSamplesFromBufEx(uint8_t *data, size_t sample_num, uint8_t bits_per_sample, bool verbose) {
size_t max_num = MIN(sample_num, MAX_GRAPH_TRACE_LEN);
if (bits_per_sample < 8) { if (bits_per_sample < 8) {
if (verbose) PrintAndLogEx(INFO, "Unpacking..."); if (verbose) PrintAndLogEx(INFO, "Unpacking...");
BitstreamOut_t bout = { got, bits_per_sample * n, 0}; BitstreamOut_t bout = {data, bits_per_sample * sample_num, 0};
uint32_t j = 0; size_t j = 0;
for (j = 0; j * bits_per_sample < n * 8 && j * bits_per_sample < MAX_GRAPH_TRACE_LEN * 8; j++) { for (j = 0; j < max_num; j++) {
uint8_t sample = getByte(bits_per_sample, &bout); uint8_t sample = getByte(bits_per_sample, &bout);
g_GraphBuffer[j] = ((int) sample) - 127; g_GraphBuffer[j] = ((int) sample) - 127;
} }
g_GraphTraceLen = j; g_GraphTraceLen = j;
if (verbose) PrintAndLogEx(INFO, "Unpacked %d samples", j); if (verbose) PrintAndLogEx(INFO, "Unpacked %zu samples", j);
} else { } else {
for (uint32_t j = 0; j < n; j++) { for (size_t j = 0; j < max_num; j++) {
g_GraphBuffer[j] = ((int)got[j]) - 127; g_GraphBuffer[j] = ((int)data[j]) - 127;
} }
g_GraphTraceLen = n; g_GraphTraceLen = max_num;
} }
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noise detection // set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
free(bits);
setClockGrid(0, 0); setClockGrid(0, 0);
g_DemodBufferLen = 0; g_DemodBufferLen = 0;
RepaintGraphWindow(); RepaintGraphWindow();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2094,12 +2145,17 @@ static int CmdLoad(const char *Cmd) {
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", g_GraphTraceLen); PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", g_GraphTraceLen);
if (nofix == false) { if (nofix == false) {
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
removeSignalOffset(bits, size); removeSignalOffset(bits, size);
setGraphBuf(bits, size); setGraphBuf(bits, size);
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
free(bits);
} }
setClockGrid(0, 0); setClockGrid(0, 0);
@ -2231,12 +2287,17 @@ int CmdNorm(const char *Cmd) {
} }
} }
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noise detection // set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2377,12 +2438,17 @@ static int CmdDirectionalThreshold(const char *Cmd) {
directionalThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down); directionalThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down);
// set signal properties low/high/mean/amplitude and isnoice detection // set signal properties low/high/mean/amplitude and isnoice detection
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noice detection // set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2420,11 +2486,16 @@ static int CmdZerocrossings(const char *Cmd) {
} }
} }
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noise detection // set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2733,11 +2804,16 @@ static int CmdDataIIR(const char *Cmd) {
iceSimple_Filter(g_GraphBuffer, g_GraphTraceLen, k); iceSimple_Filter(g_GraphBuffer, g_GraphTraceLen, k);
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noise detection // set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -3360,11 +3436,16 @@ static int CmdCenterThreshold(const char *Cmd) {
centerThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down); centerThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down);
// set signal properties low/high/mean/amplitude and isnoice detection // set signal properties low/high/mean/amplitude and isnoice detection
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noice detection // set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -3405,11 +3486,16 @@ static int CmdEnvelope(const char *Cmd) {
envelope_square(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen); envelope_square(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen);
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
// set signal properties low/high/mean/amplitude and is_noice detection // set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size); computeSignalProperties(bits, size);
RepaintGraphWindow(); RepaintGraphWindow();
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -3584,4 +3670,3 @@ int CmdData(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }

View file

@ -86,6 +86,7 @@ int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveG
int getSamples(uint32_t n, bool verbose); int getSamples(uint32_t n, bool verbose);
int getSamplesEx(uint32_t start, uint32_t end, bool verbose, bool ignore_lf_config); int getSamplesEx(uint32_t start, uint32_t end, bool verbose, bool ignore_lf_config);
int getSamplesFromBufEx(uint8_t *data, size_t sample_num, uint8_t bits_per_sample, bool verbose);
void setClockGrid(uint32_t clk, int offset); void setClockGrid(uint32_t clk, int offset);
int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down); int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down);

View file

@ -66,8 +66,6 @@
#include "crc.h" #include "crc.h"
#include "pm3_cmd.h" // for LF_CMDREAD_MAX_EXTRA_SYMBOLS #include "pm3_cmd.h" // for LF_CMDREAD_MAX_EXTRA_SYMBOLS
static bool gs_lf_threshold_set = false;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
// Informative user function. // Informative user function.
@ -433,7 +431,11 @@ int CmdFlexdemod(const char *Cmd) {
#endif #endif
int i, j, start, bit, sum; int i, j, start, bit, sum;
int data[g_GraphTraceLen]; int *data = calloc(g_GraphTraceLen, sizeof(int));
if (data == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
memcpy(data, g_GraphBuffer, g_GraphTraceLen); memcpy(data, g_GraphBuffer, g_GraphTraceLen);
size_t size = g_GraphTraceLen; size_t size = g_GraphTraceLen;
@ -454,6 +456,7 @@ int CmdFlexdemod(const char *Cmd) {
if (start == size - LONG_WAIT) { if (start == size - LONG_WAIT) {
PrintAndLogEx(WARNING, "nothing to wait for"); PrintAndLogEx(WARNING, "nothing to wait for");
free(data);
return PM3_ENODATA; return PM3_ENODATA;
} }
@ -497,6 +500,7 @@ int CmdFlexdemod(const char *Cmd) {
} }
} }
RepaintGraphWindow(); RepaintGraphWindow();
free(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -644,7 +648,6 @@ int CmdLFConfig(const char *Cmd) {
config.divisor = LF_DIVISOR_125; config.divisor = LF_DIVISOR_125;
config.samples_to_skip = 0; config.samples_to_skip = 0;
config.trigger_threshold = 0; config.trigger_threshold = 0;
gs_lf_threshold_set = false;
} }
if (use_125) if (use_125)
@ -689,29 +692,61 @@ int CmdLFConfig(const char *Cmd) {
if (trigg > -1) { if (trigg > -1) {
config.trigger_threshold = trigg; config.trigger_threshold = trigg;
gs_lf_threshold_set = (config.trigger_threshold > 0);
} }
config.samples_to_skip = skip; config.samples_to_skip = skip;
return lf_config(&config); return lf_config(&config);
} }
int lf_read(bool verbose, uint32_t samples) { static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) {
if (!g_session.pm3_present) return PM3_ENOTTY; if (!g_session.pm3_present) return PM3_ENOTTY;
struct p { lf_sample_payload_t payload = {0};
uint32_t samples : 31; payload.realtime = realtime;
bool verbose : 1;
} PACKED;
struct p payload;
payload.verbose = verbose; payload.verbose = verbose;
payload.samples = samples;
sample_config current_config;
int retval = lf_getconfig(&current_config);
if (retval != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to get current device config");
return retval;
}
clearCommandBuffer(); clearCommandBuffer();
const uint8_t bits_per_sample = current_config.bits_per_sample;
const bool is_trigger_threshold_set = (current_config.trigger_threshold > 0);
if (realtime) {
uint8_t *realtimeBuf = calloc(samples, sizeof(uint8_t));
if (realtimeBuf == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t sample_bytes = samples * bits_per_sample;
sample_bytes = (sample_bytes / 8) + (sample_bytes % 8 != 0);
SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
if (is_trigger_threshold_set) {
size_t first_receive_len = 32; // larger than the response of CMD_WTX
// Wait until a bunch of data arrives
first_receive_len = WaitForRawDataTimeout(realtimeBuf, first_receive_len, -1, false);
sample_bytes = WaitForRawDataTimeout(realtimeBuf + first_receive_len, sample_bytes - first_receive_len, 1000 + FPGA_LOAD_WAIT_TIME, true);
sample_bytes += first_receive_len;
} else {
sample_bytes = WaitForRawDataTimeout(realtimeBuf, sample_bytes, 1000 + FPGA_LOAD_WAIT_TIME, true);
}
samples = sample_bytes * 8 / bits_per_sample;
PrintAndLogEx(INFO, "Done: %" PRIu64 " samples (%zu bytes)", samples, sample_bytes);
if (samples != 0) {
getSamplesFromBufEx(realtimeBuf, samples, bits_per_sample, verbose);
}
free(realtimeBuf);
} else {
payload.samples = (samples > MAX_LF_SAMPLES) ? MAX_LF_SAMPLES : samples;
SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp; PacketResponseNG resp;
if (gs_lf_threshold_set) { if (is_trigger_threshold_set) {
WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp); WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp);
} else { } else {
if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) { if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) {
@ -719,14 +754,21 @@ int lf_read(bool verbose, uint32_t samples) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
} }
// response is number of bits read // response is number of bits read
uint32_t size = (resp.data.asDwords[0] / 8); uint32_t size = (resp.data.asDwords[0] / bits_per_sample);
getSamples(size, verbose); getSamples(size, verbose);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int lf_read(bool verbose, uint64_t samples) {
return lf_read_internal(false, verbose, samples);
}
int CmdLFRead(const char *Cmd) { int CmdLFRead(const char *Cmd) {
// In real-time mode, the first few bytes might be the response of CMD_WTX
// rather than the real samples if the LF FPGA image is not ready.
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf read", CLIParserInit(&ctx, "lf read",
"Sniff low frequency signal.\n" "Sniff low frequency signal.\n"
@ -734,6 +776,7 @@ int CmdLFRead(const char *Cmd) {
_CYAN_(" - use ") _YELLOW_("`data plot`") _CYAN_(" to look at it"), _CYAN_(" - use ") _YELLOW_("`data plot`") _CYAN_(" to look at it"),
"lf read -v -s 12000 --> collect 12000 samples\n" "lf read -v -s 12000 --> collect 12000 samples\n"
"lf read -s 3000 -@ --> oscilloscope style \n" "lf read -s 3000 -@ --> oscilloscope style \n"
"lf read -r --> use real-time mode \n"
); );
void *argtable[] = { void *argtable[] = {
@ -741,42 +784,82 @@ int CmdLFRead(const char *Cmd) {
arg_u64_0("s", "samples", "<dec>", "number of samples to collect"), arg_u64_0("s", "samples", "<dec>", "number of samples to collect"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0("@", NULL, "continuous reading mode"), arg_lit0("@", NULL, "continuous reading mode"),
arg_lit0("r", "realtime", "real-time reading mode"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t samples = arg_get_u32_def(ctx, 1, 0); uint64_t samples = arg_get_u64_def(ctx, 1, 0);
bool verbose = arg_get_lit(ctx, 2); bool verbose = arg_get_lit(ctx, 2);
bool cm = arg_get_lit(ctx, 3); bool cm = arg_get_lit(ctx, 3);
bool realtime = arg_get_lit(ctx, 4);
CLIParserFree(ctx); CLIParserFree(ctx);
if (g_session.pm3_present == false) if (g_session.pm3_present == false)
return PM3_ENOTTY; return PM3_ENOTTY;
if (cm) { if (realtime && samples == 0) {
samples = MAX_GRAPH_TRACE_LEN;
}
if (cm || realtime) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit"); PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
} }
int ret = PM3_SUCCESS; int ret = PM3_SUCCESS;
do { do {
ret = lf_read(verbose, samples); ret = lf_read_internal(realtime, verbose, samples);
} while (cm && kbd_enter_pressed() == false); } while (cm && kbd_enter_pressed() == false);
return ret; return ret;
} }
int lf_sniff(bool verbose, uint32_t samples) { int lf_sniff(bool realtime, bool verbose, uint64_t samples) {
if (!g_session.pm3_present) return PM3_ENOTTY; if (!g_session.pm3_present) return PM3_ENOTTY;
struct p { lf_sample_payload_t payload = {0};
uint32_t samples : 31; payload.realtime = realtime;
bool verbose : 1;
} PACKED payload;
payload.samples = (samples & 0xFFFF);
payload.verbose = verbose; payload.verbose = verbose;
sample_config current_config;
int retval = lf_getconfig(&current_config);
if (retval != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to get current device config");
return retval;
}
clearCommandBuffer(); clearCommandBuffer();
const uint8_t bits_per_sample = current_config.bits_per_sample;
const bool is_trigger_threshold_set = (current_config.trigger_threshold > 0);
if (realtime) {
uint8_t *realtimeBuf = calloc(samples, sizeof(uint8_t));
if (realtimeBuf == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t sample_bytes = samples * bits_per_sample;
sample_bytes = (sample_bytes / 8) + (sample_bytes % 8 != 0);
SendCommandNG(CMD_LF_SNIFF_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
if (is_trigger_threshold_set) {
size_t first_receive_len = 32; // larger than the response of CMD_WTX
// Wait until a bunch of data arrives
first_receive_len = WaitForRawDataTimeout(realtimeBuf, first_receive_len, -1, false);
sample_bytes = WaitForRawDataTimeout(realtimeBuf + first_receive_len, sample_bytes - first_receive_len, 1000 + FPGA_LOAD_WAIT_TIME, true);
sample_bytes += first_receive_len;
} else {
sample_bytes = WaitForRawDataTimeout(realtimeBuf, sample_bytes, 1000 + FPGA_LOAD_WAIT_TIME, true);
}
samples = sample_bytes * 8 / bits_per_sample;
PrintAndLogEx(INFO, "Done: %" PRIu64 " samples (%zu bytes)", samples, sample_bytes);
if (samples != 0) {
getSamplesFromBufEx(realtimeBuf, samples, bits_per_sample, verbose);
}
free(realtimeBuf);
} else {
payload.samples = (samples > MAX_LF_SAMPLES) ? MAX_LF_SAMPLES : samples;
SendCommandNG(CMD_LF_SNIFF_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_LF_SNIFF_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp; PacketResponseNG resp;
if (gs_lf_threshold_set) { if (is_trigger_threshold_set) {
WaitForResponse(CMD_LF_SNIFF_RAW_ADC, &resp); WaitForResponse(CMD_LF_SNIFF_RAW_ADC, &resp);
} else { } else {
if (WaitForResponseTimeout(CMD_LF_SNIFF_RAW_ADC, &resp, 2500) == false) { if (WaitForResponseTimeout(CMD_LF_SNIFF_RAW_ADC, &resp, 2500) == false) {
@ -784,14 +867,17 @@ int lf_sniff(bool verbose, uint32_t samples) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
} }
// response is number of bits read // response is number of bits read
uint32_t size = (resp.data.asDwords[0] / 8); uint32_t size = (resp.data.asDwords[0] / bits_per_sample);
getSamples(size, verbose); getSamples(size, verbose);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdLFSniff(const char *Cmd) { int CmdLFSniff(const char *Cmd) {
// In real-time mode, the first few bytes might be the response of CMD_WTX
// rather than the real samples if the LF FPGA image is not ready.
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf sniff", CLIParserInit(&ctx, "lf sniff",
"Sniff low frequency signal. You need to configure the LF part on the Proxmark3 device manually.\n" "Sniff low frequency signal. You need to configure the LF part on the Proxmark3 device manually.\n"
@ -802,6 +888,7 @@ int CmdLFSniff(const char *Cmd) {
_CYAN_(" - use ") _YELLOW_("`lf search -1`") _CYAN_(" to see if signal can be automatic decoded\n"), _CYAN_(" - use ") _YELLOW_("`lf search -1`") _CYAN_(" to see if signal can be automatic decoded\n"),
"lf sniff -v\n" "lf sniff -v\n"
"lf sniff -s 3000 -@ --> oscilloscope style \n" "lf sniff -s 3000 -@ --> oscilloscope style \n"
"lf sniff -r --> use real-time mode \n"
); );
void *argtable[] = { void *argtable[] = {
@ -809,24 +896,30 @@ int CmdLFSniff(const char *Cmd) {
arg_u64_0("s", "samples", "<dec>", "number of samples to collect"), arg_u64_0("s", "samples", "<dec>", "number of samples to collect"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_lit0("@", NULL, "continuous sniffing mode"), arg_lit0("@", NULL, "continuous sniffing mode"),
arg_lit0("r", "realtime", "real-time sniffing mode"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t samples = (arg_get_u32_def(ctx, 1, 0) & 0xFFFF); uint64_t samples = arg_get_u64_def(ctx, 1, 0);
bool verbose = arg_get_lit(ctx, 2); bool verbose = arg_get_lit(ctx, 2);
bool cm = arg_get_lit(ctx, 3); bool cm = arg_get_lit(ctx, 3);
bool realtime = arg_get_lit(ctx, 4);
CLIParserFree(ctx); CLIParserFree(ctx);
if (g_session.pm3_present == false) if (g_session.pm3_present == false)
return PM3_ENOTTY; return PM3_ENOTTY;
if (cm) { if (realtime && samples == 0) {
samples = MAX_GRAPH_TRACE_LEN;
}
if (cm || realtime) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit"); PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
} }
int ret = PM3_SUCCESS; int ret = PM3_SUCCESS;
do { do {
ret = lf_sniff(verbose, samples); ret = lf_sniff(realtime, verbose, samples);
} while (cm && !kbd_enter_pressed()); } while (cm && kbd_enter_pressed() == false);
return ret; return ret;
} }

View file

@ -40,8 +40,8 @@ int CmdLFSniff(const char *Cmd);
int CmdVchDemod(const char *Cmd); int CmdVchDemod(const char *Cmd);
int CmdLFfind(const char *Cmd); int CmdLFfind(const char *Cmd);
int lf_read(bool verbose, uint32_t samples); int lf_read(bool verbose, uint64_t samples);
int lf_sniff(bool verbose, uint32_t samples); int lf_sniff(bool realtime, bool verbose, uint64_t samples);
int lf_config(sample_config *config); int lf_config(sample_config *config);
int lf_getconfig(sample_config *config); int lf_getconfig(sample_config *config);
int lfsim_upload_gb(void); int lfsim_upload_gb(void);

View file

@ -117,10 +117,15 @@ int demodHID(bool verbose) {
//raw fsk demod no manchester decoding no start bit finding just get binary from wave //raw fsk demod no manchester decoding no start bit finding just get binary from wave
uint32_t hi2 = 0, hi = 0, lo = 0; uint32_t hi2 = 0, hi = 0, lo = 0;
uint8_t bits[g_GraphTraceLen]; uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size == 0) { if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples")); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
//get binary from fsk wave //get binary from fsk wave
@ -141,11 +146,13 @@ int demodHID(bool verbose) {
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
setDemodBuff(bits, size, idx); setDemodBuff(bits, size, idx);
setClockGrid(50, waveIdx + (idx * 50)); setClockGrid(50, waveIdx + (idx * 50));
free(bits);
if (hi2 == 0 && hi == 0 && lo == 0) { if (hi2 == 0 && hi == 0 && lo == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID no values found")); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID no values found"));

View file

@ -403,7 +403,11 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
// worst case with g_GraphTraceLen=40000 is < 4096 // worst case with g_GraphTraceLen=40000 is < 4096
// under normal conditions it's < 2048 // under normal conditions it's < 2048
uint8_t data[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t *data = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (data == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t datasize = getFromGraphBuf(data); size_t datasize = getFromGraphBuf(data);
uint8_t rawbits[4096] = {0}; uint8_t rawbits[4096] = {0};
@ -446,6 +450,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
count = 0; count = 0;
} }
} }
free(data);
if (rawbit > 0) { if (rawbit > 0) {
PrintAndLogEx(INFO, "Recovered %d raw bits, expected: %zu", rawbit, g_GraphTraceLen / 32); PrintAndLogEx(INFO, "Recovered %d raw bits, expected: %zu", rawbit, g_GraphTraceLen / 32);

View file

@ -66,10 +66,15 @@ static int CmdIOProxWatch(const char *Cmd) {
int demodIOProx(bool verbose) { int demodIOProx(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
int idx = 0, retval = PM3_SUCCESS; int idx = 0, retval = PM3_SUCCESS;
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size < 65) { if (size < 65) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer"); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
//get binary from fsk wave //get binary from fsk wave
@ -93,6 +98,7 @@ int demodIOProx(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox error demoding fsk %d", idx); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox error demoding fsk %d", idx);
} }
} }
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
setDemodBuff(bits, size, idx); setDemodBuff(bits, size, idx);
@ -103,6 +109,7 @@ int demodIOProx(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox data not found - FSK Bits: %zu", size); PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox data not found - FSK Bits: %zu", size);
if (size > 92) PrintAndLogEx(DEBUG, "%s", sprint_bytebits_bin_break(bits, 92, 16)); if (size > 92) PrintAndLogEx(DEBUG, "%s", sprint_bytebits_bin_break(bits, 92, 16));
} }
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -156,6 +163,7 @@ int demodIOProx(bool verbose) {
printDemodBuff(0, false, false, true); printDemodBuff(0, false, false, true);
printDemodBuff(0, false, false, false); printDemodBuff(0, false, false, false);
} }
free(bits);
return retval; return retval;
} }
@ -441,4 +449,3 @@ int getIOProxBits(uint8_t version, uint8_t fc, uint16_t cn, uint8_t *bits) {
PrintAndLogEx(SUCCESS, "IO raw bits:\n %s \n", sprint_bytebits_bin(bits, 64)); PrintAndLogEx(SUCCESS, "IO raw bits:\n %s \n", sprint_bytebits_bin(bits, 64));
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -103,10 +103,15 @@ static uint8_t GetParadoxBits(const uint32_t fc, const uint32_t cn, unsigned int
int demodParadox(bool verbose, bool oldChksum) { int demodParadox(bool verbose, bool oldChksum) {
(void) verbose; // unused so far (void) verbose; // unused so far
//raw fsk demod no manchester decoding no start bit finding just get binary from wave //raw fsk demod no manchester decoding no start bit finding just get binary from wave
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size == 0) { if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox not enough samples");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -125,6 +130,7 @@ int demodParadox(bool verbose, bool oldChksum) {
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox error demoding fsk %d", idx); PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox error demoding fsk %d", idx);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -175,6 +181,7 @@ int demodParadox(bool verbose, bool oldChksum) {
if (hi2 == 0 && hi == 0 && lo == 0) { if (hi2 == 0 && hi == 0 && lo == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox no value found"); PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox no value found");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -230,6 +237,7 @@ int demodParadox(bool verbose, bool oldChksum) {
printDemodBuff(0, false, false, false); printDemodBuff(0, false, false, false);
} }
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -500,5 +508,3 @@ int detectParadox(uint8_t *dest, size_t *size, int *wave_start_idx) {
return (int)idx; return (int)idx;
} }

View file

@ -43,10 +43,15 @@ static int CmdHelp(const char *Cmd);
int demodPyramid(bool verbose) { int demodPyramid(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
//raw fsk demod no manchester decoding no start bit finding just get binary from wave //raw fsk demod no manchester decoding no start bit finding just get binary from wave
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size == 0) { if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid not enough samples");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
//get binary from fsk wave //get binary from fsk wave
@ -65,6 +70,7 @@ int demodPyramid(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: size not correct: %zu", size); PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: size not correct: %zu", size);
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: error demoding fsk idx: %d", idx); PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: error demoding fsk idx: %d", idx);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
setDemodBuff(bits, size, idx); setDemodBuff(bits, size, idx);
@ -113,6 +119,7 @@ int demodPyramid(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: parity check failed - IDX: %d, hi3: %08X", idx, rawHi3); PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: parity check failed - IDX: %d, hi3: %08X", idx, rawHi3);
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: at parity check - tag size does not match Pyramid format, SIZE: %zu, IDX: %d, hi3: %08X", size, idx, rawHi3); PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: at parity check - tag size does not match Pyramid format, SIZE: %zu, IDX: %d, hi3: %08X", size, idx, rawHi3);
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -181,6 +188,7 @@ int demodPyramid(bool verbose) {
printDemodBuff(0, false, false, false); printDemodBuff(0, false, false, false);
} }
free(bits);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -507,4 +515,3 @@ int detectPyramid(uint8_t *dest, size_t *size, int *waveStartIdx) {
return (int)startIdx; return (int)startIdx;
} }

View file

@ -41,6 +41,10 @@ capabilities_t g_pm3_capabilities;
static pthread_t communication_thread; static pthread_t communication_thread;
static bool comm_thread_dead = false; static bool comm_thread_dead = false;
static bool comm_raw_mode = false;
static uint8_t *comm_raw_data = NULL;
static size_t comm_raw_len = 0;
static size_t comm_raw_pos = 0;
// Transmit buffer. // Transmit buffer.
static PacketCommandOLD txBuffer; static PacketCommandOLD txBuffer;
@ -346,6 +350,8 @@ __attribute__((force_align_arg_pointer))
bool commfailed = false; bool commfailed = false;
PacketResponseNG rx; PacketResponseNG rx;
PacketResponseNGRaw rx_raw; PacketResponseNGRaw rx_raw;
// Stash the last state of is_receiving_raw, to detect if state changed
bool is_receiving_raw_last = false;
#if defined(__MACH__) && defined(__APPLE__) #if defined(__MACH__) && defined(__APPLE__)
disableAppNap("Proxmark3 polling UART"); disableAppNap("Proxmark3 polling UART");
@ -368,6 +374,43 @@ __attribute__((force_align_arg_pointer))
break; break;
} }
bool is_receiving_raw = __atomic_load_n(&comm_raw_mode, __ATOMIC_SEQ_CST);
if (is_receiving_raw) {
uint8_t *bufferData = __atomic_load_n(&comm_raw_data, __ATOMIC_SEQ_CST); // read only
size_t bufferLen = __atomic_load_n(&comm_raw_len, __ATOMIC_SEQ_CST); // read only
size_t bufferPos = __atomic_load_n(&comm_raw_pos, __ATOMIC_SEQ_CST); // read and write
if (bufferPos < bufferLen) {
size_t rxMaxLen = bufferLen - bufferPos;
rxMaxLen = MIN(COMM_RAW_RECEIVE_LEN, rxMaxLen);
res = uart_receive(sp, bufferData + bufferPos, rxMaxLen, &rxlen);
if (res == PM3_SUCCESS) {
uint64_t clk = msclock();
__atomic_store_n(&timeout_start_time, clk, __ATOMIC_SEQ_CST);
__atomic_store_n(&comm_raw_pos, bufferPos + rxlen, __ATOMIC_SEQ_CST);
} else if (res != PM3_ENODATA) {
PrintAndLogEx(WARNING, "Error when reading raw data: %zu/%zu, %d", bufferPos, bufferLen, res);
error = true;
if (res == PM3_ENOTTY) {
commfailed = true;
}
}
} else {
// Ignore data when bufferPos >= bufferLen and is_receiving_raw has not been set to false
uint8_t dummyData[64];
uint32_t dummyLen;
uart_receive(sp, dummyData, sizeof(dummyData), &dummyLen);
}
} else {
if (is_receiving_raw_last) {
// is_receiving_raw changed from true to false
// Set the buffer as undefined
// comm_raw_data == NULL is used in SetCommunicationReceiveMode()
__atomic_store_n(&comm_raw_data, NULL, __ATOMIC_SEQ_CST);
}
res = uart_receive(sp, (uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), &rxlen); res = uart_receive(sp, (uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), &rxlen);
if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) { if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) {
@ -497,7 +540,9 @@ __attribute__((force_align_arg_pointer))
commfailed = true; commfailed = true;
} }
} }
}
is_receiving_raw_last = is_receiving_raw;
// TODO if error, shall we resync ? // TODO if error, shall we resync ?
pthread_mutex_lock(&txBufferMutex); pthread_mutex_lock(&txBufferMutex);
@ -560,6 +605,45 @@ bool IsCommunicationThreadDead(void) {
return ret; return ret;
} }
// To start raw receive mode:
// 1. Call SetCommunicationRawReceiveBuffer(...)
// 2. Call SetCommunicationReceiveMode(true)
//
// To stop raw receive mode:
// Call SetCommunicationReceiveMode(false)
//
// Note:
// 1. The receiving thread won't accept any normal packets after calling
// SetCommunicationReceiveMode(true). You need to call
// SetCommunicationReceiveMode(false) to stop the raw receiving process.
// 2. If the received size >= len used in SetCommunicationRawReceiveBuffer(),
// The receiving thread will ignore the incoming data to prevent overflow.
// 3. Normally you only need WaitForRawDataTimeout() rather than the
// low level functions like SetCommunicationReceiveMode(),
// SetCommunicationRawReceiveBuffer() and GetCommunicationRawReceiveNum()
bool SetCommunicationReceiveMode(bool isRawMode) {
if (isRawMode) {
uint8_t *buffer = __atomic_load_n(&comm_raw_data, __ATOMIC_SEQ_CST);
if (buffer == NULL) {
PrintAndLogEx(ERR, "Buffer for raw data is not set");
return false;
}
}
__atomic_store_n(&comm_raw_mode, isRawMode, __ATOMIC_SEQ_CST);
return true;
}
void SetCommunicationRawReceiveBuffer(uint8_t *buffer, size_t len) {
__atomic_store_n(&comm_raw_data, buffer, __ATOMIC_SEQ_CST);
__atomic_store_n(&comm_raw_len, len, __ATOMIC_SEQ_CST);
__atomic_store_n(&comm_raw_pos, 0, __ATOMIC_SEQ_CST);
}
size_t GetCommunicationRawReceiveNum(void) {
return __atomic_load_n(&comm_raw_pos, __ATOMIC_SEQ_CST);
}
bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed) { bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed) {
if (!wait_for_port) { if (!wait_for_port) {
@ -738,6 +822,78 @@ static size_t communication_delay(void) {
return 0; return 0;
} }
/**
* @brief Wait for receiving a specified amount of bytes
*
* @param buffer The receive buffer
* @param len The maximum receive byte size
* @param ms_timeout the maximum timeout
* @param show_process print how many bytes are received
* @return the number of received bytes
*/
size_t WaitForRawDataTimeout(uint8_t *buffer, size_t len, size_t ms_timeout, bool show_process) {
uint8_t print_counter = 0;
size_t last_pos = 0;
// Add delay depending on the communication channel & speed
if (ms_timeout != (size_t) - 1) {
ms_timeout += communication_delay();
}
__atomic_store_n(&timeout_start_time, msclock(), __ATOMIC_SEQ_CST);
SetCommunicationRawReceiveBuffer(buffer, len);
SetCommunicationReceiveMode(true);
size_t pos = 0;
while (pos < len) {
if (kbd_enter_pressed()) {
// Send anything to stop the transfer
PrintAndLogEx(INFO, "Stopping");
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
// For ms_timeout == -1, pos < len might always be true
// so user need a spectial way to break this loop
if (ms_timeout == (size_t) - 1) {
break;
}
}
pos = __atomic_load_n(&comm_raw_pos, __ATOMIC_SEQ_CST);
// Check the timeout if pos is not updated
if (last_pos == pos) {
uint64_t tmp_clk = __atomic_load_n(&timeout_start_time, __ATOMIC_SEQ_CST);
// If ms_timeout == -1, the loop can only be breaked by pressing Enter or receiving enough data
if ((ms_timeout != (size_t) - 1) && (msclock() - tmp_clk > ms_timeout)) {
break;
}
} else {
// Print process when (print_counter % 64) == 0
if (show_process && (print_counter & 0x3F) == 0) {
PrintAndLogEx(INFO, "[%zu/%zu]", pos, len);
}
}
print_counter++;
last_pos = pos;
msleep(10);
}
if (pos == len && (ms_timeout != (size_t) - 1)) {
// If ms_timeout != -1, when the desired data is received, tell the arm side
// to stop the current process, and wait for some time to make sure the process
// has been stopped.
// If ms_timeout == -1, the user might not want to break the existing process
// on the arm side.
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
msleep(ms_timeout);
}
SetCommunicationReceiveMode(false);
pos = __atomic_load_n(&comm_raw_pos, __ATOMIC_SEQ_CST);
return pos;
}
/** /**
* @brief Waits for a certain response type. This method waits for a maximum of * @brief Waits for a certain response type. This method waits for a maximum of
* ms_timeout milliseconds for a specified response command. * ms_timeout milliseconds for a specified response command.

View file

@ -45,6 +45,8 @@ extern "C" {
#define CMD_BUFFER_SIZE 100 #define CMD_BUFFER_SIZE 100
#endif #endif
#define COMM_RAW_RECEIVE_LEN (1024)
typedef enum { typedef enum {
BIG_BUF, BIG_BUF,
BIG_BUF_EML, BIG_BUF_EML,
@ -96,10 +98,14 @@ void clearCommandBuffer(void);
#define FLASHMODE_SPEED 460800 #define FLASHMODE_SPEED 460800
bool IsCommunicationThreadDead(void); bool IsCommunicationThreadDead(void);
bool SetCommunicationReceiveMode(bool isRawMode);
void SetCommunicationRawReceiveBuffer(uint8_t *buffer, size_t len);
size_t GetCommunicationRawReceiveNum(void);
bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed); bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed);
int TestProxmark(pm3_device_t *dev); int TestProxmark(pm3_device_t *dev);
void CloseProxmark(pm3_device_t *dev); void CloseProxmark(pm3_device_t *dev);
size_t WaitForRawDataTimeout(uint8_t *buffer, size_t len, size_t ms_timeout, bool show_process);
bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout, bool show_warning); bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout, bool show_warning);
bool WaitForResponseTimeout(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout); bool WaitForResponseTimeout(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout);
bool WaitForResponse(uint32_t cmd, PacketResponseNG *response); bool WaitForResponse(uint32_t cmd, PacketResponseNG *response);
@ -111,5 +117,3 @@ bool GetFromDevice(DeviceMemType_t memtype, uint8_t *dest, uint32_t bytes, uint3
} }
#endif #endif
#endif #endif

View file

@ -113,12 +113,19 @@ void setGraphBuf(const uint8_t *src, size_t size) {
RepaintGraphWindow(); RepaintGraphWindow();
} }
// This function assumes that the length of dest array >= g_GraphTraceLen.
// If the length of dest array is less than g_GraphTraceLen, use getFromGraphBufEx(dest, maxLen) instead.
size_t getFromGraphBuf(uint8_t *dest) { size_t getFromGraphBuf(uint8_t *dest) {
return getFromGraphBufEx(dest, g_GraphTraceLen);
}
size_t getFromGraphBufEx(uint8_t *dest, size_t maxLen) {
if (dest == NULL) return 0; if (dest == NULL) return 0;
if (g_GraphTraceLen == 0) return 0; if (g_GraphTraceLen == 0) return 0;
size_t i; size_t i;
for (i = 0; i < g_GraphTraceLen; ++i) { maxLen = (maxLen < g_GraphTraceLen) ? maxLen : g_GraphTraceLen;
for (i = 0; i < maxLen; ++i) {
//trim //trim
if (g_GraphBuffer[i] > 127) g_GraphBuffer[i] = 127; if (g_GraphBuffer[i] > 127) g_GraphBuffer[i] = 127;
if (g_GraphBuffer[i] < -127) g_GraphBuffer[i] = -127; if (g_GraphBuffer[i] < -127) g_GraphBuffer[i] = -127;
@ -387,4 +394,3 @@ bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge) {
} }
return true; return true;
} }

View file

@ -31,6 +31,7 @@ bool HasGraphData(void);
void setGraphBuf(const uint8_t *src, size_t size); void setGraphBuf(const uint8_t *src, size_t size);
void save_restoreGB(uint8_t saveOpt); void save_restoreGB(uint8_t saveOpt);
size_t getFromGraphBuf(uint8_t *dest); size_t getFromGraphBuf(uint8_t *dest);
size_t getFromGraphBufEx(uint8_t *dest, size_t maxLen);
void convertGraphFromBitstream(void); void convertGraphFromBitstream(void);
void convertGraphFromBitstreamEx(int hi, int low); void convertGraphFromBitstreamEx(int hi, int low);
bool isGraphBitstream(void); bool isGraphBitstream(void);
@ -42,7 +43,7 @@ int GetNrzClock(const char *str, bool verbose);
int GetFskClock(const char *str, bool verbose); int GetFskClock(const char *str, bool verbose);
bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge); bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge);
#define MAX_GRAPH_TRACE_LEN (40000 * 8) #define MAX_GRAPH_TRACE_LEN (40000 * 32)
#define GRAPH_SAVE 1 #define GRAPH_SAVE 1
#define GRAPH_RESTORE 0 #define GRAPH_RESTORE 0

View file

@ -37,10 +37,7 @@ AT91SAM7S256 USB Device Port
#define AT91C_EP_IN 2 // cfg bulk in #define AT91C_EP_IN 2 // cfg bulk in
#define AT91C_EP_NOTIFY 3 // cfg cdc notification interrup #define AT91C_EP_NOTIFY 3 // cfg cdc notification interrup
#define AT91C_EP_CONTROL_SIZE 8 // The endpoint size is defined in usb_cdc.h
#define AT91C_EP_OUT_SIZE 64
#define AT91C_EP_IN_SIZE 64
// Section: USB Descriptors // Section: USB Descriptors
#define USB_DESCRIPTOR_DEVICE 0x01 // DescriptorType for a Device Descriptor. #define USB_DESCRIPTOR_DEVICE 0x01 // DescriptorType for a Device Descriptor.
@ -114,6 +111,7 @@ AT91SAM7S256 USB Device Port
#define SET_LINE_CODING 0x2021 #define SET_LINE_CODING 0x2021
#define SET_CONTROL_LINE_STATE 0x2221 #define SET_CONTROL_LINE_STATE 0x2221
static bool isAsyncRequestFinished = false;
static AT91PS_UDP pUdp = AT91C_BASE_UDP; static AT91PS_UDP pUdp = AT91C_BASE_UDP;
static uint8_t btConfiguration = 0; static uint8_t btConfiguration = 0;
static uint8_t btConnection = 0; static uint8_t btConnection = 0;
@ -127,7 +125,7 @@ static const char devDescriptor[] = {
2, // Device Class: Communication Device Class 2, // Device Class: Communication Device Class
0, // Device Subclass: CDC class sub code ACM [ice 0x02 = win10 virtual comport ] 0, // Device Subclass: CDC class sub code ACM [ice 0x02 = win10 virtual comport ]
0, // Device Protocol: CDC Device protocol (unused) 0, // Device Protocol: CDC Device protocol (unused)
AT91C_EP_CONTROL_SIZE, // MaxPacketSize0 AT91C_USB_EP_CONTROL_SIZE, // MaxPacketSize0
0xc4, 0x9a, // Vendor ID [0x9ac4 = J. Westhues] 0xc4, 0x9a, // Vendor ID [0x9ac4 = J. Westhues]
0x8f, 0x4b, // Product ID [0x4b8f = Proxmark-3 RFID Instrument] 0x8f, 0x4b, // Product ID [0x4b8f = Proxmark-3 RFID Instrument]
0x00, 0x01, // BCD Device release number (1.00) 0x00, 0x01, // BCD Device release number (1.00)
@ -217,7 +215,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP03_IN, // EndpointAddress: Endpoint 03 - IN _EP03_IN, // EndpointAddress: Endpoint 03 - IN
_INTERRUPT, // Attributes _INTERRUPT, // Attributes
AT91C_EP_CONTROL_SIZE, 0x00, // MaxPacket Size: EP0 - 8 AT91C_USB_EP_CONTROL_SIZE, 0x00, // MaxPacket Size: EP0 - 8
0xFF, // Interval polling 0xFF, // Interval polling
@ -238,7 +236,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP01_OUT, // Endpoint Address: Endpoint 01 - OUT _EP01_OUT, // Endpoint Address: Endpoint 01 - OUT
_BULK, // Attributes: BULK _BULK, // Attributes: BULK
AT91C_EP_OUT_SIZE, 0x00, // MaxPacket Size: 64 bytes AT91C_USB_EP_OUT_SIZE, 0x00, // MaxPacket Size: 64 bytes
0, // Interval: ignored for bulk 0, // Interval: ignored for bulk
/* Endpoint descriptor */ /* Endpoint descriptor */
@ -246,7 +244,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP02_IN, // Endpoint Address: Endpoint 02 - IN _EP02_IN, // Endpoint Address: Endpoint 02 - IN
_BULK, // Attribute: BULK _BULK, // Attribute: BULK
AT91C_EP_IN_SIZE, 0x00, // MaxPacket Size: 64 bytes AT91C_USB_EP_IN_SIZE, 0x00, // MaxPacket Size: 64 bytes
0 // Interval: ignored for bulk 0 // Interval: ignored for bulk
}; };
@ -638,6 +636,10 @@ bool usb_poll(void) {
return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank); return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);
} }
inline uint16_t usb_available_length(void) {
return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16);
}
/** /**
In github PR #129, some users appears to get a false positive from In github PR #129, some users appears to get a false positive from
usb_poll, which returns true, but the usb_read operation usb_poll, which returns true, but the usb_read operation
@ -671,7 +673,7 @@ uint32_t usb_read(uint8_t *data, size_t len) {
if (pUdp->UDP_CSR[AT91C_EP_OUT] & bank) { if (pUdp->UDP_CSR[AT91C_EP_OUT] & bank) {
packetSize = (pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16; packetSize = ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16);
packetSize = MIN(packetSize, len); packetSize = MIN(packetSize, len);
len -= packetSize; len -= packetSize;
while (packetSize--) while (packetSize--)
@ -727,7 +729,7 @@ uint32_t usb_read_ng(uint8_t *data, size_t len) {
if ((pUdp->UDP_CSR[AT91C_EP_OUT] & bank)) { if ((pUdp->UDP_CSR[AT91C_EP_OUT] & bank)) {
uint32_t available = (pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16; uint32_t available = ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16);
packetSize = MIN(available, len); packetSize = MIN(available, len);
available -= packetSize; available -= packetSize;
len -= packetSize; len -= packetSize;
@ -770,7 +772,7 @@ int usb_write(const uint8_t *data, const size_t len) {
// send first chunk // send first chunk
cpt = MIN(length, AT91C_EP_IN_SIZE); cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt; length -= cpt;
while (cpt--) { while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++; pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
@ -781,7 +783,7 @@ int usb_write(const uint8_t *data, const size_t len) {
while (length) { while (length) {
// Send next chunk // Send next chunk
cpt = MIN(length, AT91C_EP_IN_SIZE); cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt; length -= cpt;
while (cpt--) { while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++; pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
@ -809,7 +811,7 @@ int usb_write(const uint8_t *data, const size_t len) {
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {}; while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
if (len % AT91C_EP_IN_SIZE == 0) { if (len % AT91C_USB_EP_IN_SIZE == 0) {
// like AT91F_USB_SendZlp(), in non ping-pong mode // like AT91F_USB_SendZlp(), in non ping-pong mode
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {}; while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {};
@ -821,6 +823,117 @@ int usb_write(const uint8_t *data, const size_t len) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_start
* \brief Start async write process
* \return PM3_EIO if USB is invalid, PM3_SUCCESS if it is ready for write
*
* This function checks if the USB is connected, and wait until the FIFO
* is ready to be filled.
*
* Warning: usb_write() should not be called between
* async_usb_write_start() and async_usb_write_stop().
*----------------------------------------------------------------------------
*/
int async_usb_write_start(void) {
if (!usb_check()) return PM3_EIO;
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
if (!usb_check()) return PM3_EIO;
}
isAsyncRequestFinished = false;
return PM3_SUCCESS;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_pushByte
* \brief Push one byte to the FIFO of IN endpoint (time-critical)
*
* This function simply push a byte to the FIFO of IN endpoint.
* The FIFO size is AT91C_USB_EP_IN_SIZE. Make sure this function is not called
* over AT91C_USB_EP_IN_SIZE times between each async_usb_write_requestWrite().
*----------------------------------------------------------------------------
*/
inline void async_usb_write_pushByte(uint8_t data) {
pUdp->UDP_FDR[AT91C_EP_IN] = data;
isAsyncRequestFinished = false;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_requestWrite
* \brief Request a write operation (time-critical)
* \return false if the last write request is not finished, true if success
*
* This function requests a write operation from FIFO to the USB bus,
* and switch the internal banks of FIFO. It doesn't wait for the end of
* transmission from FIFO to the USB bus.
*
* Note: This function doesn't check if the usb is valid, as it is
* time-critical.
*----------------------------------------------------------------------------
*/
inline bool async_usb_write_requestWrite(void) {
// check if last request is finished
if (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
return false;
}
// clear transmission completed flag
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
// start of transmission
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
// hack: no need to wait if UDP_CSR and UDP_FDR are not used immediately.
// while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) {};
isAsyncRequestFinished = true;
return true;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_stop
* \brief Stop async write process
* \return PM3_EIO if USB is invalid, PM3_SUCCESS if data is written
*
* This function makes sure the data left in the FIFO is written to the
* USB bus.
*
* Warning: usb_write() should not be called between
* async_usb_write_start() and async_usb_write_stop().
*----------------------------------------------------------------------------
*/
int async_usb_write_stop(void) {
// Wait for the end of transfer
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
if (!usb_check()) return PM3_EIO;
}
// clear transmission completed flag
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
// FIFO is not empty, request a write in non-ping-pong mode
if (isAsyncRequestFinished == false) {
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
if (!usb_check()) return PM3_EIO;
}
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
}
return PM3_SUCCESS;
}
/* /*
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
* \fn AT91F_USB_SendData * \fn AT91F_USB_SendData
@ -831,7 +944,7 @@ void AT91F_USB_SendData(AT91PS_UDP pudp, const char *pData, uint32_t length) {
AT91_REG csr; AT91_REG csr;
do { do {
uint32_t cpt = MIN(length, AT91C_EP_CONTROL_SIZE); uint32_t cpt = MIN(length, AT91C_USB_EP_CONTROL_SIZE);
length -= cpt; length -= cpt;
while (cpt--) while (cpt--)

View file

@ -23,13 +23,22 @@
#include "common.h" #include "common.h"
#include "at91sam7s512.h" #include "at91sam7s512.h"
#define AT91C_USB_EP_CONTROL_SIZE 8
#define AT91C_USB_EP_OUT_SIZE 64
#define AT91C_USB_EP_IN_SIZE 64
void usb_disable(void); void usb_disable(void);
void usb_enable(void); void usb_enable(void);
bool usb_check(void); bool usb_check(void);
bool usb_poll(void); bool usb_poll(void);
uint16_t usb_available_length(void);
bool usb_poll_validate_length(void); bool usb_poll_validate_length(void);
uint32_t usb_read(uint8_t *data, size_t len); uint32_t usb_read(uint8_t *data, size_t len);
int usb_write(const uint8_t *data, const size_t len); int usb_write(const uint8_t *data, const size_t len);
int async_usb_write_start(void);
void async_usb_write_pushByte(uint8_t data);
bool async_usb_write_requestWrite(void);
int async_usb_write_stop(void);
uint32_t usb_read_ng(uint8_t *data, size_t len); uint32_t usb_read_ng(uint8_t *data, size_t len);
void usb_update_serial(uint64_t newSerialNumber); void usb_update_serial(uint64_t newSerialNumber);

View file

@ -196,4 +196,21 @@ extern bool g_tearoff_enabled;
#define CLEAR_BIT(data, i) *(data + (i / 8)) &= ~(1 << (7 - (i % 8))) #define CLEAR_BIT(data, i) *(data + (i / 8)) &= ~(1 << (7 - (i % 8)))
#define FLIP_BIT(data, i) *(data + (i / 8)) ^= (1 << (7 - (i % 8))) #define FLIP_BIT(data, i) *(data + (i / 8)) ^= (1 << (7 - (i % 8)))
// time for decompressing and loading the image to the FPGA
#define FPGA_LOAD_WAIT_TIME (1500)
// GCC extension
// from client/deps/tinycbor/compilersupport_p.h
#ifdef __GNUC__
#ifndef likely
# define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
# define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
#endif #endif

View file

@ -274,6 +274,17 @@ typedef struct {
uint8_t data[]; uint8_t data[];
} PACKED lf_hitag_t; } PACKED lf_hitag_t;
// For CMD_LF_SNIFF_RAW_ADC and CMD_LF_ACQ_RAW_ADC
#define LF_SAMPLES_BITS 30
#define MAX_LF_SAMPLES ((((uint32_t)1u) << LF_SAMPLES_BITS) - 1)
typedef struct {
// 64KB SRAM -> 524288 bits(max sample num) < 2^30
uint32_t samples : LF_SAMPLES_BITS;
bool realtime : 1;
bool verbose : 1;
} PACKED lf_sample_payload_t;
typedef struct { typedef struct {
uint8_t blockno; uint8_t blockno;
uint8_t keytype; uint8_t keytype;