Renamed repo
parent
f9646e9667
commit
174b460919
@ -0,0 +1,398 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/tehmaze/go-dmr/bit"
|
||||
"github.com/tehmaze/go-dmr/dmr"
|
||||
"github.com/tehmaze/go-dmr/dmr/repeater"
|
||||
"github.com/tehmaze/go-dmr/homebrew"
|
||||
"github.com/tehmaze/go-dmr/ipsc"
|
||||
)
|
||||
|
||||
var (
|
||||
bursttypes = map[uint32]string{
|
||||
0: "pi header",
|
||||
1: "voice lc header",
|
||||
2: "terminator with lc",
|
||||
3: "csbk",
|
||||
4: "csbk",
|
||||
5: "appended mbc",
|
||||
6: "data header",
|
||||
7: "rate ½ data continuation",
|
||||
8: "rate ¾ data continuation",
|
||||
9: "idle",
|
||||
}
|
||||
headertypes = []string{
|
||||
"UDT ", "Resp", "UDat", "CDat", "Hdr4", "Hdr5", "Hdr6", "Hdr7",
|
||||
"Hdr8", "Hdr9", "Hdr10", "Hdr11", "Hdr12", "DSDa", "RSDa", "Prop",
|
||||
}
|
||||
saptypes = []string{
|
||||
"UDT", "1", "TCP HC", "UDP HC", "IP Pkt", "ARP Pkt", "6", "7",
|
||||
"8", "Prop Pkt", "Short Data", "11", "12", "13", "14", "15",
|
||||
}
|
||||
fidMap = [256]byte{
|
||||
0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
fidName = map[uint8]string{
|
||||
0: "Unknown",
|
||||
1: "Standard",
|
||||
2: "Flyde Micro",
|
||||
3: "PROD-EL SPA",
|
||||
4: "Motorola Connect+",
|
||||
5: "RADIODATA GmbH",
|
||||
6: "Hyteria (8)",
|
||||
7: "Motorola Capacity+",
|
||||
8: "EMC S.p.A (19)",
|
||||
9: "EMC S.p.A (28)",
|
||||
10: "Radio Activity Srl (51)",
|
||||
11: "Radio Activity Srl (60)",
|
||||
12: "Tait Electronics",
|
||||
13: "Hyteria (104)",
|
||||
14: "Vertex Standard",
|
||||
}
|
||||
)
|
||||
|
||||
func dumpFCLO(payload []byte, fid uint8) {
|
||||
fmt.Printf(" fid: %s (%d)\n", fidName[fid], fid)
|
||||
if fid == 0 || fid == 16 { // MotoTRBO Capacity+
|
||||
fmt.Printf(" fclo: -\n")
|
||||
}
|
||||
}
|
||||
|
||||
func dumpDataHeader(header []byte) {
|
||||
dh, err := dmr.ParseDataHeader(header, false)
|
||||
if err != nil {
|
||||
fmt.Printf(" data header error: %v\n", err)
|
||||
return
|
||||
}
|
||||
dc := dh.CommonHeader()
|
||||
fmt.Printf(" service accesspt: %d\n", dc.ServiceAccessPoint)
|
||||
fmt.Printf(" src id -> dst id: %d -> %d\n", dc.SrcID, dc.DstID)
|
||||
switch d := dh.(type) {
|
||||
case dmr.UDTDataHeader:
|
||||
fmt.Printf(" format..........: %s (%#02x)\n", dmr.UDTFormatName[d.Format], d.Format)
|
||||
fmt.Printf(" pad nibble......: %d\n", d.PadNibble)
|
||||
fmt.Printf(" appended blocks.: %d\n", d.AppendedBlocks)
|
||||
fmt.Printf(" supplementary f.: %b\n", d.SupplementaryFlag)
|
||||
fmt.Printf(" opcode..........: %d\n", d.OPCode)
|
||||
case dmr.UnconfirmedDataHeader:
|
||||
fmt.Printf(" pad octet count.: %d\n", d.PadOctetCount)
|
||||
fmt.Printf(" full message....: %b\n", d.FullMessage)
|
||||
fmt.Printf(" blocks to follow: %d\n", d.BlocksToFollow)
|
||||
fmt.Printf(" fragment seq.no.: %d\n", d.FragmentSequenceNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func dumpData(data bit.Bits) {
|
||||
var out = make([][]byte, 7)
|
||||
for y := 0; y < 7; y++ {
|
||||
out[y] = make([]byte, 80)
|
||||
for x := 0; x < 80; x++ {
|
||||
if x == 0 || x == 18 || x == 21 || x == 30 || x == 33 || x == 51 {
|
||||
out[y][x] = '|'
|
||||
} else {
|
||||
out[y][x] = ' '
|
||||
}
|
||||
}
|
||||
}
|
||||
// Info first half
|
||||
for i := 0; i < 98; i++ {
|
||||
var x = 1 + (i % 16)
|
||||
var y = (i / 16)
|
||||
if x > 8 {
|
||||
x++
|
||||
}
|
||||
if data[i] > 0 {
|
||||
out[y][x] = '1'
|
||||
} else {
|
||||
out[y][x] = '0'
|
||||
}
|
||||
}
|
||||
// Slot type first half
|
||||
for i := 98; i < 108; i++ {
|
||||
var x = 19 + ((i - 98) % 2)
|
||||
var y = (i - 98) / 2
|
||||
if data[i] > 0 {
|
||||
out[y][x] = '1'
|
||||
} else {
|
||||
out[y][x] = '0'
|
||||
}
|
||||
}
|
||||
// SYNC
|
||||
for i := 108; i < 156; i++ {
|
||||
var x = 22 + ((i - 108) % 8)
|
||||
var y = (i - 108) / 8
|
||||
if data[i] > 0 {
|
||||
out[y][x] = '1'
|
||||
} else {
|
||||
out[y][x] = '0'
|
||||
}
|
||||
}
|
||||
// Slot type second half
|
||||
for i := 156; i < 166; i++ {
|
||||
var x = 31 + ((i - 156) % 2)
|
||||
var y = (i - 156) / 2
|
||||
if data[i] > 0 {
|
||||
out[y][x] = '1'
|
||||
} else {
|
||||
out[y][x] = '0'
|
||||
}
|
||||
}
|
||||
// Info second half
|
||||
for i := 166; i < 264; i++ {
|
||||
var x = 34 + ((i - 166) % 16)
|
||||
var y = ((i - 166) / 16)
|
||||
if x > 41 {
|
||||
x++
|
||||
}
|
||||
if data[i] > 0 {
|
||||
out[y][x] = '1'
|
||||
} else {
|
||||
out[y][x] = '0'
|
||||
}
|
||||
}
|
||||
fmt.Println("|------INFO1------|ST|--SYNC--|ST|------INFO2------|")
|
||||
for _, row := range out {
|
||||
fmt.Println(string(row))
|
||||
}
|
||||
}
|
||||
|
||||
func dumpSync(p *ipsc.Packet, desc string) {
|
||||
sync := dmr.ExtractSyncBits(p.PayloadBits)
|
||||
patt := dmr.SyncPattern(sync)
|
||||
fmt.Printf("dmr[%d->%d]: ts%d got %s:\n", p.SrcID, p.DstID, p.Timeslot+1, desc)
|
||||
fmt.Printf(" sync pattern: %s\n", dmr.SyncPatternName[patt])
|
||||
if patt == dmr.SyncPatternUnknown {
|
||||
fmt.Print(hex.Dump(sync.Bytes()))
|
||||
for i, b := range sync {
|
||||
sync[i] = b ^ 1
|
||||
}
|
||||
fmt.Print(hex.Dump(sync.Bytes()))
|
||||
}
|
||||
|
||||
/*
|
||||
slot := dmr.ExtractSlotType(p.PayloadBits)
|
||||
var (
|
||||
codeword uint32
|
||||
bursttype uint32
|
||||
payload = make([]byte, 12)
|
||||
)
|
||||
|
||||
codeword = (uint32(slot[0]) << 11) | (uint32(slot[1]) << 3) | uint32(slot[2])>>5
|
||||
bursttype = uint32(slot[0]) & 7
|
||||
fmt.Printf("codeword: %#08x, bursttype: %#04x\n", codeword, bursttype)
|
||||
fec.Golay_23_12_Correct(&codeword)
|
||||
fmt.Printf("codeword: %#08x (after correcting)\n", codeword)
|
||||
codeword &= 0x0f
|
||||
fmt.Printf("codeword: %#08x (after masking)\n", codeword)
|
||||
bursttype ^= codeword
|
||||
var errors int
|
||||
if bursttype&1 > 0 {
|
||||
errors++
|
||||
}
|
||||
if bursttype&2 > 0 {
|
||||
errors++
|
||||
}
|
||||
if bursttype&4 > 0 {
|
||||
errors++
|
||||
}
|
||||
if bursttype&8 > 0 {
|
||||
errors++
|
||||
}
|
||||
bursttype = codeword
|
||||
//fmt.Printf("%d errors detected, burstype: %08x (%d)\n", errors, bursttype, bursttype)
|
||||
fmt.Printf(" burst type: %s (%d), %d errors\n", bursttypes[bursttype], bursttype, errors)
|
||||
|
||||
if bursttype < 7 {
|
||||
if err := bptc.Process(dmr.ExtractInfoBits(p.PayloadBits), payload); err != nil {
|
||||
fmt.Printf(" payload error: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf(" payload: (%d bytes)\n", len(payload))
|
||||
fmt.Print(" " + hex.Dump(payload))
|
||||
}
|
||||
|
||||
fid := payload[1]
|
||||
fidm := fidMap[fid]
|
||||
|
||||
switch bursttype {
|
||||
case 1, 2:
|
||||
dumpFCLO(payload, fidm)
|
||||
case 6:
|
||||
dumpDataHeader(payload)
|
||||
}
|
||||
|
||||
/*
|
||||
if err := fec.Golay_20_8_Check(slot); err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
fmt.Print(hex.Dump(slot.Bytes()))
|
||||
return
|
||||
}
|
||||
|
||||
cc := (slot[0] << 3) | (slot[1] << 2) | (slot[2] << 1) | slot[3]
|
||||
dt := (slot[4] << 3) | (slot[5] << 2) | (slot[6] << 1) | slot[7]
|
||||
fmt.Printf("cc: %d, data type: %d\n", cc, dt)
|
||||
*/
|
||||
}
|
||||
|
||||
func rc() *homebrew.RepeaterConfiguration {
|
||||
return &homebrew.RepeaterConfiguration{
|
||||
Callsign: "PI1BOL",
|
||||
RepeaterID: 2043044,
|
||||
RXFreq: 0,
|
||||
TXFreq: 0,
|
||||
TXPower: 0,
|
||||
ColorCode: 1,
|
||||
Latitude: 52.296786,
|
||||
Longitude: 4.595454,
|
||||
Height: 12,
|
||||
Location: "Hillegom, ZH, NL",
|
||||
Description: fmt.Sprintf("%s go-dmr", homebrew.Version),
|
||||
URL: "https://github.com/tehmaze",
|
||||
}
|
||||
}
|
||||
|
||||
func dumpRaw(raw []byte) {
|
||||
fmt.Printf("dump raw frame of %d bytes\n", len(raw))
|
||||
p, err := homebrew.ParseData(raw)
|
||||
if err != nil {
|
||||
fmt.Printf(" parse error: %v\n", err)
|
||||
return
|
||||
}
|
||||
dumpPacket(p)
|
||||
}
|
||||
|
||||
func dumpPacket(p *ipsc.Packet) {
|
||||
fmt.Print(p.Dump())
|
||||
dumpData(p.PayloadBits)
|
||||
|
||||
switch p.SlotType {
|
||||
case ipsc.VoiceLCHeader:
|
||||
dumpSync(p, "voice LC header")
|
||||
case ipsc.TerminatorWithLC:
|
||||
dumpSync(p, "terminator with LC")
|
||||
case ipsc.CSBK:
|
||||
dumpSync(p, "CSBK")
|
||||
case ipsc.VoiceDataA:
|
||||
dumpSync(p, "voice A")
|
||||
case ipsc.VoiceDataB:
|
||||
dumpSync(p, "voice B")
|
||||
case ipsc.VoiceDataC:
|
||||
dumpSync(p, "voice C")
|
||||
case ipsc.VoiceDataD:
|
||||
dumpSync(p, "voice D")
|
||||
case ipsc.VoiceDataE:
|
||||
dumpSync(p, "voice E")
|
||||
case ipsc.VoiceDataF:
|
||||
dumpSync(p, "voice F")
|
||||
}
|
||||
|
||||
fmt.Print("\n---\n\n")
|
||||
}
|
||||
|
||||
func main() {
|
||||
dumpFile := flag.String("dump", "", "dump file")
|
||||
liveFile := flag.String("live", "", "live configuration file")
|
||||
showRaw := flag.Bool("raw", false, "show raw frames")
|
||||
flag.Parse()
|
||||
|
||||
r := repeater.New()
|
||||
if *liveFile != "" {
|
||||
log.Printf("going in live mode using %q\n", *liveFile)
|
||||
f, err := os.Open(*liveFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
network := &homebrew.Network{}
|
||||
if err := yaml.Unmarshal(d, network); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
protocol, err := homebrew.New(network, rc, r.Stream)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
protocol.Dump = true
|
||||
panic(protocol.Run())
|
||||
|
||||
} else {
|
||||
|
||||
i, err := os.Open(*dumpFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer i.Close()
|
||||
|
||||
var raw = make([]byte, 53)
|
||||
for {
|
||||
if _, err := i.Read(raw); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if *showRaw {
|
||||
fmt.Println("raw packet:")
|
||||
fmt.Print(hex.Dump(raw))
|
||||
}
|
||||
|
||||
//dumpRaw(raw)
|
||||
|
||||
p, err := homebrew.ParseData(raw)
|
||||
if err != nil {
|
||||
fmt.Printf(" parse error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
r.Stream(p)
|
||||
|
||||
// Skip newline in recording
|
||||
if _, err := i.Seek(1, 1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"pd0mz/go-dmr/homebrew"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func rc() *homebrew.RepeaterConfiguration {
|
||||
return &homebrew.RepeaterConfiguration{
|
||||
Callsign: "PI1BOL",
|
||||
RepeaterID: 2043044,
|
||||
RXFreq: 433787500,
|
||||
TXFreq: 438787500,
|
||||
TXPower: 5,
|
||||
ColorCode: 1,
|
||||
Latitude: 52.296786,
|
||||
Longitude: 4.595454,
|
||||
Height: 12,
|
||||
Location: "Hillegom, ZH, NL",
|
||||
Description: fmt.Sprintf("%s go-dmr", homebrew.Version),
|
||||
URL: "https://github.com/pd0mz",
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
callType = map[homebrew.CallType]string{
|
||||
homebrew.GroupCall: "group",
|
||||
homebrew.UnitCall: "unit",
|
||||
}
|
||||
frameType = map[homebrew.FrameType]string{
|
||||
homebrew.Voice: "voice",
|
||||
homebrew.VoiceSync: "voice sync",
|
||||
homebrew.DataSync: "data sync",
|
||||
homebrew.UnusedFrameType: "unused (should not happen)",
|
||||
}
|
||||
)
|
||||
|
||||
func dump(d *homebrew.Frame) {
|
||||
fmt.Println("DMR data:")
|
||||
fmt.Printf("\tsequence: %d\n", d.Sequence)
|
||||
fmt.Printf("\ttarget..: %d -> %d\n", d.SrcID, d.DstID)
|
||||
fmt.Printf("\trepeater: %d\n", d.RepeaterID)
|
||||
fmt.Printf("\tslot....: %d\n", d.Slot())
|
||||
fmt.Printf("\tcall....: %s\n", callType[d.CallType()])
|
||||
fmt.Printf("\tframe...: %s\n", frameType[d.FrameType()])
|
||||
switch d.FrameType() {
|
||||
case homebrew.DataSync:
|
||||
fmt.Printf("\tdatatype: %d\n", d.DataType())
|
||||
case homebrew.Voice, homebrew.VoiceSync:
|
||||
fmt.Printf("\tsequence: %c (voice)\n", 'A'+d.DataType())
|
||||
}
|
||||
fmt.Printf("\tdump....:\n")
|
||||
fmt.Println(hex.Dump(d.DMR[:]))
|
||||
}
|
||||
|
||||
func main() {
|
||||
configFile := flag.String("config", "dmr-homebrew.yaml", "configuration file")
|
||||
flag.Parse()
|
||||
|
||||
f, err := os.Open(*configFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
network := &homebrew.Network{}
|
||||
if err := yaml.Unmarshal(d, network); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
repeater, err := homebrew.New(network, rc, dump)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
repeater.Dump = true
|
||||
panic(repeater.Run())
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"pd0mz/go-dmr/ipsc"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
configFile := flag.String("config", "dmr.yaml", "configuration file")
|
||||
flag.Parse()
|
||||
|
||||
f, err := os.Open(*configFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
network := &ipsc.Network{}
|
||||
if err := yaml.Unmarshal(d, network); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
repeater, err := ipsc.New(network)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
repeater.Dump = true
|
||||
panic(repeater.Run())
|
||||
}
|
Loading…
Reference in New Issue