diff --git a/firmware/bluetooth_rxtx/bluetooth_rxtx.c b/firmware/bluetooth_rxtx/bluetooth_rxtx.c index 99065fa2..42053bcf 100644 --- a/firmware/bluetooth_rxtx/bluetooth_rxtx.c +++ b/firmware/bluetooth_rxtx/bluetooth_rxtx.c @@ -68,7 +68,7 @@ volatile uint8_t modulation = MOD_BT_BASIC_RATE; /* specan stuff */ volatile uint16_t low_freq = 2400; volatile uint16_t high_freq = 2483; -volatile int8_t rssi_threshold = -30; // -54dBm - 30 = -84dBm +volatile int8_t rssi_threshold = -84; /* Generic TX stuff */ generic_tx_packet tx_pkt; @@ -140,10 +140,12 @@ static int enqueue(uint8_t type, uint8_t* buf) f->clkn_high = idle_buf_clkn_high; f->clk100ns = idle_buf_clk100ns; f->channel = (uint8_t)((idle_buf_channel - 2402) & 0xff); - f->rssi_min = rssi_min; - f->rssi_max = rssi_max; - f->rssi_avg = rssi_get_avg(idle_buf_channel); - f->rssi_count = rssi_count; + f->rssi_min = rssi_get_min(); + f->rssi_max = rssi_get_max(); + f->rssi_noise = rssi_get_noise(); + f->rssi_signal = rssi_get_signal(); + f->rssi_avg = rssi_get_avg(); + f->rssi_count = rssi_get_cnt(); } memcpy(f->data, buf, DMA_SIZE); @@ -400,7 +402,7 @@ static int vendor_request_handler(uint8_t request, uint16_t* request_params, uin case UBERTOOTH_LED_SPECAN: if (request_params[0] > 256) return 0; - rssi_threshold = 54 - request_params[0]; + rssi_threshold = request_params[0]; requested_mode = MODE_LED_SPECAN; *data_len = 0; break; @@ -1270,12 +1272,11 @@ void bt_stream_rx() * at multiple trigger points there. The MAX() below * helps with statistics in the case that cs_trigger * happened before the loop started. */ - rssi_reset(); rssi_at_trigger = INT8_MIN; while (!rx_tc) { - rssi = (int8_t)(cc2400_get(RSSI) >> 8); + rssi = cc2400_rssi(); if (cs_trigger && (rssi_at_trigger == INT8_MIN)) { - rssi = MAX(rssi,(cs_threshold_cur+54)); + rssi = MAX(rssi, cs_threshold_cur); rssi_at_trigger = rssi; } rssi_add(rssi); @@ -1284,6 +1285,7 @@ void bt_stream_rx() /* If timer says time to hop, do it. */ if (do_hop) { + rssi_reset(); hop(); } else { TXLED_CLR; @@ -1307,8 +1309,6 @@ void bt_stream_rx() dma_discard = 0; } - rssi_iir_update(channel); - /* Set squelch hold if there was either a CS trigger, squelch * is disabled, or if the current rssi_max is above the same * threshold. Currently, this is redundant, but allows for @@ -1318,12 +1318,14 @@ void bt_stream_rx() cs_trigger = 0; } - if (rssi_max >= (cs_threshold_cur + 54)) { + if (rssi_get_max() >= cs_threshold_cur) { status |= RSSI_TRIGGER; } enqueue(BR_PACKET, (uint8_t*)idle_rxbuf); + rssi_reset(); + handle_usb(clkn); rx_tc = 0; rx_err = 0; @@ -1548,9 +1550,9 @@ void bt_generic_le(u8 active_mode) rssi_at_trigger = INT8_MIN; while ((rx_tc == 0) && (rx_err == 0)) { - rssi = (int8_t)(cc2400_get(RSSI) >> 8); + rssi = cc2400_rssi(); if (cs_trigger && (rssi_at_trigger == INT8_MIN)) { - rssi = MAX(rssi,(cs_threshold_cur+54)); + rssi = MAX(rssi,cs_threshold_cur); rssi_at_trigger = rssi; } rssi_add(rssi); @@ -1568,8 +1570,6 @@ void bt_generic_le(u8 active_mode) if (rx_tc > 1) status |= DMA_OVERFLOW; - rssi_iir_update(channel); - /* Set squelch hold if there was either a CS trigger, squelch * is disabled, or if the current rssi_max is above the same * threshold. Currently, this is redundant, but allows for @@ -1580,7 +1580,7 @@ void bt_generic_le(u8 active_mode) cs_trigger = 0; } - if (rssi_max >= (cs_threshold_cur + 54)) { + if (rssi_get_max(channel) >= cs_threshold_cur) { status |= RSSI_TRIGGER; hold = CS_HOLD_TIME; } @@ -1670,8 +1670,8 @@ void bt_le_sync(u8 active_mode) while ((rx_tc == 0) && (rx_err == 0) && (do_hop == 0) && requested_mode == active_mode) ; - rssi = (int8_t)(cc2400_get(RSSI) >> 8); - rssi_min = rssi_max = rssi; + rssi = cc2400_rssi(); + rssi_add(rssi); if (requested_mode != active_mode) { goto cleanup; @@ -1747,6 +1747,8 @@ void bt_le_sync(u8 active_mode) enqueue(LE_PACKET, (uint8_t *)packet); le.last_packet = CLK100NS; + rssi_reset(); + rx_flush: // this might happen twice, but it's safe to do so cc2400_strobe(SFSON); @@ -2438,7 +2440,7 @@ void specan() volatile u32 j = 500; while (--j); //FIXME crude delay buf[3 * i] = (f >> 8) & 0xFF; buf[(3 * i) + 1] = f & 0xFF; - buf[(3 * i) + 2] = cc2400_get(RSSI) >> 8; + buf[(3 * i) + 2] = cc2400_rssi(); i++; if (i == 16) { enqueue(SPECAN, buf); @@ -2484,7 +2486,7 @@ void led_specan() /* give the CC2400 time to acquire RSSI reading */ volatile u32 j = 500; while (--j); //FIXME crude delay - lvl = (int8_t)((cc2400_get(RSSI) >> 8) & 0xff); + lvl = cc2400_rssi(); if (lvl > rssi_threshold) { switch (i) { case 0: diff --git a/firmware/bluetooth_rxtx/ubertooth_rssi.c b/firmware/bluetooth_rxtx/ubertooth_rssi.c index 4af1e591..ccb1b1e1 100644 --- a/firmware/bluetooth_rxtx/ubertooth_rssi.c +++ b/firmware/bluetooth_rxtx/ubertooth_rssi.c @@ -23,58 +23,101 @@ #include -#define RSSI_IIR_ALPHA 3 // 3/256 = .012 +#define RINGBUFFER_SIZE 40 -int32_t rssi_sum; -int16_t rssi_iir[79] = {0}; +size_t pointer = 0; +size_t size = 0; +int8_t values[RINGBUFFER_SIZE] = {0}; + +int8_t max = -120; +int8_t min = 0; void rssi_reset(void) { - memset(rssi_iir, 0, sizeof(rssi_iir)); + memset(values, 0, size); + pointer = 0; + size = 0; - rssi_count = 0; - rssi_sum = 0; - rssi_max = INT8_MIN; - rssi_min = INT8_MAX; + max = -120; + min = 0; } void rssi_add(int8_t v) { - rssi_max = (v > rssi_max) ? v : rssi_max; - rssi_min = (v < rssi_min) ? v : rssi_min; - rssi_sum += ((int32_t)v * 256); // scaled int math (x256) - rssi_count += 1; + max = (v > max) ? v : max; + min = (v < min) ? v : min; + + values[pointer] = v; + pointer = (pointer + 1) % RINGBUFFER_SIZE; + + size = size < RINGBUFFER_SIZE ? size + 1 : RINGBUFFER_SIZE; +} + +int8_t rssi_get_avg() +{ + int32_t sum = 0; + + for (size_t i = 0; i < size; i++) + { + sum += values[i]; + } + + uint8_t avg = (int8_t)(sum / (int)size); + + return avg; } -/* For sweep mode, update IIR per channel. Otherwise, use single value. */ -void rssi_iir_update(uint16_t channel) +int8_t rssi_get_signal() { - int32_t avg; - int32_t rssi_iir_acc; - - /* Use array to track 79 Bluetooth channels, or just first slot - * of array if the frequency is not a valid Bluetooth channel. */ - if ( channel < 2402 || channel < 2480 ) - channel = 2402; - - int i = channel - 2402; - - // IIR using scaled int math (x256) - if (rssi_count != 0) - avg = (rssi_sum + 128) / rssi_count; - else - avg = 0; // really an error - rssi_iir_acc = rssi_iir[i] * (256-RSSI_IIR_ALPHA); - rssi_iir_acc += avg * RSSI_IIR_ALPHA; - rssi_iir[i] = (int16_t)((rssi_iir_acc + 128) / 256); + int32_t sum = 0; + size_t num = 0; + int8_t avg = ((int16_t)min + (int16_t)max) / 2; + + for (size_t i = 0; i < size; i++) + { + if (values[i] > avg) + { + sum += values[i]; + num++; + } + } + + int8_t signal = (int8_t)(sum / (int)num); + + return signal; } -int8_t rssi_get_avg(uint16_t channel) +int8_t rssi_get_noise() { - /* Use array to track 79 Bluetooth channels, or just first slot - * of array if the frequency is not a valid Bluetooth channel. */ - if ( channel < 2402 || channel < 2480 ) - channel = 2402; + int32_t sum = 0; + size_t num = 0; + int8_t avg = ((int16_t)min + (int16_t)max) / 2; - return (rssi_iir[channel-2402] + 128) / 256; + for (size_t i = 0; i < size; i++) + { + if (values[i] <= avg) + { + sum += values[i]; + num++; + } + } + + int8_t noise = (int8_t)(sum / (int)num); + + return noise; +} + +uint8_t rssi_get_cnt() +{ + return (uint8_t)size; +} + +int8_t rssi_get_min() +{ + return min; +} + +int8_t rssi_get_max() +{ + return max; } diff --git a/firmware/bluetooth_rxtx/ubertooth_rssi.h b/firmware/bluetooth_rxtx/ubertooth_rssi.h index 26911714..203ecb12 100644 --- a/firmware/bluetooth_rxtx/ubertooth_rssi.h +++ b/firmware/bluetooth_rxtx/ubertooth_rssi.h @@ -24,13 +24,13 @@ #include "inttypes.h" -int8_t rssi_max; -int8_t rssi_min; -uint8_t rssi_count; - -void rssi_reset(void); +void rssi_reset(); void rssi_add(int8_t v); -void rssi_iir_update(uint16_t channel); -int8_t rssi_get_avg(uint16_t channel); +int8_t rssi_get_avg(); +int8_t rssi_get_signal(); +int8_t rssi_get_noise(); +int8_t rssi_get_min(); +int8_t rssi_get_max(); +uint8_t rssi_get_cnt(); #endif diff --git a/firmware/common/ubertooth.c b/firmware/common/ubertooth.c index 6395c4b1..593e58a9 100644 --- a/firmware/common/ubertooth.c +++ b/firmware/common/ubertooth.c @@ -64,7 +64,7 @@ void wait_us(u32 us) */ void gpio_init() { - /* + /* * Set all pins for GPIO. This shouldn't be necessary after a reset, but * we might get called at other times. */ @@ -306,6 +306,11 @@ u16 cc2400_get(u8 reg) return in & 0xFFFF; } +int8_t cc2400_rssi() +{ + return (int8_t)(cc2400_get(RSSI) >> 8) - 54; +} + /* write 16 bit value to a register */ void cc2400_set(u8 reg, u16 val) { @@ -374,7 +379,7 @@ void cc2400_fifo_write(u8 len, u8 *data) { SCLK_SET; SCLK_CLR; } - + spi_delay(); /* end transaction by raising CSN */ CSN_SET; @@ -531,9 +536,9 @@ void reset() USRLED_CLR; WDMOD |= WDMOD_WDEN | WDMOD_WDRESET; WDFEED_SEQUENCE; - + /* Set watchdog timeout to 256us (minimum) */ - + /* sleep for 1s (minimum) */ wait(1); } @@ -633,7 +638,7 @@ void get_part_num(uint8_t *buffer, int *len) buffer[3] = (result[1] >> 16) & 0xFF; buffer[4] = (result[1] >> 24) & 0xFF; *len = 5; - + } void get_device_serial(uint8_t *buffer, int *len) diff --git a/firmware/common/ubertooth.h b/firmware/common/ubertooth.h index 513fbc99..feb75c0d 100644 --- a/firmware/common/ubertooth.h +++ b/firmware/common/ubertooth.h @@ -323,6 +323,7 @@ void atest_init(void); void cc2400_init(void); u32 cc2400_spi(u8 len, u32 data); u16 cc2400_get(u8 reg); +int8_t cc2400_rssi(); void cc2400_set(u8 reg, u16 val); u8 cc2400_get8(u8 reg); void cc2400_set8(u8 reg, u8 val); diff --git a/host/libubertooth/src/ubertooth_callback.c b/host/libubertooth/src/ubertooth_callback.c index 37310353..50015b5a 100644 --- a/host/libubertooth/src/ubertooth_callback.c +++ b/host/libubertooth/src/ubertooth_callback.c @@ -29,62 +29,6 @@ unsigned int packet_counter_max; -static int8_t cc2400_rssi_to_dbm( const int8_t rssi ) -{ - /* models the cc2400 datasheet fig 22 for 1M as piece-wise linear */ - if (rssi < -48) { - return -120; - } - else if (rssi <= -45) { - return 6*(rssi+28); - } - else if (rssi <= 30) { - return (int8_t) ((99*((int)rssi-62))/110); - } - else if (rssi <= 35) { - return (int8_t) ((60*((int)rssi-35))/11); - } - else { - return 0; - } -} - -#define RSSI_HISTORY_LEN 10 - -/* Ignore packets with a SNR lower than this in order to reduce - * processor load. TODO: this should be a command line parameter. */ - -static int8_t rssi_history[NUM_BREDR_CHANNELS][RSSI_HISTORY_LEN] = {{INT8_MIN}}; - -static void determine_signal_and_noise( usb_pkt_rx *rx, int8_t * sig, int8_t * noise ) -{ - int8_t * channel_rssi_history = rssi_history[rx->channel]; - int8_t rssi; - int i; - - /* Shift rssi max history and append current max */ - memmove(channel_rssi_history, - channel_rssi_history+1, - RSSI_HISTORY_LEN-1); - channel_rssi_history[RSSI_HISTORY_LEN-1] = rx->rssi_max; - -#if 0 - /* Signal starts in oldest bank, but may cross into second - * oldest bank. Take the max or the 2 maxs. */ - rssi = MAX(channel_rssi_history[0], channel_rssi_history[1]); -#else - /* Alternatively, use all banks in history. */ - rssi = channel_rssi_history[0]; - for (i = 1; i < RSSI_HISTORY_LEN; i++) - rssi = MAX(rssi, channel_rssi_history[i]); -#endif - *sig = cc2400_rssi_to_dbm( rssi ); - - /* Noise is an IIR of averages */ - /* FIXME: currently bogus */ - *noise = cc2400_rssi_to_dbm( rx->rssi_avg ); -} - static uint64_t now_ns( void ) { /* As per Apple QA1398 */ @@ -130,9 +74,6 @@ static uint64_t now_ns_from_clk100ns( ubertooth_t* ut, const usb_pkt_rx* rx ) void cb_scan(ubertooth_t* ut, void* args __attribute__((unused))) { btbb_packet* pkt = NULL; - int8_t signal_level; - int8_t noise_level; - int8_t snr; int offset; uint32_t clkn; @@ -145,9 +86,6 @@ void cb_scan(ubertooth_t* ut, void* args __attribute__((unused))) if (rx->channel > (NUM_BREDR_CHANNELS-1)) goto out; - determine_signal_and_noise( rx, &signal_level, &noise_level ); - snr = signal_level - noise_level; - /* Pass packet-pointer-pointer so that * packet can be created in libbtbb. */ offset = btbb_find_ac(syms, BANK_LEN - 64, LAP_ANY, max_ac_errors, &pkt); @@ -168,9 +106,9 @@ void cb_scan(ubertooth_t* ut, void* args __attribute__((unused))) btbb_packet_get_ac_errors(pkt), rx->clk100ns, btbb_packet_get_clkn(pkt), - signal_level, - noise_level, - snr); + rx->rssi_signal, + rx->rssi_noise, + rx->rssi_signal - rx->rssi_noise); btbb_process_packet(pkt, NULL); @@ -321,7 +259,6 @@ void cb_btle(ubertooth_t* ut, void* args) static u32 prev_ts = 0; uint32_t refAA; - int8_t sig, noise; // display LE promiscuous mode state changes if (rx->pkt_type == LE_PROMISC) { @@ -381,13 +318,12 @@ void cb_btle(ubertooth_t* ut, void* args) /* Dump to PCAP/PCAPNG if specified */ refAA = lell_packet_is_data(pkt) ? 0 : 0x8e89bed6; - determine_signal_and_noise( rx, &sig, &noise ); if (ut->h_pcap_le) { /* only one of these two will succeed, depending on * whether PCAP was opened with DLT_PPI or not */ lell_pcap_append_packet(ut->h_pcap_le, nowns, - sig, noise, + rx->rssi_signal, rx->rssi_noise, refAA, pkt); lell_pcap_append_ppi_packet(ut->h_pcap_le, nowns, rx->clkn_high, @@ -397,7 +333,7 @@ void cb_btle(ubertooth_t* ut, void* args) } if (ut->h_pcapng_le) { lell_pcapng_append_packet(ut->h_pcapng_le, nowns, - sig, noise, + rx->rssi_signal, rx->rssi_noise, refAA, pkt); } @@ -409,7 +345,7 @@ void cb_btle(ubertooth_t* ut, void* args) prev_ts = rx->clk100ns; printf("systime=%u freq=%d addr=%08x delta_t=%.03f ms rssi=%d\n", systime, rx->channel + 2402, lell_get_access_address(pkt), - ts_diff / 10000.0, rx->rssi_min - 54); + ts_diff / 10000.0, rx->rssi_signal); int len = (rx->data[5] & 0x3f) + 6 + 3; if (len > 50) len = 50; @@ -489,11 +425,6 @@ void cb_rx(ubertooth_t* ut, void* args) uint64_t nowns = now_ns_from_clk100ns( ut, rx ); - int8_t signal_level = rx->rssi_max; - int8_t noise_level = rx->rssi_min; - determine_signal_and_noise( rx, &signal_level, &noise_level ); - int8_t snr = signal_level - noise_level; - /* Look for packets with specified LAP, if given. Otherwise * search for any packet. */ if (pn) { @@ -534,9 +465,9 @@ void cb_rx(ubertooth_t* ut, void* args) btbb_packet_get_ac_errors(pkt), clkn, clk_offset, - signal_level, - noise_level, - snr + rx->rssi_signal, + rx->rssi_noise, + rx->rssi_signal - rx->rssi_noise ); /* calibrate Ubertooth clock such that the first bit of the AC @@ -602,12 +533,12 @@ void cb_rx(ubertooth_t* ut, void* args) /* Dump to PCAP/PCAPNG if specified */ if (ut->h_pcap_bredr) { btbb_pcap_append_packet(ut->h_pcap_bredr, nowns, - signal_level, noise_level, + rx->rssi_signal, rx->rssi_noise, lap, uap, pkt); } if (ut->h_pcapng_bredr) { btbb_pcapng_append_packet(ut->h_pcapng_bredr, nowns, - signal_level, noise_level, + rx->rssi_signal, rx->rssi_noise, lap, uap, pkt); } diff --git a/host/libubertooth/src/ubertooth_interface.h b/host/libubertooth/src/ubertooth_interface.h index 62e24da6..992f1579 100644 --- a/host/libubertooth/src/ubertooth_interface.h +++ b/host/libubertooth/src/ubertooth_interface.h @@ -25,7 +25,7 @@ #include // increment on every API change -#define UBERTOOTH_API_VERSION 1 +#define UBERTOOTH_API_VERSION 2 #define DMA_SIZE 50 @@ -157,17 +157,18 @@ enum usb_pkt_status { * USB packet for Bluetooth RX (64 total bytes) */ typedef struct { - u8 pkt_type; - u8 status; - u8 channel; - u8 clkn_high; - u32 clk100ns; - char rssi_max; // Max RSSI seen while collecting symbols in this packet - char rssi_min; // Min ... - char rssi_avg; // Average ... - u8 rssi_count; // Number of ... (0 means RSSI stats are invalid) - u8 reserved[2]; - u8 data[DMA_SIZE]; + uint8_t pkt_type; + uint8_t status; + uint8_t channel; + uint8_t clkn_high; + uint32_t clk100ns; + int8_t rssi_max; // Max RSSI seen while collecting symbols in this packet + int8_t rssi_min; // Min ... + int8_t rssi_avg; // Average ... + uint8_t rssi_count; // Number of ... (0 means RSSI stats are invalid) + int8_t rssi_signal; + int8_t rssi_noise; + uint8_t data[DMA_SIZE]; } usb_pkt_rx; typedef struct { diff --git a/host/python/specan_ui/specan/Ubertooth.py b/host/python/specan_ui/specan/Ubertooth.py index 6fd75c82..4d63c18f 100644 --- a/host/python/specan_ui/specan/Ubertooth.py +++ b/host/python/specan_ui/specan/Ubertooth.py @@ -46,9 +46,8 @@ def specan(self, low_frequency, high_frequency, ubertooth_device=-1): self.proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) default_raw_rssi = -128 - rssi_offset = -54 rssi_values = numpy.empty((bin_count,), dtype=numpy.float32) - rssi_values.fill(default_raw_rssi + rssi_offset) + rssi_values.fill(default_raw_rssi) # Give it a chance to time out if it fails to find Ubertooth time.sleep(0.5) @@ -69,8 +68,8 @@ def specan(self, low_frequency, high_frequency, ubertooth_device=-1): # We started a new frame, send the existing frame yield (frequency_axis, rssi_values) - rssi_values.fill(default_raw_rssi + rssi_offset) - rssi_values[index] = raw_rssi_value + rssi_offset + rssi_values.fill(default_raw_rssi) + rssi_values[index] = raw_rssi_value def close(self): if self.proc and not self.proc.poll():