This commit is contained in:
Jim Colderwood 2024-05-24 23:07:40 +01:00
commit b8138c0462
7 changed files with 224 additions and 0 deletions

3
README.md Normal file
View 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
View 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
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/usrpserv
go 1.22.2

73
main.go Normal file
View 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
View 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
View 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
View 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
}