Module: PWN::SDR::Decoder::DECT

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

Overview

DECT (ETSI EN 300 175) true-air decoder.

1.152 Mbit/s GFSK, 24-slot / 10 ms TDMA. I/Q → PWN::FFI::Liquid gmskdem (or DSP.fm_demod_iq→NRZ) → hunt 32-bit S-field (16-bit preamble + 16-bit sync 0xE98A FP / 0x1675 PP) → A-field (64 bits: 8-bit header + 40-bit tail + 16-bit R-CRC) → RFPI extraction on Nt/Qt tails. Emits role:, slot_est:, crc_ok:.

Defined Under Namespace

Classes: DemodIQ

Constant Summary collapse

SYNC_FP =
0xAAAAE98A
SYNC_PP =
0x55551675
BAUD =
1_152_000
RCRC_POLY =

R-CRC-16 poly x^16+x^10+x^8+x^7+x^3+1 = 0x0589, init 0x0000.

0x0589
A_TA =
{ 0 => 'Ct', 1 => 'Ct', 2 => 'Nt', 3 => 'Nt', 4 => 'Qt', 5 => 'Nt', 6 => 'Mt', 7 => 'Pt' }.freeze

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. support@0dayinc.com



136
137
138
# File 'lib/pwn/sdr/decoder/dect.rb', line 136

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <support@0dayinc.com>\n"
end

.decode(opts = {}) ⇒ Object

Supported Method Parameters

PWN::SDR::Decoder::DECT.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' )



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/pwn/sdr/decoder/dect.rb', line 104

public_class_method def self.decode(opts = {})
  freq_obj = opts[:freq_obj]
  hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
  # EU: carrier 0 = 1897.344 MHz, step 1.728 MHz down; US 1.9296 GHz.
  carrier = ((1_897_344_000 - hz) / 1_728_000.0).round
  rate = (opts[:sample_rate] || freq_obj[:iq_rate] || 2_304_000).to_i
  PWN::SDR::Decoder::Base.run_iq(
    freq_obj: freq_obj,
    protocol: 'DECT',
    sample_rate: rate,
    source: opts[:source],
    file: opts[:file],
    demod: DemodIQ.new(rate: rate, carrier: carrier),
    note: '1.152 Mbit/s GFSK — I/Q→gmskdem→S-field 0xE98A→A-field/RFPI/R-CRC.',
    describe: proc { |b| { modulation: 'GFSK', tdma_slots: (b[:duration_ms] / 0.417).round } }
  )
end

.helpObject



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/pwn/sdr/decoder/dect.rb', line 140

public_class_method def self.help
  puts "USAGE (true-air I/Q via PWN::FFI + detector fallback):
    #{self}.decode(
      freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq',
      source:   'optional - :auto|:rtlsdr|:adalm_pluto|:file',
      file:     'optional - .cu8/.cs16 capture (≥2.304 Msps)'
    )

    #{self}.authors
  "
end

.parse_line(opts = {}) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/pwn/sdr/decoder/dect.rb', line 122

public_class_method def self.parse_line(opts = {})
  line = opts[:line].to_s
  out  = { protocol: 'DECT' }
  out[:rfpi]    = ::Regexp.last_match(1).delete(' ') if line =~ /RFPI[:=]?\s*((?:[0-9A-Fa-f]{2}\s*){5})/
  out[:slot]    = ::Regexp.last_match(1) if line =~ /slot\s*(\d+)/i
  out[:carrier] = ::Regexp.last_match(1) if line =~ /carrier\s*(\d+)/i
  out[:rssi]    = ::Regexp.last_match(1) if line =~ /RSSI[:=]?\s*(-?\d+)/i
  out[:role]    = ::Regexp.last_match(1) if line =~ /\b(FP|PP)\b/
  out[:summary] = "DECT RFPI=#{out[:rfpi]} slot=#{out[:slot]} carrier=#{out[:carrier]}"
  out.compact
end