Class: PWN::SDR::Decoder::Iridium::RingAlert
- Inherits:
-
Object
- Object
- PWN::SDR::Decoder::Iridium::RingAlert
- Defined in:
- lib/pwn/sdr/decoder/iridium.rb
Overview
Deliberately scoped to the IRA family, not a generic RAW-bit decoder.
Constant Summary collapse
- ACCESS =
'001100000011000011110011'- POLYNOMIAL =
1207- ERROR_SYNDROMES =
Extended BCH(32,21): minimum distance six, bounded radius two. Include the parity bit in the syndrome; never silently ignore it.
begin positions = (0...32).to_a masks = [0] + positions.map { |bit| 1 << bit } + positions.combination(2).map { |a, b| (1 << a) | (1 << b) } masks.to_h do |mask| value = mask >> 1 value ^= POLYNOMIAL << (value.bit_length - POLYNOMIAL.bit_length) while value.bit_length >= POLYNOMIAL.bit_length [((value << 1) | (mask.to_s(2).count('1') & 1)), mask] end.freeze end
Instance Method Summary collapse
Instance Method Details
#decode(bits) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/pwn/sdr/decoder/iridium.rb', line 113 def decode(bits) raise ArgumentError, 'Expected binary IRA bits with downlink access word' unless bits.is_a?(String) && bits.match?(/\A[01]+\z/) && bits.start_with?(ACCESS) raise ArgumentError, 'Truncated IRA header' if bits.length < 120 @corrected = 0 header = deinterleave(bits[24, 96], 3).map { |word| check_word(word) }.join pages = [] offset = 120 ended = false 13.times do raise ArgumentError, 'Truncated IRA paging section' if bits.length < offset + 64 page = deinterleave(bits[offset, 64], 2).map { |word| check_word(word) }.join offset += 64 if page == '1' * 42 ended = true break end raise ArgumentError, 'Invalid IRA paging reserved bits' unless page[32, 2] == '00' && page[39, 3] == '000' pages << { tmsi: page[0, 32].to_i(2), msc_id: page[34, 5].to_i(2) } break if pages.length == 12 end raise ArgumentError, 'Missing IRA paging terminator' unless ended || pages.length == 12 x, y, z = [13, 25, 37].map do |start| value = header[start, 12].to_i(2) value >= 2048 ? value - 4096 : value end { protocol: 'IRIDIUM', frame_type: 'IRA', decoded: true, integrity: 'BCH(31,21)+parity', corrected_bits: @corrected, sat: header[0, 7].to_i(2), beam: header[7, 6].to_i(2), xyz: [x, y, z], latitude: Math.atan2(z, Math.sqrt((x * x) + (y * y))) * 180 / Math::PI, longitude: Math.atan2(y, x) * 180 / Math::PI, radius_km: Math.sqrt((x * x) + (y * y) + (z * z)) * 4, interval: header[49, 7].to_i(2), broadcast_slot: header[56] == '0' ? 1 : 4, eip: header[57].to_i, downlink_subband: header[58, 5].to_i(2), pages: pages, summary: "IRIDIUM IRA sat=#{header[0, 7].to_i(2)} beam=#{header[7, 6].to_i(2)}" } end |