Path fixes

pull/1/head
Wijnand Modderman-Lenstra 9 years ago
parent 3603905b6f
commit a7136447fc

6
.gitignore vendored

@ -22,3 +22,9 @@ _testmain.go
*.exe
*.test
*.prof
# Editor remains
*.swp
# Dump files
*.dump

@ -4,7 +4,8 @@ package bptc
import (
"errors"
"fmt"
"pd0mz/go-dmr/bit"
"github.com/pd0mz/go-dmr/bit"
)
type vector [4]bit.Bit

@ -0,0 +1,86 @@
// Package dmr contains generic message structures for the Digital Mobile Radio standard
package dmr
import (
"fmt"
"github.com/pd0mz/go-dmr/bit"
)
const (
InfoPartBits = 98
InfoBits = InfoPartBits * 2
SlotPartBits = 10
SlotBits = SlotPartBits * 2
PayloadPartBits = InfoPartBits + SlotPartBits
PayloadBits = PayloadPartBits * 2
SignalBits = 48
BurstBits = PayloadBits + SignalBits
)
// Table 9.2: SYNC Patterns
var SYNCPatterns = map[string]struct {
ControlMode string
PDU string
}{
"\x07\x05\x05\x0f\x0d\x07\x0d\x0f\x07\x05\x0f\x07": {"BS sourced", "voice"},
"\x0d\x0f\x0f\x05\x07\x0d\x07\x05\x0d\x0f\x05\x0d": {"BS sourced", "data"},
"\x07\x0f\x07\x0d\x05\x0d\x0d\x05\x07\x0d\x0f\x0d": {"MS sourced", "voice"},
"\x0d\x05\x0d\x07\x0f\x07\x07\x0f\x0d\x07\x05\x07": {"MS sourced", "data"},
"\x07\x07\x0d\x05\x05\x0f\x07\x0d\x0f\x0d\x07\x07": {"MS sourced", "rc sync"},
"\x05\x0d\x05\x07\x07\x0f\x07\x07\x05\x07\x0f\x0f": {"TDMA direct mode time slot 1", "voice"},
"\x0f\x07\x0f\x0d\x0d\x05\x0d\x0d\x0f\x0d\x05\x05": {"TDMA direct mode time slot 1", "data"},
"\x07\x0d\x0f\x0f\x0d\x05\x0f\x05\x05\x0d\x05\x0f": {"TDMA direct mode time slot 2", "voice"},
"\x0d\x07\x05\x05\x07\x0f\x05\x0f\x0f\x07\x0f\x05": {"TDMA direct mode time slot 2", "data"},
"\x0d\x0d\x07\x0f\x0f\x05\x0d\x07\x05\x07\x0d\x0d": {"Reserved SYNC pattern", "reserved"},
}
// Burst contains data from a single burst, see 4.2.2 Burst and frame structure
type Burst struct {
bits bit.Bits
}
func NewBurst(raw []byte) (*Burst, error) {
if len(raw)*8 != BurstBits {
return nil, fmt.Errorf("dmr: expected %d bits, got %d", BurstBits, len(raw)*8)
}
b := &Burst{}
b.bits = bit.NewBits(raw)
return b, nil
}
// Info returns the 196 bits of info in the burst. The data is usually BPTC(196, 96) encoded.
func (b *Burst) Info() bit.Bits {
// The info is contained in bits 0..98 and 166..216 for a total of 196 bits
var n = make(bit.Bits, InfoBits)
copy(n[0:InfoPartBits], b.bits[0:InfoPartBits])
copy(n[InfoPartBits:InfoBits], b.bits[InfoPartBits+SignalBits+SlotBits:BurstBits])
return n
}
// Payload returns the 216 bits of payload in the burst.
func (b *Burst) Payload() bit.Bits {
// The payload is contained in bits 0..108 and 156..264 for a total of 216 bits
var p = make(bit.Bits, PayloadBits)
copy(p[0:PayloadPartBits], b.bits[0:PayloadPartBits])
copy(p[PayloadPartBits:PayloadBits], b.bits[PayloadPartBits+SignalBits:BurstBits])
return p
}
// Signal returns the 48 bits of signal or SYNC information in the burst.
func (b *Burst) Signal() bit.Bits {
// The signal bits are contained in bits 108..156 for a total of 48 bits
var s = make(bit.Bits, SignalBits)
copy(s, b.bits[PayloadPartBits:PayloadPartBits+SignalBits])
return s
}
func (b *Burst) SlotType() uint32 {
/* The slottype is 20 bits, starting after the payload info */
var s uint32
for i := InfoPartBits; i < InfoPartBits+SlotBits; i++ {
var shift = uint32(20 - (i - InfoPartBits))
s = s | uint32(b.bits[i]<<shift)
}
return s
}

