Class: PWN::SDR::Decoder::Bluetooth::DemodIQ
- Inherits:
-
Object
- Object
- PWN::SDR::Decoder::Bluetooth::DemodIQ
- Defined in:
- lib/pwn/sdr/decoder/bluetooth.rb
Overview
Streaming BLE GFSK demod for Base.run_iq — I/Q → advertising PDUs.
Constant Summary collapse
- BAUD =
1_000_000
Instance Method Summary collapse
- #feed_bits(bits) ⇒ Object
- #feed_iq(samples, rate: nil) ⇒ Object
-
#initialize(rate:, channel: 37, ble: true, extended: false, **connection) ⇒ DemodIQ
constructor
A new instance of DemodIQ.
Constructor Details
#initialize(rate:, channel: 37, ble: true, extended: false, **connection) ⇒ DemodIQ
Returns a new instance of DemodIQ.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/pwn/sdr/decoder/bluetooth.rb', line 86 def initialize(rate:, channel: 37, ble: true, extended: false, **connection) access_address = connection.fetch(:access_address, BLE_ADV_AA) crc_init = connection[:crc_init] encrypted = connection[:encrypted] raise ArgumentError, 'BR/EDR is unsupported; only legacy BLE advertising is decoded' unless ble @connected = access_address != BLE_ADV_AA @extended = extended raise ArgumentError, 'advertising channel must be 37, 38 or 39' unless @connected || @extended || BLE_ADV_CHANNELS.key?(channel) raise ArgumentError, 'channel must be an integer 0..39' unless channel.is_a?(Integer) && (0..39).cover?(channel) raise ArgumentError, 'connected channel must be 0..36' if @connected && channel >= 37 raise ArgumentError, 'connected decoding requires crc_init and explicit encrypted: true/false' if @connected && (crc_init.nil? || ![true, false].include?(encrypted)) @access_address = Integer(access_address) @crc_init = crc_init || BLE_CRC_INIT raise ArgumentError, 'invalid access address or CRCInit width' unless (0..0xFFFFFFFF).cover?(@access_address) && @crc_init.is_a?(Integer) && (0..0xFFFFFF).cover?(@crc_init) @encrypted = encrypted || false @aa_bits = Array.new(32) { |i| (@access_address >> i) & 1 } @aa_inv = @aa_bits.map { |b| b ^ 1 } @rate = rate.to_f @channel = channel @ble = ble @bits = [] end |
Instance Method Details
#feed_bits(bits) ⇒ Object
121 122 123 124 125 126 |
# File 'lib/pwn/sdr/decoder/bluetooth.rb', line 121 def feed_bits(bits, &) raise ArgumentError, 'bits must contain only 0 or 1' unless bits.all? { |bit| [0, 1].include?(bit) } @bits.concat(bits) scan(&) if block_given? end |
#feed_iq(samples, rate: nil) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/pwn/sdr/decoder/bluetooth.rb', line 113 def feed_iq(samples, rate: nil, &) @rate = rate.to_f if rate # Try both polarities — GFSK sign depends on tuner spectral inversion. @slicer ||= Bluetooth::SymbolStream.new(rate: @rate, baud: BAUD) new_bits = @slicer.feed_iq(samples) feed_bits(new_bits, &) end |