init
This commit is contained in:
commit
b8138c0462
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# USRPSERV
|
||||
**This is a work in progress!**
|
||||
Very early stages, currently parses between MMDVM and Allstar using USRP.
|
28
config/config.go
Normal file
28
config/config.go
Normal file
@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
LocalAddr UDP `json:"localAddr"`
|
||||
RemoteAddr UDP `json:"remoteAddr"`
|
||||
}
|
||||
|
||||
type UDP struct {
|
||||
IP string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func ParseConfig(file string) (*Config, error) {
|
||||
raw, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var config Config
|
||||
if err = json.Unmarshal(raw, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
73
main.go
Normal file
73
main.go
Normal file
@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
config2 "github.com/usrpserv/config"
|
||||
"github.com/usrpserv/usrp"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config, err := config2.ParseConfig("config.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
client := usrp.NewClient(net.UDPAddr{Port: config.RemoteAddr.Port, IP: net.ParseIP(config.RemoteAddr.IP)},
|
||||
net.UDPAddr{Port: config.LocalAddr.Port, IP: net.ParseIP(config.LocalAddr.IP)})
|
||||
defer client.Sock.Close()
|
||||
connectedIP := make(map[string]net.UDPAddr, 1)
|
||||
listenAddr := net.UDPAddr{
|
||||
Port: 4810,
|
||||
IP: net.ParseIP("0.0.0.0"),
|
||||
}
|
||||
netListener, err := net.ListenUDP("udp", &listenAddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
buffer := make([]byte, 500)
|
||||
clientBuffer := make([]byte, 500)
|
||||
frame := usrp.NewFrame()
|
||||
go func() {
|
||||
for {
|
||||
n, clientAddr, err := netListener.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
_, ok := connectedIP[clientAddr.String()]
|
||||
if !ok {
|
||||
log.Println("Adding new client:", clientAddr.String())
|
||||
connectedIP[clientAddr.String()] = *clientAddr
|
||||
}
|
||||
if frame.Metadata == 0 {
|
||||
if err = frame.Init(buffer, n); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err = frame.Parse(buffer, n); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
if err = client.WriteFrame(buffer, n); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
if frame.PTT == 0 {
|
||||
log.Println("END OF TRANSMISSION")
|
||||
}
|
||||
}
|
||||
}()
|
||||
c := func(buffer []byte, size int) {
|
||||
for _, c := range connectedIP {
|
||||
_, err := netListener.WriteToUDP(buffer[:size], &c)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
client.Poll(clientBuffer, &c)
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
}
|
36
usrp/client.go
Normal file
36
usrp/client.go
Normal file
@ -0,0 +1,36 @@
|
||||
package usrp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
func NewClient(addr net.UDPAddr, laddr net.UDPAddr) Client {
|
||||
var client Client
|
||||
var err error
|
||||
client.Sock, err = net.DialUDP("udp4", &laddr, &addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *Client) WriteFrame(buffer []byte, n int) error {
|
||||
n, err := c.Sock.Write(buffer[:n])
|
||||
if err != nil || n == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Poll(buffer []byte, callback *func([]byte, int)) {
|
||||
go func() {
|
||||
for {
|
||||
n, err := c.Sock.Read(buffer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
(*callback)(buffer, n)
|
||||
}
|
||||
}()
|
||||
}
|
53
usrp/proto.go
Normal file
53
usrp/proto.go
Normal file
@ -0,0 +1,53 @@
|
||||
package usrp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewFrame() Frame {
|
||||
var frame Frame
|
||||
frame.Time = time.Now()
|
||||
return frame
|
||||
}
|
||||
|
||||
func (f *Frame) Init(buff []byte, n int) error {
|
||||
if err := IsValid(buff); err != nil {
|
||||
return err
|
||||
}
|
||||
/* Can't initialize existing frame */
|
||||
if f.Metadata == 2 {
|
||||
return errors.New("frame is already initialized")
|
||||
}
|
||||
f.Metadata = int8(buff[23])
|
||||
if f.Metadata == 2 {
|
||||
fmt.Println("meta data")
|
||||
callLen := buff[33]
|
||||
f.Callsign = string(buff[46 : 46+callLen])
|
||||
}
|
||||
f.Seq = binary.LittleEndian.Uint32(buff[4:9])
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsValid(buff []byte) error {
|
||||
if bytes.Compare(buff[0:4], []byte{'U', 'S', 'R', 'P'}) != 0 {
|
||||
return errors.New("not a valid USRP packet")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Frame) Parse(buff []byte, n int) error {
|
||||
if err := IsValid(buff); err != nil {
|
||||
return err
|
||||
}
|
||||
f.Seq = binary.BigEndian.Uint32(buff[4:9])
|
||||
if len(buff[32:n]) > 320 {
|
||||
return errors.New("too many bytes")
|
||||
}
|
||||
f.PTT = int8(buff[15])
|
||||
copy(f.PCM.Data[:], buff[32:])
|
||||
return nil
|
||||
}
|
28
usrp/types.go
Normal file
28
usrp/types.go
Normal file
@ -0,0 +1,28 @@
|
||||
package usrp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
METADATA int8 = 2
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
UDPAddr net.UDPAddr
|
||||
Sock *net.UDPConn
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
Seq uint32
|
||||
Metadata int8
|
||||
Callsign string
|
||||
Time time.Time
|
||||
PCM PCM
|
||||
PTT int8
|
||||
}
|
||||
|
||||
type PCM struct {
|
||||
Data [320]byte
|
||||
}
|
Loading…
Reference in New Issue
Block a user