Class: PWN::SDR::Decoder::GSM::SCHDemodIQ

Inherits:
Object
  • Object
show all
Defined in:
lib/pwn/sdr/decoder/gsm.rb

Overview

Noncoherent SCH receiver for channelized GMSK, BT=0.3. Searches sample timing against differentially precoded ETSC and estimates CFO from its two discriminator levels. No multipath equalizer or BCCH/TCH.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rate:, native: true) ⇒ SCHDemodIQ

Returns a new instance of SCHDemodIQ.

Raises:

  • (ArgumentError)


101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/pwn/sdr/decoder/gsm.rb', line 101

def initialize(rate:, native: true)
  @rate = Float(rate)
  raise ArgumentError, 'SCH IQ needs at least four samples per symbol' unless @rate.finite? && @rate >= 1_083_333

  @spb = @rate / SYMBOL_RATE
  @audio = []
  @state = {}
  @cursor = 0
  @offset = 0
  @training = SCH_ETSC.each_cons(2).map { |a, b| a == b ? 1 : -1 }
  @backend = :ruby
  load_native if native
end

Instance Attribute Details

#backendObject (readonly)

Returns the value of attribute backend.



99
100
101
# File 'lib/pwn/sdr/decoder/gsm.rb', line 99

def backend
  @backend
end

Instance Method Details

#feed_iq(samples, rate: nil) ⇒ Object

Raises:

  • (ArgumentError)


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/pwn/sdr/decoder/gsm.rb', line 115

def feed_iq(samples, rate: nil)
  raise ArgumentError, 'SCH sample rate cannot change during a stream' if rate && (rate.to_f - @rate).abs > 0.5

  @audio.concat(DSP.fm_demod_iq(iq: samples, state: @state))
  span = (148 * @spb).ceil
  packed = @audio.pack('d*') if @scanner && @audio.length > span
  while @cursor + span < @audio.length
    if packed
      @cursor = @scanner.pwn_gsm_search(packed, @audio.length, @cursor, @spb, @training_packed)
      break unless @cursor + span < @audio.length
    end
    frame = candidate(@cursor)
    if frame
      yield frame if block_given?
      @cursor += span
    else
      @cursor += 1
    end
  end
  @audio.shift(@cursor)
  @offset += @cursor
  @cursor = 0
end