@ -119,6 +119,25 @@ type Frame struct {
DMR [33]byte
}
// Bytes packs the frame into bytes ready to send over the network.
func (f *Frame) Bytes() []byte {
var b = make([]byte, 53)
copy(b[:4], f.Signature[:])
b[4] = f.Sequence
b[5] = byte(f.SrcID >> 16)
b[6] = byte(f.SrcID >> 8)
b[7] = byte(f.SrcID)
b[8] = byte(f.DstID >> 16)
b[9] = byte(f.DstID >> 8)
b[10] = byte(f.DstID)
binary.BigEndian.PutUint32(b[11:15], f.RepeaterID)
b[15] = f.Flags
binary.BigEndian.PutUint32(b[16:20], f.StreamID)
copy(b[21:], f.DMR[:])
return b
}
// CallType returns if the current frame is a group or unit call.
func (f *Frame) CallType() CallType {
return CallType((f.Flags >> 1) & 0x01)
@ -149,8 +168,8 @@ func ParseFrame(data []byte) (*Frame, error) {
f := &Frame{}
copy(f.Signature[:], data[:4])
f.Sequence = data[4]
f.SrcID = binary.BigEndian.Uint32(append([]byte{0x00}, data[5:7]...))
f.DstID = binary.BigEndian.Uint32(append([]byte{0x00}, data[8:10]...))
f.SrcID = (uint32(data[5]) << 16) | (uint32(data[6]) << 8) | uint32(data[7])
f.DstID = (uint32(data[8]) << 16) | (uint32(data[9]) << 8) | uint32(data[10])
f.RepeaterID = binary.BigEndian.Uint32(data[11:15])
f.Flags = data[15]
f.StreamID = binary.BigEndian.Uint32(data[16:20])
@ -179,6 +198,11 @@ type Network struct {
MasterID uint32
}
type packet struct {
addr *net.UDPAddr
data []byte
}
type Link struct {
Dump bool
config ConfigFunc
@ -250,7 +274,9 @@ func (l *Link) Run() error {
return err
}
queue := make(chan packet)
go l.login()
go l.parse(queue)
for {
var (
@ -263,7 +289,7 @@ func (l *Link) Run() error {
continue
}
go l.parse(peer, data[:n])
queue <- packet{peer, data[:n]}
}
return nil
@ -304,7 +330,9 @@ func (l *Link) login() {
case authDone:
config := l.config().Bytes()
fmt.Printf(hex.Dump(config))
if l.Dump {
fmt.Printf(hex.Dump(config))
}
log.Printf("dmr/homebrew: logged in, sending %d bytes of repeater configuration\n", len(config))
if err := l.Send(l.master.addr, config); err != nil {
@ -342,88 +370,93 @@ func (l *Link) keepAlive() {
}
}
func (l *Link) parse(addr *net.UDPAddr, data []byte) {
size := len(data)
func (l *Link) parse(queue <-chan packet) {
for {
select {
case p := <-queue:
size := len(p.data)
if size < 4 {
continue
}
switch l.master.status {
case authNone:
if bytes.Equal(data, DMRData) {
return
}
if size < 14 {
return
}
packet := data[:6]
repeater, err := hex.DecodeString(string(data[6:14]))
if err != nil {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
switch l.master.status {
case authNone:
if bytes.Equal(p.data[:4], DMRData) {
return
}
if size < 14 {
return
}
packet := p.data[:6]
repeater, err := hex.DecodeString(string(p.data[6:14]))
if err != nil {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
switch {
case bytes.Equal(packet, MasterNAK):
log.Printf("dmr/homebrew: login refused by master %d\n", repeater)
l.master.status = authFail
break
case bytes.Equal(packet, MasterACK):
log.Printf("dmr/homebrew: login accepted by master %d\n", repeater)
l.master.secret = data[14:]
l.master.status = authBegin
break
default:
log.Printf("dmr/homebrew: unexpected login reply from master %d\n", repeater)
l.master.status = authFail
break
}
switch {
case bytes.Equal(packet, MasterNAK):
log.Printf("dmr/homebrew: login refused by master %d\n", repeater)
l.master.status = authFail
break
case bytes.Equal(packet, MasterACK):
log.Printf("dmr/homebrew: login accepted by master %d\n", repeater)
l.master.secret = p.data[14:]
l.master.status = authBegin
break
default:
log.Printf("dmr/homebrew: unexpected login reply from master %d\n", repeater)
l.master.status = authFail
break
}
case authBegin:
if bytes.Equal(data, DMRData) {
return
}
if size < 14 {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
packet := data[:6]
repeater, err := hex.DecodeString(string(data[6:14]))
if err != nil {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
case authBegin:
if bytes.Equal(p.data[:4], DMRData) {
return
}
if size < 14 {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
packet := p.data[:6]
repeater, err := hex.DecodeString(string(p.data[6:14]))
if err != nil {
log.Println("dmr/homebrew: unexpected login reply from master")
l.master.status = authFail
break
}
switch {
case bytes.Equal(packet, MasterNAK):
log.Printf("dmr/homebrew: authentication refused by master %d\n", repeater)
l.master.status = authFail
break
case bytes.Equal(packet, MasterACK):
log.Printf("dmr/homebrew: authentication accepted by master %d\n", repeater)
l.master.status = authDone
break
default:
log.Printf("dmr/homebrew: unexpected authentication reply from master %d\n", repeater)
l.master.status = authFail
break
}
switch {
case bytes.Equal(packet, MasterNAK):
log.Printf("dmr/homebrew: authentication refused by master %d\n", repeater)
l.master.status = authFail
break
case bytes.Equal(packet, MasterACK):
log.Printf("dmr/homebrew: authentication accepted by master %d\n", repeater)
l.master.status = authDone
break
default:
log.Printf("dmr/homebrew: unexpected authentication reply from master %d\n", repeater)
l.master.status = authFail
break
}
case authDone:
if len(data) < 4 {
return
}
switch {
case bytes.Equal(data[:4], DMRData):
if l.stream == nil {
return
}
frame, err := ParseFrame(data)
if err != nil {
log.Printf("error parsing DMR data: %v\n", err)
return
case authDone:
switch {
case bytes.Equal(p.data[:4], DMRData):
if l.stream == nil {
return
}
frame, err := ParseFrame(p.data)
if err != nil {
log.Printf("error parsing DMR data: %v\n", err)
return
}
l.stream(frame)
}
}
l.stream(frame)
}
}
}

Loading…
Cancel
Save