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

View file

@ -493,7 +493,7 @@ void FpgaDownloadAndGo(int bitstream_version) {
#endif
// 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);

View file

@ -27,6 +27,7 @@
#include "lfdemod.h"
#include "string.h" // memset
#include "appmain.h" // print stack
#include "usb_cdc.h" // real-time sampling
/*
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
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
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.
// interruptible only when logging not yet triggered
if ((checked >= 4000) && trigger_hit == false) {
if (trigger_hit == false && (checked >= 4000)) {
if (data_available()) {
checked = -1;
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) {
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();
// threshold either high or low values 128 = center 0. if trigger = 178
@ -337,10 +338,9 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
}
continue;
}
trigger_hit = true;
}
trigger_hit = true;
if (samples_to_skip > 0) {
samples_to_skip--;
continue;
@ -370,6 +370,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
}
return data.numbits;
}
/**
* @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
@ -424,6 +425,123 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol) {
BigBuf_Clear_ext(false);
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.
* @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);
/**
* 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.
* @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;
(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();
}

View file

@ -298,6 +298,8 @@ int BUTTON_HELD(int ms) {
return BUTTON_ERROR;
}
// This function returns false if no data is available or
// the USB connection is invalid.
bool data_available(void) {
#ifdef WITH_FPC_USART_HOST
return usb_poll_validate_length() || (usart_rxdata_available() > 0);
@ -305,3 +307,14 @@ bool data_available(void) {
return usb_poll_validate_length();
#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_HELD(int ms);
bool data_available(void);
bool data_available_fast(void);
#endif

View file

@ -564,7 +564,11 @@ static int Cmdmandecoderaw(const char *Cmd) {
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
int high = 0, low = 0;
@ -579,6 +583,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
if (high > 7 || low < 0) {
PrintAndLogEx(ERR, "Error: please first raw demod then manchester raw decode");
free(bits);
return PM3_ESOFT;
}
@ -587,6 +592,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
uint16_t err_cnt = manrawdecode(bits, &size, invert, &offset);
if (err_cnt > max_err) {
PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT;
}
@ -611,6 +617,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
}
setDemodBuff(bits, size, 0);
setClockGrid(g_DemodClock * 2, g_DemodStartIdx);
free(bits);
return PM3_SUCCESS;
}
@ -651,17 +658,27 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
return PM3_ESOFT;
}
uint8_t bits[MAX_DEMOD_BUF_LEN] = {0};
size_t size = sizeof(bits);
if (!getDemodBuff(bits, &size)) return PM3_ESOFT;
uint8_t *bits = calloc(MAX_DEMOD_BUF_LEN, sizeof(uint8_t));
if (bits == NULL) {
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);
if (err_cnt < 0) {
PrintAndLogEx(ERR, "Error during decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT;
}
if (err_cnt > max_err) {
PrintAndLogEx(ERR, "Too many errors attempting to decode " _RED_("%i"), err_cnt);
free(bits);
return PM3_ESOFT;
}
@ -674,6 +691,7 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
setDemodBuff(bits, size, 0);
setClockGrid(g_DemodClock * 2, g_DemodStartIdx + g_DemodClock * offset);
free(bits);
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) {
//ask raw demod g_GraphBuffer first
uint8_t bs[MAX_DEMOD_BUF_LEN];
size_t size = getFromGraphBuf(bs);
uint8_t *bs = calloc(MAX_DEMOD_BUF_LEN, sizeof(uint8_t));
if (bs == NULL) {
PrintAndLogEx(FAILED, "failed to allocate memory");
return PM3_EMALLOC;
}
size_t size = getFromGraphBufEx(bs, MAX_DEMOD_BUF_LEN);
if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf");
free(bs);
return PM3_ESOFT;
}
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);
if (errCnt < 0 || errCnt > maxErr) {
PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk);
free(bs);
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);
if (errCnt < 0) {
if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt);
free(bs);
return PM3_ESOFT;
}
if (errCnt > maxErr) {
if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode too many errors: %d", errCnt);
free(bs);
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));
printDemodBuff(offset, false, false, false);
}
free(bs);
return PM3_SUCCESS;
}
@ -1011,7 +1039,11 @@ static int CmdUndecimate(const char *Cmd) {
CLIParserFree(ctx);
//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;
while (g_index < g_GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) {
int count = 0;
@ -1028,6 +1060,7 @@ static int CmdUndecimate(const char *Cmd) {
memcpy(g_GraphBuffer, swap, s_index * sizeof(int));
g_GraphTraceLen = s_index;
RepaintGraphWindow();
free(swap);
return PM3_SUCCESS;
}
@ -1707,7 +1740,11 @@ int CmdHpf(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, true);
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);
removeSignalOffset(bits, size);
// push it back to graph
@ -1716,6 +1753,7 @@ int CmdHpf(const char *Cmd) {
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
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;
}
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 (verbose) PrintAndLogEx(INFO, "Unpacking...");
BitstreamOut_t bout = { got, bits_per_sample * n, 0};
uint32_t j = 0;
for (j = 0; j * bits_per_sample < n * 8 && j * bits_per_sample < MAX_GRAPH_TRACE_LEN * 8; j++) {
BitstreamOut_t bout = {data, bits_per_sample * sample_num, 0};
size_t j = 0;
for (j = 0; j < max_num; j++) {
uint8_t sample = getByte(bits_per_sample, &bout);
g_GraphBuffer[j] = ((int) sample) - 127;
}
g_GraphTraceLen = j;
if (verbose) PrintAndLogEx(INFO, "Unpacked %d samples", j);
if (verbose) PrintAndLogEx(INFO, "Unpacked %zu samples", j);
} else {
for (uint32_t j = 0; j < n; j++) {
g_GraphBuffer[j] = ((int)got[j]) - 127;
for (size_t j = 0; j < max_num; j++) {
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);
// set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size);
free(bits);
setClockGrid(0, 0);
g_DemodBufferLen = 0;
RepaintGraphWindow();
return PM3_SUCCESS;
}
@ -2094,12 +2145,17 @@ static int CmdLoad(const char *Cmd) {
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", g_GraphTraceLen);
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);
removeSignalOffset(bits, size);
setGraphBuf(bits, size);
computeSignalProperties(bits, size);
free(bits);
}
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);
// set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
return PM3_SUCCESS;
}
@ -2377,12 +2438,17 @@ static int CmdDirectionalThreshold(const char *Cmd) {
directionalThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down);
// 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);
// set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
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);
// set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
return PM3_SUCCESS;
}
@ -2733,11 +2804,16 @@ static int CmdDataIIR(const char *Cmd) {
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);
// set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
return PM3_SUCCESS;
}
@ -3360,11 +3436,16 @@ static int CmdCenterThreshold(const char *Cmd) {
centerThreshold(g_GraphBuffer, g_GraphBuffer, g_GraphTraceLen, up, down);
// 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);
// set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
return PM3_SUCCESS;
}
@ -3405,11 +3486,16 @@ static int CmdEnvelope(const char *Cmd) {
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);
// set signal properties low/high/mean/amplitude and is_noice detection
computeSignalProperties(bits, size);
RepaintGraphWindow();
free(bits);
return PM3_SUCCESS;
}
@ -3584,4 +3670,3 @@ int CmdData(const char *Cmd) {
clearCommandBuffer();
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 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);
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 "pm3_cmd.h" // for LF_CMDREAD_MAX_EXTRA_SYMBOLS
static bool gs_lf_threshold_set = false;
static int CmdHelp(const char *Cmd);
// Informative user function.
@ -433,7 +431,11 @@ int CmdFlexdemod(const char *Cmd) {
#endif
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);
size_t size = g_GraphTraceLen;
@ -454,6 +456,7 @@ int CmdFlexdemod(const char *Cmd) {
if (start == size - LONG_WAIT) {
PrintAndLogEx(WARNING, "nothing to wait for");
free(data);
return PM3_ENODATA;
}
@ -497,6 +500,7 @@ int CmdFlexdemod(const char *Cmd) {
}
}
RepaintGraphWindow();
free(data);
return PM3_SUCCESS;
}
@ -644,7 +648,6 @@ int CmdLFConfig(const char *Cmd) {
config.divisor = LF_DIVISOR_125;
config.samples_to_skip = 0;
config.trigger_threshold = 0;
gs_lf_threshold_set = false;
}
if (use_125)
@ -689,44 +692,83 @@ int CmdLFConfig(const char *Cmd) {
if (trigg > -1) {
config.trigger_threshold = trigg;
gs_lf_threshold_set = (config.trigger_threshold > 0);
}
config.samples_to_skip = skip;
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;
struct p {
uint32_t samples : 31;
bool verbose : 1;
} PACKED;
struct p payload;
lf_sample_payload_t payload = {0};
payload.realtime = realtime;
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();
SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (gs_lf_threshold_set) {
WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp);
} else {
if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) {
PrintAndLogEx(WARNING, "(lf_read) command execution time out");
return PM3_ETIMEOUT;
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));
PacketResponseNG resp;
if (is_trigger_threshold_set) {
WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp);
} else {
if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) {
PrintAndLogEx(WARNING, "(lf_read) command execution time out");
return PM3_ETIMEOUT;
}
}
// response is number of bits read
uint32_t size = (resp.data.asDwords[0] / bits_per_sample);
getSamples(size, verbose);
}
// response is number of bits read
uint32_t size = (resp.data.asDwords[0] / 8);
getSamples(size, verbose);
return PM3_SUCCESS;
}
int lf_read(bool verbose, uint64_t samples) {
return lf_read_internal(false, verbose, samples);
}
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;
CLIParserInit(&ctx, "lf read",
"Sniff low frequency signal.\n"
@ -734,6 +776,7 @@ int CmdLFRead(const char *Cmd) {
_CYAN_(" - use ") _YELLOW_("`data plot`") _CYAN_(" to look at it"),
"lf read -v -s 12000 --> collect 12000 samples\n"
"lf read -s 3000 -@ --> oscilloscope style \n"
"lf read -r --> use real-time mode \n"
);
void *argtable[] = {
@ -741,57 +784,100 @@ int CmdLFRead(const char *Cmd) {
arg_u64_0("s", "samples", "<dec>", "number of samples to collect"),
arg_lit0("v", "verbose", "verbose output"),
arg_lit0("@", NULL, "continuous reading mode"),
arg_lit0("r", "realtime", "real-time reading mode"),
arg_param_end
};
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 cm = arg_get_lit(ctx, 3);
bool realtime = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (g_session.pm3_present == false)
return PM3_ENOTTY;
if (cm) {
if (realtime && samples == 0) {
samples = MAX_GRAPH_TRACE_LEN;
}
if (cm || realtime) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
}
int ret = PM3_SUCCESS;
do {
ret = lf_read(verbose, samples);
ret = lf_read_internal(realtime, verbose, samples);
} while (cm && kbd_enter_pressed() == false);
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;
struct p {
uint32_t samples : 31;
bool verbose : 1;
} PACKED payload;
payload.samples = (samples & 0xFFFF);
lf_sample_payload_t payload = {0};
payload.realtime = realtime;
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();
SendCommandNG(CMD_LF_SNIFF_RAW_ADC, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (gs_lf_threshold_set) {
WaitForResponse(CMD_LF_SNIFF_RAW_ADC, &resp);
} else {
if (WaitForResponseTimeout(CMD_LF_SNIFF_RAW_ADC, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "(lf_read) command execution time out");
return PM3_ETIMEOUT;
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));
PacketResponseNG resp;
if (is_trigger_threshold_set) {
WaitForResponse(CMD_LF_SNIFF_RAW_ADC, &resp);
} else {
if (WaitForResponseTimeout(CMD_LF_SNIFF_RAW_ADC, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "(lf_read) command execution time out");
return PM3_ETIMEOUT;
}
}
// response is number of bits read
uint32_t size = (resp.data.asDwords[0] / bits_per_sample);
getSamples(size, verbose);
}
// response is number of bits read
uint32_t size = (resp.data.asDwords[0] / 8);
getSamples(size, verbose);
return PM3_SUCCESS;
}
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;
CLIParserInit(&ctx, "lf sniff",
"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"),
"lf sniff -v\n"
"lf sniff -s 3000 -@ --> oscilloscope style \n"
"lf sniff -r --> use real-time mode \n"
);
void *argtable[] = {
@ -809,24 +896,30 @@ int CmdLFSniff(const char *Cmd) {
arg_u64_0("s", "samples", "<dec>", "number of samples to collect"),
arg_lit0("v", "verbose", "verbose output"),
arg_lit0("@", NULL, "continuous sniffing mode"),
arg_lit0("r", "realtime", "real-time sniffing mode"),
arg_param_end
};
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 cm = arg_get_lit(ctx, 3);
bool realtime = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (g_session.pm3_present == false)
return PM3_ENOTTY;
if (cm) {
if (realtime && samples == 0) {
samples = MAX_GRAPH_TRACE_LEN;
}
if (cm || realtime) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
}
int ret = PM3_SUCCESS;
do {
ret = lf_sniff(verbose, samples);
} while (cm && !kbd_enter_pressed());
ret = lf_sniff(realtime, verbose, samples);
} while (cm && kbd_enter_pressed() == false);
return ret;
}

View file

@ -40,8 +40,8 @@ int CmdLFSniff(const char *Cmd);
int CmdVchDemod(const char *Cmd);
int CmdLFfind(const char *Cmd);
int lf_read(bool verbose, uint32_t samples);
int lf_sniff(bool verbose, uint32_t samples);
int lf_read(bool verbose, uint64_t samples);
int lf_sniff(bool realtime, bool verbose, uint64_t samples);
int lf_config(sample_config *config);
int lf_getconfig(sample_config *config);
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
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);
if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
free(bits);
return PM3_ESOFT;
}
//get binary from fsk wave
@ -141,11 +146,13 @@ int demodHID(bool verbose) {
else
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx);
free(bits);
return PM3_ESOFT;
}
setDemodBuff(bits, size, idx);
setClockGrid(50, waveIdx + (idx * 50));
free(bits);
if (hi2 == 0 && hi == 0 && lo == 0) {
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
// 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);
uint8_t rawbits[4096] = {0};
@ -446,6 +450,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
count = 0;
}
}
free(data);
if (rawbit > 0) {
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) {
(void) verbose; // unused so far
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);
if (size < 65) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox not enough samples in GraphBuffer");
free(bits);
return PM3_ESOFT;
}
//get binary from fsk wave
@ -93,6 +98,7 @@ int demodIOProx(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - IO prox error demoding fsk %d", idx);
}
}
free(bits);
return PM3_ESOFT;
}
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);
if (size > 92) PrintAndLogEx(DEBUG, "%s", sprint_bytebits_bin_break(bits, 92, 16));
}
free(bits);
return PM3_ESOFT;
}
@ -156,6 +163,7 @@ int demodIOProx(bool verbose) {
printDemodBuff(0, false, false, true);
printDemodBuff(0, false, false, false);
}
free(bits);
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));
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) {
(void) verbose; // unused so far
//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);
if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox not enough samples");
free(bits);
return PM3_ESOFT;
}
@ -125,6 +130,7 @@ int demodParadox(bool verbose, bool oldChksum) {
else
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox error demoding fsk %d", idx);
free(bits);
return PM3_ESOFT;
}
@ -175,6 +181,7 @@ int demodParadox(bool verbose, bool oldChksum) {
if (hi2 == 0 && hi == 0 && lo == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Paradox no value found");
free(bits);
return PM3_ESOFT;
}
@ -230,6 +237,7 @@ int demodParadox(bool verbose, bool oldChksum) {
printDemodBuff(0, false, false, false);
}
free(bits);
return PM3_SUCCESS;
}
@ -500,5 +508,3 @@ int detectParadox(uint8_t *dest, size_t *size, int *wave_start_idx) {
return (int)idx;
}

View file

@ -43,10 +43,15 @@ static int CmdHelp(const char *Cmd);
int demodPyramid(bool verbose) {
(void) verbose; // unused so far
//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);
if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid not enough samples");
free(bits);
return PM3_ESOFT;
}
//get binary from fsk wave
@ -65,6 +70,7 @@ int demodPyramid(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: size not correct: %zu", size);
else
PrintAndLogEx(DEBUG, "DEBUG: Error - Pyramid: error demoding fsk idx: %d", idx);
free(bits);
return PM3_ESOFT;
}
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);
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);
free(bits);
return PM3_ESOFT;
}
@ -181,6 +188,7 @@ int demodPyramid(bool verbose) {
printDemodBuff(0, false, false, false);
}
free(bits);
return PM3_SUCCESS;
}
@ -507,4 +515,3 @@ int detectPyramid(uint8_t *dest, size_t *size, int *waveStartIdx) {
return (int)startIdx;
}

View file

@ -41,6 +41,10 @@ capabilities_t g_pm3_capabilities;
static pthread_t communication_thread;
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.
static PacketCommandOLD txBuffer;
@ -346,6 +350,8 @@ __attribute__((force_align_arg_pointer))
bool commfailed = false;
PacketResponseNG rx;
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__)
disableAppNap("Proxmark3 polling UART");
@ -368,136 +374,175 @@ __attribute__((force_align_arg_pointer))
break;
}
res = uart_receive(sp, (uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), &rxlen);
bool is_receiving_raw = __atomic_load_n(&comm_raw_mode, __ATOMIC_SEQ_CST);
if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) {
rx.magic = rx_raw.pre.magic;
uint16_t length = rx_raw.pre.length;
rx.ng = rx_raw.pre.ng;
rx.status = rx_raw.pre.status;
rx.cmd = rx_raw.pre.cmd;
if (rx.magic == RESPONSENG_PREAMBLE_MAGIC) { // New style NG reply
if (length > PM3_CMD_DATA_SIZE) {
PrintAndLogEx(WARNING, "Received packet frame with incompatible length: 0x%04x", length);
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
if ((!error) && (length > 0)) { // Get the variable length payload
// 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.data, length, &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != length)) {
PrintAndLogEx(WARNING, "Received packet frame with variable part too short? %d/%d", rxlen, length);
if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) {
rx.magic = rx_raw.pre.magic;
uint16_t length = rx_raw.pre.length;
rx.ng = rx_raw.pre.ng;
rx.status = rx_raw.pre.status;
rx.cmd = rx_raw.pre.cmd;
if (rx.magic == RESPONSENG_PREAMBLE_MAGIC) { // New style NG reply
if (length > PM3_CMD_DATA_SIZE) {
PrintAndLogEx(WARNING, "Received packet frame with incompatible length: 0x%04x", length);
error = true;
} else {
}
if (rx.ng) { // Received a valid NG frame
memcpy(&rx.data, &rx_raw.data, length);
rx.length = length;
if ((rx.cmd == g_conn.last_command) && (rx.status == PM3_SUCCESS)) {
ACK_received = true;
}
if ((!error) && (length > 0)) { // Get the variable length payload
res = uart_receive(sp, (uint8_t *)&rx_raw.data, length, &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != length)) {
PrintAndLogEx(WARNING, "Received packet frame with variable part too short? %d/%d", rxlen, length);
error = true;
} else {
uint64_t arg[3];
if (length < sizeof(arg)) {
PrintAndLogEx(WARNING, "Received MIX packet frame with incompatible length: 0x%04x", length);
error = true;
}
if (!error) { // Received a valid MIX frame
memcpy(arg, &rx_raw.data, sizeof(arg));
rx.oldarg[0] = arg[0];
rx.oldarg[1] = arg[1];
rx.oldarg[2] = arg[2];
memcpy(&rx.data, ((uint8_t *)&rx_raw.data) + sizeof(arg), length - sizeof(arg));
rx.length = length - sizeof(arg);
if (rx.cmd == CMD_ACK) {
if (rx.ng) { // Received a valid NG frame
memcpy(&rx.data, &rx_raw.data, length);
rx.length = length;
if ((rx.cmd == g_conn.last_command) && (rx.status == PM3_SUCCESS)) {
ACK_received = true;
}
} else {
uint64_t arg[3];
if (length < sizeof(arg)) {
PrintAndLogEx(WARNING, "Received MIX packet frame with incompatible length: 0x%04x", length);
error = true;
}
if (!error) { // Received a valid MIX frame
memcpy(arg, &rx_raw.data, sizeof(arg));
rx.oldarg[0] = arg[0];
rx.oldarg[1] = arg[1];
rx.oldarg[2] = arg[2];
memcpy(&rx.data, ((uint8_t *)&rx_raw.data) + sizeof(arg), length - sizeof(arg));
rx.length = length - sizeof(arg);
if (rx.cmd == CMD_ACK) {
ACK_received = true;
}
}
}
}
}
} else if ((!error) && (length == 0)) { // we received an empty frame
if (rx.ng)
rx.length = 0; // set received length to 0
else { // old frames can't be empty
PrintAndLogEx(WARNING, "Received empty MIX packet frame (length: 0x00)");
error = true;
}
}
if (!error) { // Get the postamble
res = uart_receive(sp, (uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseNGPostamble))) {
PrintAndLogEx(WARNING, "Received packet frame without postamble");
error = true;
}
}
if (!error) { // Check CRC, accept MAGIC as placeholder
rx.crc = rx_raw.foopost.crc;
if (rx.crc != RESPONSENG_POSTAMBLE_MAGIC) {
uint8_t first, second;
compute_crc(CRC_14443_A, (uint8_t *)&rx_raw, sizeof(PacketResponseNGPreamble) + length, &first, &second);
if ((first << 8) + second != rx.crc) {
PrintAndLogEx(WARNING, "Received packet frame with invalid CRC %02X%02X <> %04X", first, second, rx.crc);
} else if ((!error) && (length == 0)) { // we received an empty frame
if (rx.ng)
rx.length = 0; // set received length to 0
else { // old frames can't be empty
PrintAndLogEx(WARNING, "Received empty MIX packet frame (length: 0x00)");
error = true;
}
}
}
if (!error) { // Received a valid OLD frame
#ifdef COMMS_DEBUG
PrintAndLogEx(NORMAL, "Receiving %s:", rx.ng ? "NG" : "MIX");
#endif
#ifdef COMMS_DEBUG_RAW
print_hex_break((uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), 32);
print_hex_break((uint8_t *)&rx_raw.data, rx_raw.pre.length, 32);
print_hex_break((uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), 32);
#endif
PacketResponseReceived(&rx);
}
} else { // Old style reply
PacketResponseOLD rx_old;
memcpy(&rx_old, &rx_raw.pre, sizeof(PacketResponseNGPreamble));
res = uart_receive(sp, ((uint8_t *)&rx_old) + sizeof(PacketResponseNGPreamble), sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble), &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble))) {
PrintAndLogEx(WARNING, "Received packet OLD frame with payload too short? %d/%zu", rxlen, sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble));
error = true;
}
if (!error) {
if (!error) { // Get the postamble
res = uart_receive(sp, (uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseNGPostamble))) {
PrintAndLogEx(WARNING, "Received packet frame without postamble");
error = true;
}
}
if (!error) { // Check CRC, accept MAGIC as placeholder
rx.crc = rx_raw.foopost.crc;
if (rx.crc != RESPONSENG_POSTAMBLE_MAGIC) {
uint8_t first, second;
compute_crc(CRC_14443_A, (uint8_t *)&rx_raw, sizeof(PacketResponseNGPreamble) + length, &first, &second);
if ((first << 8) + second != rx.crc) {
PrintAndLogEx(WARNING, "Received packet frame with invalid CRC %02X%02X <> %04X", first, second, rx.crc);
error = true;
}
}
}
if (!error) { // Received a valid OLD frame
#ifdef COMMS_DEBUG
PrintAndLogEx(NORMAL, "Receiving OLD:");
PrintAndLogEx(NORMAL, "Receiving %s:", rx.ng ? "NG" : "MIX");
#endif
#ifdef COMMS_DEBUG_RAW
print_hex_break((uint8_t *)&rx_old.cmd, sizeof(rx_old.cmd), 32);
print_hex_break((uint8_t *)&rx_old.arg, sizeof(rx_old.arg), 32);
print_hex_break((uint8_t *)&rx_old.d, sizeof(rx_old.d), 32);
print_hex_break((uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), 32);
print_hex_break((uint8_t *)&rx_raw.data, rx_raw.pre.length, 32);
print_hex_break((uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), 32);
#endif
rx.ng = false;
rx.magic = 0;
rx.status = 0;
rx.crc = 0;
rx.cmd = rx_old.cmd;
rx.oldarg[0] = rx_old.arg[0];
rx.oldarg[1] = rx_old.arg[1];
rx.oldarg[2] = rx_old.arg[2];
rx.length = PM3_CMD_DATA_SIZE;
memcpy(&rx.data, &rx_old.d, rx.length);
PacketResponseReceived(&rx);
if (rx.cmd == CMD_ACK) {
ACK_received = true;
PacketResponseReceived(&rx);
}
} else { // Old style reply
PacketResponseOLD rx_old;
memcpy(&rx_old, &rx_raw.pre, sizeof(PacketResponseNGPreamble));
res = uart_receive(sp, ((uint8_t *)&rx_old) + sizeof(PacketResponseNGPreamble), sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble), &rxlen);
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble))) {
PrintAndLogEx(WARNING, "Received packet OLD frame with payload too short? %d/%zu", rxlen, sizeof(PacketResponseOLD) - sizeof(PacketResponseNGPreamble));
error = true;
}
if (!error) {
#ifdef COMMS_DEBUG
PrintAndLogEx(NORMAL, "Receiving OLD:");
#endif
#ifdef COMMS_DEBUG_RAW
print_hex_break((uint8_t *)&rx_old.cmd, sizeof(rx_old.cmd), 32);
print_hex_break((uint8_t *)&rx_old.arg, sizeof(rx_old.arg), 32);
print_hex_break((uint8_t *)&rx_old.d, sizeof(rx_old.d), 32);
#endif
rx.ng = false;
rx.magic = 0;
rx.status = 0;
rx.crc = 0;
rx.cmd = rx_old.cmd;
rx.oldarg[0] = rx_old.arg[0];
rx.oldarg[1] = rx_old.arg[1];
rx.oldarg[2] = rx_old.arg[2];
rx.length = PM3_CMD_DATA_SIZE;
memcpy(&rx.data, &rx_old.d, rx.length);
PacketResponseReceived(&rx);
if (rx.cmd == CMD_ACK) {
ACK_received = true;
}
}
}
}
} else {
if (rxlen > 0) {
PrintAndLogEx(WARNING, "Received packet frame preamble too short: %d/%zu", rxlen, sizeof(PacketResponseNGPreamble));
error = true;
}
if (res == PM3_ENOTTY) {
commfailed = true;
} else {
if (rxlen > 0) {
PrintAndLogEx(WARNING, "Received packet frame preamble too short: %d/%zu", rxlen, sizeof(PacketResponseNGPreamble));
error = true;
}
if (res == PM3_ENOTTY) {
commfailed = true;
}
}
}
is_receiving_raw_last = is_receiving_raw;
// TODO if error, shall we resync ?
pthread_mutex_lock(&txBufferMutex);
@ -560,6 +605,45 @@ bool IsCommunicationThreadDead(void) {
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) {
if (!wait_for_port) {
@ -738,6 +822,78 @@ static size_t communication_delay(void) {
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
* ms_timeout milliseconds for a specified response command.

View file

@ -45,6 +45,8 @@ extern "C" {
#define CMD_BUFFER_SIZE 100
#endif
#define COMM_RAW_RECEIVE_LEN (1024)
typedef enum {
BIG_BUF,
BIG_BUF_EML,
@ -96,10 +98,14 @@ void clearCommandBuffer(void);
#define FLASHMODE_SPEED 460800
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);
int TestProxmark(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 WaitForResponseTimeout(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout);
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

View file

@ -113,12 +113,19 @@ void setGraphBuf(const uint8_t *src, size_t size) {
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) {
return getFromGraphBufEx(dest, g_GraphTraceLen);
}
size_t getFromGraphBufEx(uint8_t *dest, size_t maxLen) {
if (dest == NULL) return 0;
if (g_GraphTraceLen == 0) return 0;
size_t i;
for (i = 0; i < g_GraphTraceLen; ++i) {
maxLen = (maxLen < g_GraphTraceLen) ? maxLen : g_GraphTraceLen;
for (i = 0; i < maxLen; ++i) {
//trim
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;
}

View file

@ -31,6 +31,7 @@ bool HasGraphData(void);
void setGraphBuf(const uint8_t *src, size_t size);
void save_restoreGB(uint8_t saveOpt);
size_t getFromGraphBuf(uint8_t *dest);
size_t getFromGraphBufEx(uint8_t *dest, size_t maxLen);
void convertGraphFromBitstream(void);
void convertGraphFromBitstreamEx(int hi, int low);
bool isGraphBitstream(void);
@ -42,7 +43,7 @@ int GetNrzClock(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);
#define MAX_GRAPH_TRACE_LEN (40000 * 8)
#define MAX_GRAPH_TRACE_LEN (40000 * 32)
#define GRAPH_SAVE 1
#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_NOTIFY 3 // cfg cdc notification interrup
#define AT91C_EP_CONTROL_SIZE 8
#define AT91C_EP_OUT_SIZE 64
#define AT91C_EP_IN_SIZE 64
// The endpoint size is defined in usb_cdc.h
// Section: USB Descriptors
#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_CONTROL_LINE_STATE 0x2221
static bool isAsyncRequestFinished = false;
static AT91PS_UDP pUdp = AT91C_BASE_UDP;
static uint8_t btConfiguration = 0;
static uint8_t btConnection = 0;
@ -127,7 +125,7 @@ static const char devDescriptor[] = {
2, // Device Class: Communication Device Class
0, // Device Subclass: CDC class sub code ACM [ice 0x02 = win10 virtual comport ]
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]
0x8f, 0x4b, // Product ID [0x4b8f = Proxmark-3 RFID Instrument]
0x00, 0x01, // BCD Device release number (1.00)
@ -217,7 +215,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP03_IN, // EndpointAddress: Endpoint 03 - IN
_INTERRUPT, // Attributes
AT91C_EP_CONTROL_SIZE, 0x00, // MaxPacket Size: EP0 - 8
AT91C_USB_EP_CONTROL_SIZE, 0x00, // MaxPacket Size: EP0 - 8
0xFF, // Interval polling
@ -238,7 +236,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP01_OUT, // Endpoint Address: Endpoint 01 - OUT
_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
/* Endpoint descriptor */
@ -246,7 +244,7 @@ static const char cfgDescriptor[] = {
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP02_IN, // Endpoint Address: Endpoint 02 - IN
_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
};
@ -638,6 +636,10 @@ bool usb_poll(void) {
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
usb_poll, which returns true, but the usb_read operation
@ -649,7 +651,7 @@ bool usb_poll(void) {
bool usb_poll_validate_length(void) {
if (!usb_check()) return false;
if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;
return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0;
return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0;
}
/*
@ -671,7 +673,7 @@ uint32_t usb_read(uint8_t *data, size_t len) {
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);
len -= 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)) {
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);
available -= packetSize;
len -= packetSize;
@ -770,7 +772,7 @@ int usb_write(const uint8_t *data, const size_t len) {
// send first chunk
cpt = MIN(length, AT91C_EP_IN_SIZE);
cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt;
while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
@ -781,7 +783,7 @@ int usb_write(const uint8_t *data, const size_t len) {
while (length) {
// Send next chunk
cpt = MIN(length, AT91C_EP_IN_SIZE);
cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt;
while (cpt--) {
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) {};
if (len % AT91C_EP_IN_SIZE == 0) {
if (len % AT91C_USB_EP_IN_SIZE == 0) {
// like AT91F_USB_SendZlp(), in non ping-pong mode
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
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;
}
/*
*----------------------------------------------------------------------------
* \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
@ -831,7 +944,7 @@ void AT91F_USB_SendData(AT91PS_UDP pudp, const char *pData, uint32_t length) {
AT91_REG csr;
do {
uint32_t cpt = MIN(length, AT91C_EP_CONTROL_SIZE);
uint32_t cpt = MIN(length, AT91C_USB_EP_CONTROL_SIZE);
length -= cpt;
while (cpt--)

View file

@ -23,13 +23,22 @@
#include "common.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_enable(void);
bool usb_check(void);
bool usb_poll(void);
uint16_t usb_available_length(void);
bool usb_poll_validate_length(void);
uint32_t usb_read(uint8_t *data, 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);
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 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

View file

@ -274,6 +274,17 @@ typedef struct {
uint8_t data[];
} 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 {
uint8_t blockno;
uint8_t keytype;