Class: PWN::SDR::Decoder::RFID::EM4100IQ
- Inherits:
-
Object
- Object
- PWN::SDR::Decoder::RFID::EM4100IQ
- Defined in:
- lib/pwn/sdr/decoder/rfid.rb
Overview
EM4100 Manchester RF/64, RF/32 and RF/16 at a configured carrier. Frame layout and polarity: https://www.priority1design.com.au/em4100_protocol.html Only ASK Manchester is supported; not PSK, biphase, ISO14443 or EPC Gen2.
Instance Method Summary collapse
- #feed_iq(samples, rate: nil) ⇒ Object
- #flush ⇒ Object
-
#initialize(rate:, carrier_hz: 125_000, clocks_per_bit: 64, threshold: 0.5) ⇒ EM4100IQ
constructor
A new instance of EM4100IQ.
Constructor Details
#initialize(rate:, carrier_hz: 125_000, clocks_per_bit: 64, threshold: 0.5) ⇒ EM4100IQ
Returns a new instance of EM4100IQ.
94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/pwn/sdr/decoder/rfid.rb', line 94 def initialize(rate:, carrier_hz: 125_000, clocks_per_bit: 64, threshold: 0.5) raise ArgumentError, 'EM4100 clocks_per_bit must be 16, 32 or 64' unless [16, 32, 64].include?(clocks_per_bit) @rate = Float(rate) @half = @rate * clocks_per_bit / (2.0 * Float(carrier_hz)) raise ArgumentError, 'EM4100 requires at least four samples per half bit' unless @half.finite? && @half >= 4 @threshold = Float(threshold)**2 @level = nil @remaining = 0 @symbols = [] end |
Instance Method Details
#feed_iq(samples, rate: nil) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/pwn/sdr/decoder/rfid.rb', line 107 def feed_iq(samples, rate: nil) raise ArgumentError, 'sample rate changed midstream' if rate && (rate.to_f - @rate).abs.positive? raise ArgumentError, 'interleaved IQ pairs required' unless samples.length.even? samples.each_slice(2) do |i, q| level = ((i * i) + (q * q)) >= @threshold ? 1 : 0 if level != @level @level = level @remaining = @half / 2.0 end @remaining -= 1 next if @remaining.positive? @remaining += @half @symbols << level @symbols.shift if @symbols.length > 128 next unless @symbols.length == 128 next unless @symbols.each_slice(2).all? { |a, b| a != b } bits = @symbols.each_slice(2).map(&:last) [bits, bits.map { |bit| bit ^ 1 }].each do |candidate| frame = RFID.parse_frame(bits: candidate) yield frame if frame && block_given? end end end |
#flush ⇒ Object
134 135 136 |
# File 'lib/pwn/sdr/decoder/rfid.rb', line 134 def flush @symbols.clear # Never pad a truncated frame into a tag. end |