Module: PWN::SDR::Decoder::GSM

Defined in:
lib/pwn/sdr/decoder/gsm.rb

Overview

SDR Decoder for GSM signals.

Constant Summary collapse

POWER_THRESHOLD =
0.1
SLEEP_INTERVAL =
0.1
HEADER_SIZE =
44
BURST_DURATION_SEC =
0.000577
TSC_0 =

TSC 0 binary sequence (26 bits): 00100101110000101010011011

[0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1].freeze

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. <[email protected]>



195
196
197
198
199
# File 'lib/pwn/sdr/decoder/gsm.rb', line 195

public_class_method def self.authors
  "AUTHOR(S):
    0day Inc. <[email protected]>
  "
end

.helpObject

Display Usage for this Module



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/pwn/sdr/decoder/gsm.rb', line 203

public_class_method def self.help
  puts "USAGE:
    gsm_decoder_thread = PWN::SDR::Decoder::GSM.start(
      freq_obj: 'required - freq_obj returned from PWN::SDR::Receiver::GQRX.init_freq method'
    )

    # To stop the decoder thread:
    PWN::SDR::Decoder::GSM.stop(
      freq_obj: 'required - freq_obj returned from PWN::SDR::Receiver::GQRX.init_freq method'
    )

    #{self}.authors
  "
end

.start(opts = {}) ⇒ Object

Starts the live decoding thread.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/pwn/sdr/decoder/gsm.rb', line 17

def self.start(opts = {})
  freq_obj = opts[:freq_obj]
  raise ':ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)

  gqrx_sock = freq_obj[:gqrx_sock]
  freq = freq_obj[:freq]
  bandwidth = freq_obj[:bandwidth].to_i
  record_path = freq_obj[:record_path]

  sleep 0.1 until File.exist?(record_path)

  header = File.binread(record_path, HEADER_SIZE)
  raise 'Invalid WAV header' unless header.start_with?('RIFF') && header.include?('WAVE')

  bytes_read = HEADER_SIZE

  puts "GSM Decoder started for freq: #{freq}, bandwidth: #{bandwidth}"

  Thread.new do
    loop do
      current_size = File.size(record_path)
      if current_size > bytes_read
        new_bytes = current_size - bytes_read
        # Ensure full I/Q pairs (8 bytes)
        new_bytes -= new_bytes % 8
        data = File.binread(record_path, new_bytes, bytes_read)
        process_chunk(
          data: data,
          bandwidth: bandwidth,
          freq: freq
        )
        bytes_read = current_size
      end

      sleep SLEEP_INTERVAL
    end
  rescue StandardError => e
    puts "Decoder error: #{e.message}"
  ensure
    cleanup(record_path: record_path)
  end
end

.stop(opts = {}) ⇒ Object

Stops the decoding thread.



61
62
63
64
65
66
67
# File 'lib/pwn/sdr/decoder/gsm.rb', line 61

def self.stop(opts = {})
  freq_obj = opts[:freq_obj]
  raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)

  decoder_thread = freq_obj[:decoder_thread]
  decoder_thread.kill if decoder_thread.is_a?(Thread)
end