diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 29cdb9c0e..fc07d66f8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -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: { diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index ccc47bcde..7ac52a42a 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -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); diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index c763bd0c6..e4f9ff2e8 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -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 diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index 8a8e40868..27844d81c 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -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 diff --git a/armsrc/lfzx.c b/armsrc/lfzx.c index f086c2d71..f95b2c2b7 100644 --- a/armsrc/lfzx.c +++ b/armsrc/lfzx.c @@ -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(); } diff --git a/armsrc/util.c b/armsrc/util.c index fe40b6b43..9f42c0b08 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -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 +} diff --git a/armsrc/util.h b/armsrc/util.h index 65d24f026..da45219a7 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -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 diff --git a/client/src/cmddata.c b/client/src/cmddata.c index cca476c20..47c8ef910 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -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); } - diff --git a/client/src/cmddata.h b/client/src/cmddata.h index 1e4500d32..0767412cb 100644 --- a/client/src/cmddata.h +++ b/client/src/cmddata.h @@ -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); diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 1d57378c7..2247236fe 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -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(¤t_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", "", "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_("") " 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(¤t_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", "", "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_("") " 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; } diff --git a/client/src/cmdlf.h b/client/src/cmdlf.h index 3bcd3ecf2..b29fd137f 100644 --- a/client/src/cmdlf.h +++ b/client/src/cmdlf.h @@ -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); diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 7e3763ec5..0526b16db 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -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")); diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index ba1d14205..5417bf158 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -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); diff --git a/client/src/cmdlfio.c b/client/src/cmdlfio.c index 454d01a54..5ef0df99a 100644 --- a/client/src/cmdlfio.c +++ b/client/src/cmdlfio.c @@ -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; } - diff --git a/client/src/cmdlfparadox.c b/client/src/cmdlfparadox.c index d750efa51..ad6b42bf8 100644 --- a/client/src/cmdlfparadox.c +++ b/client/src/cmdlfparadox.c @@ -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; } - - diff --git a/client/src/cmdlfpyramid.c b/client/src/cmdlfpyramid.c index 80eeb251c..5ed9ef576 100644 --- a/client/src/cmdlfpyramid.c +++ b/client/src/cmdlfpyramid.c @@ -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; } - diff --git a/client/src/comms.c b/client/src/comms.c index 9460c7024..1cf42f0b1 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -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. diff --git a/client/src/comms.h b/client/src/comms.h index 333b2bf1c..632f0d29f 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -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 - - diff --git a/client/src/graph.c b/client/src/graph.c index 851e49d5a..8b97dcfad 100644 --- a/client/src/graph.c +++ b/client/src/graph.c @@ -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; } - diff --git a/client/src/graph.h b/client/src/graph.h index 3be6c9852..3a05dd8eb 100644 --- a/client/src/graph.h +++ b/client/src/graph.h @@ -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 diff --git a/common_arm/usb_cdc.c b/common_arm/usb_cdc.c index 4787ce112..37774aeeb 100644 --- a/common_arm/usb_cdc.c +++ b/common_arm/usb_cdc.c @@ -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--) diff --git a/common_arm/usb_cdc.h b/common_arm/usb_cdc.h index e7f6f3d09..9c7cb7299 100644 --- a/common_arm/usb_cdc.h +++ b/common_arm/usb_cdc.h @@ -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); diff --git a/include/common.h b/include/common.h index a97545996..b3d4598c5 100644 --- a/include/common.h +++ b/include/common.h @@ -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 diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index af019eadd..4b0b21c0e 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -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;