Cleanup
parent
b7c07ac7b3
commit
f9646e9667
@ -0,0 +1,65 @@
|
|||||||
|
package homebrew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pd0mz/go-dmr/bit"
|
||||||
|
"github.com/pd0mz/go-dmr/ipsc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseData reads a raw DMR data frame from the homebrew protocol and parses it as it were an IPSC packet.
|
||||||
|
func ParseData(data []byte) (*ipsc.Packet, error) {
|
||||||
|
if len(data) != 53 {
|
||||||
|
return nil, fmt.Errorf("invalid packet length %d, expected 53 bytes", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
slotType uint16
|
||||||
|
dataType = (data[15] & bit.B11110000) >> 4
|
||||||
|
frameType = (data[15] & bit.B00001100) >> 2
|
||||||
|
)
|
||||||
|
switch frameType {
|
||||||
|
case bit.B00000000, bit.B00000001: // voice/voice sync
|
||||||
|
switch dataType {
|
||||||
|
case bit.B00000000:
|
||||||
|
slotType = ipsc.VoiceDataA
|
||||||
|
case bit.B00000001:
|
||||||
|
slotType = ipsc.VoiceDataB
|
||||||
|
case bit.B00000010:
|
||||||
|
slotType = ipsc.VoiceDataC
|
||||||
|
case bit.B00000011:
|
||||||
|
slotType = ipsc.VoiceDataD
|
||||||
|
case bit.B00000100:
|
||||||
|
slotType = ipsc.VoiceDataE
|
||||||
|
case bit.B00000101:
|
||||||
|
slotType = ipsc.VoiceDataF
|
||||||
|
}
|
||||||
|
case bit.B00000010: // data sync
|
||||||
|
switch dataType {
|
||||||
|
case bit.B00000001:
|
||||||
|
slotType = ipsc.VoiceLCHeader
|
||||||
|
case bit.B00000010:
|
||||||
|
slotType = ipsc.TerminatorWithLC
|
||||||
|
case bit.B00000011:
|
||||||
|
slotType = ipsc.CSBK
|
||||||
|
case bit.B00000110:
|
||||||
|
slotType = ipsc.DataHeader
|
||||||
|
case bit.B00000111:
|
||||||
|
slotType = ipsc.Rate12Data
|
||||||
|
case bit.B00001000:
|
||||||
|
slotType = ipsc.Rate34Data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ipsc.Packet{
|
||||||
|
Timeslot: (data[15] & bit.B00000001),
|
||||||
|
CallType: (data[15] & bit.B00000010) >> 1,
|
||||||
|
FrameType: (data[15] & bit.B00001100) >> 2,
|
||||||
|
SlotType: slotType,
|
||||||
|
SrcID: uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]),
|
||||||
|
DstID: uint32(data[8])<<16 | uint32(data[9])<<8 | uint32(data[10]),
|
||||||
|
Payload: data[20:],
|
||||||
|
PayloadBits: bit.NewBits(data[20:]),
|
||||||
|
Sequence: data[4],
|
||||||
|
}, nil
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package ipsc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pd0mz/go-dmr/bit"
|
||||||
|
"github.com/pd0mz/go-dmr/dmr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
VoiceLCHeader uint16 = 0x1111
|
||||||
|
TerminatorWithLC uint16 = 0x2222
|
||||||
|
CSBK uint16 = 0x3333
|
||||||
|
DataHeader uint16 = 0x4444
|
||||||
|
Rate12Data uint16 = 0x5555
|
||||||
|
Rate34Data uint16 = 0x6666
|
||||||
|
VoiceDataA uint16 = 0xbbbb
|
||||||
|
VoiceDataB uint16 = 0xcccc
|
||||||
|
VoiceDataC uint16 = 0x7777
|
||||||
|
VoiceDataD uint16 = 0x8888
|
||||||
|
VoiceDataE uint16 = 0x9999
|
||||||
|
VoiceDataF uint16 = 0xaaaa
|
||||||
|
IPSCSync uint16 = 0xeeee
|
||||||
|
UnknownSlotType uint16 = 0x0000
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CallTypePrivate uint8 = iota
|
||||||
|
CallTypeGroup
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TimeslotName = map[uint8]string{
|
||||||
|
0x00: "TS1",
|
||||||
|
0x01: "TS2",
|
||||||
|
}
|
||||||
|
FrameTypeName = map[uint8]string{
|
||||||
|
0x00: "voice",
|
||||||
|
0x01: "voice sync",
|
||||||
|
0x02: "data sync",
|
||||||
|
0x03: "unused",
|
||||||
|
}
|
||||||
|
SlotTypeName = map[uint16]string{
|
||||||
|
0x0000: "unknown",
|
||||||
|
0x1111: "voice LC header",
|
||||||
|
0x2222: "terminator with LC",
|
||||||
|
0x3333: "CBSK",
|
||||||
|
0x4444: "data header",
|
||||||
|
0x5555: "rate 1/2 data",
|
||||||
|
0x6666: "rate 3/4 data",
|
||||||
|
0x7777: "voice data C",
|
||||||
|
0x8888: "voice data D",
|
||||||
|
0x9999: "voice data E",
|
||||||
|
0xaaaa: "voice data F",
|
||||||
|
0xbbbb: "voice data A",
|
||||||
|
0xcccc: "voice data B",
|
||||||
|
0xeeee: "IPSC sync",
|
||||||
|
}
|
||||||
|
CallTypeName = map[uint8]string{
|
||||||
|
0x00: "private",
|
||||||
|
0x01: "group",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Packet struct {
|
||||||
|
Timeslot uint8 // 0=ts1, 1=ts2
|
||||||
|
FrameType uint8
|
||||||
|
SlotType uint16
|
||||||
|
CallType uint8 // 0=private, 1=group
|
||||||
|
SrcID uint32
|
||||||
|
DstID uint32
|
||||||
|
Payload []byte // 34 bytes
|
||||||
|
PayloadBits bit.Bits // 264 bits
|
||||||
|
Sequence uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) Dump() string {
|
||||||
|
var s string
|
||||||
|
s += fmt.Sprintf("timeslot..: 0b%02b (%s)\n", p.Timeslot, TimeslotName[p.Timeslot])
|
||||||
|
s += fmt.Sprintf("frame type: 0b%02b (%s)\n", p.FrameType, FrameTypeName[p.FrameType])
|
||||||
|
s += fmt.Sprintf("slot type.: 0x%04x (%s)\n", p.SlotType, SlotTypeName[p.SlotType])
|
||||||
|
s += fmt.Sprintf("call type.: 0x%02x (%s)\n", p.CallType, CallTypeName[p.CallType])
|
||||||
|
s += fmt.Sprintf("source....: %d\n", p.SrcID)
|
||||||
|
s += fmt.Sprintf("target....: %d\n", p.DstID)
|
||||||
|
s += fmt.Sprintf("payload...: %d bytes (swapped):\n", len(p.Payload))
|
||||||
|
s += hex.Dump(p.Payload)
|
||||||
|
s += fmt.Sprintf("payload...: %d bits:\n", len(p.PayloadBits))
|
||||||
|
s += p.PayloadBits.Dump()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) InfoBits() bit.Bits {
|
||||||
|
var b = make(bit.Bits, dmr.InfoBits)
|
||||||
|
copy(b[0:dmr.InfoHalfBits], p.PayloadBits[0:dmr.InfoHalfBits])
|
||||||
|
copy(b[dmr.InfoHalfBits:], p.PayloadBits[dmr.InfoHalfBits+dmr.SlotTypeBits+dmr.SignalBits:])
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packet) VoiceBits() bit.Bits {
|
||||||
|
var b = make(bit.Bits, dmr.VoiceBits)
|
||||||
|
copy(b[:dmr.VoiceHalfBits], p.PayloadBits[:dmr.VoiceHalfBits])
|
||||||
|
copy(b[dmr.VoiceHalfBits:], p.PayloadBits[dmr.VoiceHalfBits+dmr.SignalBits:])
|
||||||
|
return b
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package ipsc
|
||||||
|
|
||||||
|
func SwapPayloadBytes(payload []byte) {
|
||||||
|
for i := 0; i < len(payload)-1; i += 2 {
|
||||||
|
payload[i], payload[i+1] = payload[i+1], payload[i]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue