diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dded4be55..f1afc3c62 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -852,8 +852,12 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_LF_ACQ_RAW_ADC: { lf_sample_payload_t *payload = (lf_sample_payload_t *)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)); + 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: { @@ -877,9 +881,12 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_LF_SNIFF_RAW_ADC: { lf_sample_payload_t *payload = (lf_sample_payload_t *)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)); + 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/lfsampling.c b/armsrc/lfsampling.c index c763bd0c6..123befb3a 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: @@ -424,6 +425,126 @@ 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; + + uint32_t sample_size = 64; + 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; + + initSampleBuffer(&sample_size); // sample size in bytes + if (sample_size != 64) { + return PM3_EFAILED; + } + + sample_size <<= 3; // sample size in bits + sample_size /= bits_per_sample; // sample count + + 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 (unlikely(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 (unlikely(trigger_hit == false)) { + if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) { + continue; + } + trigger_hit = true; + } + + if (unlikely(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/util.c b/armsrc/util.c index fe40b6b43..70a6d01ef 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -305,3 +305,11 @@ bool data_available(void) { return usb_poll_validate_length(); #endif } + +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/include/common.h b/include/common.h index a97545996..37cf254d9 100644 --- a/include/common.h +++ b/include/common.h @@ -196,4 +196,18 @@ 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))) +// 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