diff --git a/armsrc/pm5_cep.c b/armsrc/pm5_cep.c index cd5648fec..8ef5c9674 100644 --- a/armsrc/pm5_cep.c +++ b/armsrc/pm5_cep.c @@ -343,6 +343,17 @@ static bool cep_spi_read_byte(uint8_t *out) { return true; } +// Genuinely non-blocking - a single flag read, no spin-wait at all. For +// data_available()'s use (armsrc/util.c): a tight sampling loop calls that +// every pass purely to notice an incoming CMD_BREAK_LOOP promptly, so it +// needs to cost nothing when idle. cep_spi_data_available() isn't a fit +// here - it waits (bounded, but non-zero) for a first byte to actually +// arrive, which is fine for receive_ng()'s own cadence but would add that +// wait to every iteration of every LF/HF reader loop in the codebase. +bool cep_spi_rx_pending(void) { + return spi_i2s_flag_get(SPI1, SPI_I2S_RDBF_FLAG) != RESET; +} + bool cep_spi_data_available(void) { uint8_t len_header[2] = {0x00}; size_t discarded = 0; diff --git a/armsrc/pm5_cep.h b/armsrc/pm5_cep.h index 28d7bb0d9..7185be426 100644 --- a/armsrc/pm5_cep.h +++ b/armsrc/pm5_cep.h @@ -58,6 +58,13 @@ void cep_attach_poll(void); // simple non-blocking peek. bool cep_spi_data_available(void); +// True if SPI1's receive-data register currently holds an unread byte - a +// single flag check, zero wait. Gate for data_available() (armsrc/util.c), +// which many LF/HF reader loops call every pass to notice an incoming +// CMD_BREAK_LOOP - that call site needs to cost nothing when idle, unlike +// cep_spi_data_available() above which waits (bounded) for a first byte. +bool cep_spi_rx_pending(void); + // Read up to `len` raw NG bytes off SPI1. Returns the number of bytes // actually read before an internal per-byte timeout gave up early. uint32_t cep_spi_read_ng(uint8_t *data, size_t len); diff --git a/armsrc/util.c b/armsrc/util.c index d163f47b3..cc7eb6b5e 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -28,6 +28,9 @@ #ifdef WITH_BWM_FORWARD #include "bwm_forward.h" #endif +#ifdef WITH_CEP +#include "pm5_cep.h" +#endif #include "BigBuf.h" // trace_restart_timeline #ifdef WITH_SMARTCARD #include "i2c.h" // sc_log_trace_reset @@ -330,28 +333,42 @@ int BUTTON_HELD(int ms) { // This function returns false if no data is available or // the USB connection is invalid. bool data_available(void) { + bool avail; #if defined(WITH_BWM_FORWARD) // The BWM (BLE / WiFi) link is the host connection on a Proxmark5, so it // has to be polled here too or CMD_BREAK_LOOP is never seen over it. - return usb_poll_validate_length() || (bwm_fwd_rxdata_available() > 0); + avail = usb_poll_validate_length() || (bwm_fwd_rxdata_available() > 0); #elif defined(WITH_FPC_USART_HOST) - return usb_poll_validate_length() || (usart_rxdata_available() > 0); + avail = usb_poll_validate_length() || (usart_rxdata_available() > 0); #else - return usb_poll_validate_length(); + avail = usb_poll_validate_length(); #endif +#if defined(WITH_CEP) + // CEP is independent of BWM/FPC (both may be live at once) - a Flipper + // sending CMD_BREAK_LOOP into a running reader loop is otherwise + // invisible here, leaving the loop (and its RF field) running until an + // unrelated USB command happens to arrive. + avail = avail || cep_spi_rx_pending(); +#endif + return avail; } // 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) { + bool avail; #if defined(WITH_BWM_FORWARD) - return usb_available_length() || (bwm_fwd_rxdata_available() > 0); + avail = usb_available_length() || (bwm_fwd_rxdata_available() > 0); #elif defined(WITH_FPC_USART_HOST) - return usb_available_length() || (usart_rxdata_available() > 0); + avail = usb_available_length() || (usart_rxdata_available() > 0); #else - return usb_available_length(); + avail = usb_available_length(); #endif +#if defined(WITH_CEP) + avail = avail || cep_spi_rx_pending(); +#endif + return avail; } // Combined function to convert an unsigned int to an array of hex values corresponding to the last three bits of k1