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