Skip to content

Commit 7f30323

Browse files
committed
Move decode and parse to protocol.
1 parent 6bfcafd commit 7f30323

File tree

2 files changed

+495
-0
lines changed

2 files changed

+495
-0
lines changed

protocol/decode.go

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
// RTLAMR - An rtl-sdr receiver for smart meters operating in the 900MHz ISM band.
2+
// Copyright (C) 2015 Douglas Hall
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published
6+
// by the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package protocol
18+
19+
import (
20+
"log"
21+
"math"
22+
"strings"
23+
"sync"
24+
)
25+
26+
// PacketConfig specifies packet-specific radio configuration.
27+
type PacketConfig struct {
28+
Protocol string
29+
Preamble string
30+
31+
DataRate int
32+
33+
BlockSize, BlockSize2 int
34+
ChipLength, SymbolLength int
35+
SampleRate int
36+
37+
PreambleSymbols, PacketSymbols int
38+
PreambleLength, PacketLength int
39+
40+
BufferLength int
41+
CenterFreq uint32
42+
}
43+
44+
func (d Decoder) Log() {
45+
log.Println("CenterFreq:", d.Cfg.CenterFreq)
46+
log.Println("SampleRate:", d.Cfg.SampleRate)
47+
log.Println("DataRate:", d.Cfg.DataRate)
48+
log.Println("ChipLength:", d.Cfg.ChipLength)
49+
log.Println("PreambleSymbols:", d.Cfg.PreambleSymbols)
50+
log.Println("PreambleLength:", d.Cfg.PreambleLength)
51+
log.Println("PacketSymbols:", d.Cfg.PacketSymbols)
52+
log.Println("PacketLength:", d.Cfg.PacketLength)
53+
54+
var preambles []string
55+
for preamble, _ := range d.preambleStrs {
56+
preambles = append(preambles, preamble)
57+
}
58+
59+
log.Println("Protocols:", strings.Join(d.protocols, ","))
60+
log.Println("Preambles:", strings.Join(preambles, ","))
61+
}
62+
63+
// Decoder contains buffers and radio configuration.
64+
type Decoder struct {
65+
Cfg PacketConfig
66+
wg *sync.WaitGroup
67+
68+
Signal []float64
69+
Quantized []byte
70+
71+
csum []float64
72+
demod Demodulator
73+
74+
preambleStrs map[string]bool
75+
preambles map[string][]Parser
76+
protocols []string
77+
78+
pkt []byte
79+
80+
packed []byte
81+
sIdxA, sIdxB []int
82+
}
83+
84+
func NewDecoder() Decoder {
85+
return Decoder{
86+
wg: new(sync.WaitGroup),
87+
preambles: make(map[string][]Parser),
88+
preambleStrs: make(map[string]bool),
89+
}
90+
}
91+
92+
func max(a, b int) int {
93+
if a > b {
94+
return a
95+
}
96+
return b
97+
}
98+
99+
// Using a single decoder, register protocols to pass off decoded packets to.
100+
func (d *Decoder) RegisterProtocol(p Parser) {
101+
// Protocols such as R900 require the use of internal decoder data for further processing.
102+
p.SetDecoder(d)
103+
104+
// Take the largest value for each protocol. Some values are simply overridden
105+
d.Cfg.CenterFreq = p.Cfg().CenterFreq
106+
d.Cfg.DataRate = max(d.Cfg.DataRate, p.Cfg().DataRate)
107+
d.Cfg.ChipLength = max(d.Cfg.ChipLength, p.Cfg().ChipLength)
108+
d.Cfg.PreambleSymbols = max(d.Cfg.PreambleSymbols, p.Cfg().PreambleSymbols)
109+
d.Cfg.PacketSymbols = max(d.Cfg.PacketSymbols, p.Cfg().PacketSymbols)
110+
111+
// Take a string of ascii 0's and 1's, convert them to numerical 0's and 1's.
112+
// This is used during preamble searching.
113+
preambleBytes := make([]byte, len(p.Cfg().Preamble))
114+
for idx, bit := range p.Cfg().Preamble {
115+
if bit == '1' {
116+
preambleBytes[idx] = 1
117+
}
118+
}
119+
120+
// Keep track of registered preambles for logging back to the user.
121+
d.preambleStrs[p.Cfg().Preamble] = true
122+
123+
// Associate the parser with the appropriate preamble.
124+
d.preambles[string(preambleBytes)] = append(d.preambles[string(preambleBytes)], p)
125+
126+
// Add the protocol to the list for logging back to the user.
127+
d.protocols = append(d.protocols, p.Cfg().Protocol)
128+
}
129+
130+
// Calculate lengths and allocate internal buffers.
131+
func (d *Decoder) Allocate() {
132+
d.Cfg.SymbolLength = d.Cfg.ChipLength << 1
133+
d.Cfg.SampleRate = d.Cfg.DataRate * d.Cfg.ChipLength
134+
135+
d.Cfg.PreambleLength = d.Cfg.PreambleSymbols * d.Cfg.SymbolLength
136+
d.Cfg.PacketLength = d.Cfg.PacketSymbols * d.Cfg.SymbolLength
137+
138+
d.Cfg.BlockSize = NextPowerOf2(d.Cfg.PreambleLength)
139+
d.Cfg.BlockSize2 = d.Cfg.BlockSize << 1
140+
141+
d.Cfg.BufferLength = d.Cfg.PacketLength + d.Cfg.BlockSize
142+
143+
// Allocate necessary buffers.
144+
d.Signal = make([]float64, d.Cfg.BlockSize+d.Cfg.SymbolLength)
145+
d.Quantized = make([]byte, d.Cfg.BufferLength)
146+
147+
d.csum = make([]float64, len(d.Signal)+1)
148+
149+
// Calculate magnitude lookup table specified by -fastmag flag.
150+
d.demod = NewMagLUT()
151+
152+
// Signal up to the final stage is 1-bit per byte. Allocate a buffer to
153+
// store packed version 8-bits per byte.
154+
d.pkt = make([]byte, (d.Cfg.PacketSymbols+7)>>3)
155+
156+
d.sIdxA = make([]int, 0, d.Cfg.BlockSize)
157+
d.sIdxB = make([]int, 0, d.Cfg.BlockSize)
158+
159+
d.packed = make([]byte, (d.Cfg.BlockSize+d.Cfg.PreambleLength+7)>>3)
160+
161+
return
162+
}
163+
164+
// Decode accepts a sample block and returns a channel of messages.
165+
func (d Decoder) Decode(input []byte) chan Message {
166+
// Shift buffers to append new block.
167+
copy(d.Signal, d.Signal[d.Cfg.BlockSize:])
168+
copy(d.Quantized, d.Quantized[d.Cfg.BlockSize:])
169+
170+
// Compute the magnitude of the new block.
171+
d.demod.Execute(input, d.Signal[d.Cfg.SymbolLength:])
172+
173+
// Perform matched filter on new block.
174+
d.Filter(d.Signal, d.Quantized[d.Cfg.PacketLength:])
175+
176+
msgCh := make(chan Message)
177+
178+
// For each preamble.
179+
for preamble, parsers := range d.preambles {
180+
// Get a list of packets with valid preambles.
181+
pkts := d.Slice(d.Search([]byte(preamble)))
182+
183+
// Increment the wait group for all the parsers we will run on these packets.
184+
d.wg.Add(len(parsers))
185+
186+
// For each parser, run it on the given packets.
187+
for _, p := range parsers {
188+
go p.Parse(pkts, msgCh, d.wg)
189+
}
190+
}
191+
192+
// Close the message channel when all of the parsers have finished.
193+
go func() {
194+
d.wg.Wait()
195+
close(msgCh)
196+
}()
197+
198+
return msgCh
199+
}
200+
201+
// A Demodulator knows how to demodulate an array of uint8 IQ samples into an
202+
// array of float64 samples.
203+
type Demodulator interface {
204+
Execute([]byte, []float64)
205+
}
206+
207+
// Default Magnitude Lookup Table
208+
type MagLUT []float64
209+
210+
// Pre-computes normalized squares with most common DC offset for rtl-sdr dongles.
211+
func NewMagLUT() (lut MagLUT) {
212+
lut = make([]float64, 0x100)
213+
for idx := range lut {
214+
lut[idx] = (127.5 - float64(idx)) / 127.5
215+
lut[idx] *= lut[idx]
216+
}
217+
return
218+
}
219+
220+
// Calculates complex magnitude on given IQ stream writing result to output.
221+
func (lut MagLUT) Execute(input []byte, output []float64) {
222+
i := 0
223+
for idx := range output {
224+
output[idx] = lut[input[i]] + lut[input[i+1]]
225+
i += 2
226+
}
227+
}
228+
229+
// Matched filter for Manchester coded signals. Output signal's sign at each
230+
// sample determines the bit-value due to Manchester symbol odd symmetry.
231+
func (d Decoder) Filter(input []float64, output []byte) {
232+
// Computing the cumulative summation over the signal simplifies
233+
// filtering to the difference of a pair of subtractions.
234+
var sum float64
235+
for idx, v := range input {
236+
sum += v
237+
d.csum[idx+1] = sum
238+
}
239+
240+
// Filter result is difference of summation of lower and upper chips.
241+
lower := d.csum[d.Cfg.ChipLength:]
242+
upper := d.csum[d.Cfg.SymbolLength:]
243+
for idx, l := range lower[:len(output)] {
244+
f := (l - d.csum[idx]) - (upper[idx] - l)
245+
output[idx] = 1 - byte(math.Float64bits(f)>>63)
246+
}
247+
248+
return
249+
}
250+
251+
// Return a list of indices into the quantized signal at which a valid preamble exists.
252+
func (d *Decoder) Search(preamble []byte) []int {
253+
symLenByte := d.Cfg.SymbolLength >> 3
254+
255+
// Pack the bit-wise quantized signal into bytes.
256+
for bIdx := range d.packed {
257+
var b byte
258+
for _, qBit := range d.Quantized[bIdx<<3 : (bIdx+1)<<3] {
259+
b = (b << 1) | qBit
260+
}
261+
d.packed[bIdx] = b
262+
}
263+
264+
// Filter out indices at which the preamble cannot exist.
265+
for pIdx, pBit := range preamble {
266+
pBit = (pBit ^ 1) * 0xFF
267+
offset := pIdx * symLenByte
268+
if pIdx == 0 {
269+
d.sIdxA = d.sIdxA[:0]
270+
for qIdx, b := range d.packed[:d.Cfg.BlockSize>>3] {
271+
if b != pBit {
272+
d.sIdxA = append(d.sIdxA, qIdx)
273+
}
274+
}
275+
} else {
276+
d.sIdxB, d.sIdxA = searchPassByte(pBit, d.packed[offset:], d.sIdxA, d.sIdxB[:0])
277+
278+
if len(d.sIdxA) == 0 {
279+
return nil
280+
}
281+
}
282+
}
283+
284+
symLen := d.Cfg.SymbolLength
285+
286+
// Unpack the indices from bytes to bits.
287+
d.sIdxB = d.sIdxB[:0]
288+
for _, qIdx := range d.sIdxA {
289+
for idx := 0; idx < 8; idx++ {
290+
d.sIdxB = append(d.sIdxB, (qIdx<<3)+idx)
291+
}
292+
}
293+
d.sIdxA, d.sIdxB = d.sIdxB, d.sIdxA
294+
295+
// Filter out indices at which the preamble does not exist.
296+
for pIdx, pBit := range preamble {
297+
offset := pIdx * symLen
298+
offsetQuantized := d.Quantized[offset : offset+d.Cfg.BlockSize]
299+
d.sIdxB, d.sIdxA = searchPass(pBit, offsetQuantized, d.sIdxA, d.sIdxB[:0])
300+
301+
if len(d.sIdxA) == 0 {
302+
return nil
303+
}
304+
}
305+
306+
return d.sIdxA
307+
}
308+
309+
func searchPassByte(pBit byte, sig []byte, a, b []int) ([]int, []int) {
310+
for _, qIdx := range a {
311+
if sig[qIdx] != pBit {
312+
b = append(b, qIdx)
313+
}
314+
}
315+
316+
return a, b
317+
}
318+
319+
func searchPass(pBit byte, sig []byte, a, b []int) ([]int, []int) {
320+
for _, qIdx := range a {
321+
if sig[qIdx] == pBit {
322+
b = append(b, qIdx)
323+
}
324+
}
325+
326+
return a, b
327+
}
328+
329+
// Given a list of indices the preamble exists at, sample the appropriate bits
330+
// of the signal's bit-decision. Pack bits of each index into an array of bytes
331+
// and return each packet.
332+
func (d Decoder) Slice(indices []int) (pkts []Data) {
333+
// For each of the indices the preamble exists at.
334+
for _, qIdx := range indices {
335+
// Check that we're still within the first sample block. We'll catch
336+
// the message on the next sample block otherwise.
337+
if qIdx > d.Cfg.BlockSize {
338+
continue
339+
}
340+
341+
// Packet is 1 bit per byte, pack to 8-bits per byte.
342+
for pIdx := 0; pIdx < d.Cfg.PacketSymbols; pIdx++ {
343+
d.pkt[pIdx>>3] <<= 1
344+
d.pkt[pIdx>>3] |= d.Quantized[qIdx+(pIdx*d.Cfg.SymbolLength)]
345+
}
346+
347+
// Store the packet in the seen map and append to the packet list.
348+
data := NewData(d.pkt)
349+
data.Idx = qIdx
350+
pkts = append(pkts, data)
351+
}
352+
353+
return
354+
}
355+
356+
func NextPowerOf2(v int) int {
357+
return 1 << uint(math.Ceil(math.Log2(float64(v))))
358+
}

0 commit comments

Comments
 (0)