You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
3.8 KiB
Go
189 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
"github.com/google/gopacket"
|
|
"github.com/google/gopacket/pcap"
|
|
"github.com/gordonklaus/portaudio"
|
|
"github.com/tehmaze/go-dmr/bit"
|
|
"github.com/tehmaze/go-dmr/dmr/repeater"
|
|
"github.com/tehmaze/go-dmr/homebrew"
|
|
"github.com/tehmaze/go-dmr/ipsc"
|
|
"github.com/tehmaze/go-dsd"
|
|
)
|
|
|
|
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 main() {
|
|
dumpFile := flag.String("dump", "", "dump file")
|
|
pcapFile := flag.String("pcap", "", "PCAP file")
|
|
liveFile := flag.String("live", "", "live configuration file")
|
|
showRaw := flag.Bool("raw", false, "show raw frames")
|
|
audioTS := flag.Int("audiots", 0, "play audio from time slot (1 or 2)")
|
|
flag.Parse()
|
|
|
|
if *audioTS > 2 {
|
|
log.Fatalf("invalid time slot %d\n", *audioTS)
|
|
return
|
|
}
|
|
|
|
r := repeater.New()
|
|
|
|
if *audioTS > 0 {
|
|
ambeframe := make(chan float32)
|
|
|
|
vs := dsd.NewAMBEVoiceStream(3)
|
|
r.VoiceFrameFunc = func(p *ipsc.Packet, bits bit.Bits) {
|
|
var in = make([]byte, len(bits))
|
|
for i, b := range bits {
|
|
in[i] = byte(b)
|
|
}
|
|
|
|
samples, err := vs.Decode(in)
|
|
if err != nil {
|
|
log.Printf("error decoding AMBE3000 frame: %v\n", err)
|
|
return
|
|
}
|
|
for _, sample := range samples {
|
|
ambeframe <- sample
|
|
}
|
|
}
|
|
|
|
portaudio.Initialize()
|
|
defer portaudio.Terminate()
|
|
h, err := portaudio.DefaultHostApi()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
p := portaudio.LowLatencyParameters(nil, h.DefaultOutputDevice)
|
|
p.SampleRate = 8000
|
|
p.Output.Channels = 1
|
|
stream, err := portaudio.OpenStream(p, func(out []float32) {
|
|
for i := range out {
|
|
out[i] = <-ambeframe
|
|
}
|
|
})
|
|
if err != nil {
|
|
log.Printf("error streaming: %v\n", err)
|
|
return
|
|
}
|
|
defer stream.Close()
|
|
if err := stream.Start(); err != nil {
|
|
log.Printf("error streaming: %v\n", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case *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())
|
|
|
|
case *dumpFile != "":
|
|
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)
|
|
}
|
|
}
|
|
|
|
case *pcapFile != "":
|
|
var (
|
|
handle *pcap.Handle
|
|
err error
|
|
)
|
|
|
|
if handle, err = pcap.OpenOffline(*pcapFile); err != nil {
|
|
panic(err)
|
|
}
|
|
defer handle.Close()
|
|
|
|
dec := gopacket.DecodersByLayerName["Ethernet"]
|
|
source := gopacket.NewPacketSource(handle, dec)
|
|
for packet := range source.Packets() {
|
|
raw := packet.ApplicationLayer().Payload()
|
|
if *showRaw {
|
|
fmt.Println("raw packet:")
|
|
fmt.Print(hex.Dump(raw))
|
|
}
|
|
|
|
p, err := homebrew.ParseData(raw)
|
|
if err != nil {
|
|
fmt.Printf(" parse error: %v\n", err)
|
|
continue
|
|
}
|
|
r.Stream(p)
|
|
}
|
|
}
|
|
}
|