Initial import
This commit is contained in:
329
protocol/aprs/packet_test.go
Normal file
329
protocol/aprs/packet_test.go
Normal file
@@ -0,0 +1,329 @@
|
||||
package aprs
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const earthRadius = float64(6378100)
|
||||
|
||||
func testTime(day, hour, min, sec int) *time.Time {
|
||||
t := time.Date(0, 0, day, hour, min, sec, 0, time.UTC)
|
||||
return &t
|
||||
}
|
||||
|
||||
// haversin(θ) function
|
||||
func testHaversin(theta float64) float64 {
|
||||
return math.Pow(math.Sin(theta/2), 2)
|
||||
}
|
||||
|
||||
func testDistance(a *Position, b *Position) float64 {
|
||||
var (
|
||||
lat1 = a.Latitude * math.Pi / 180
|
||||
lng1 = a.Longitude * math.Pi / 180
|
||||
lat2 = b.Latitude * math.Pi / 180
|
||||
lng2 = b.Longitude * math.Pi / 180
|
||||
h = testHaversin(lat2-lat1) + math.Cos(lat1)*math.Cos(lat2)*testHaversin(lng2-lng1)
|
||||
)
|
||||
return 2 * earthRadius * math.Asin(math.Sqrt(h))
|
||||
}
|
||||
|
||||
func TestPacket(t *testing.T) {
|
||||
var tests = []struct {
|
||||
Raw string
|
||||
Src Address
|
||||
Dst Address
|
||||
PathLen int
|
||||
Type DataType
|
||||
Position *Position
|
||||
Velocity *Velocity
|
||||
PHG *PowerHeightGain
|
||||
DFS *OmniDFStrength
|
||||
Altitude float64
|
||||
Range float64
|
||||
Time *time.Time
|
||||
}{
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:!4903.50N/07201.75W-Test 001234",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('!'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:!4903.50N/07201.75W-Test /A=001234",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('!'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:!49 . N/072 . W-",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('!'),
|
||||
Position: &Position{Latitude: 49.0, Longitude: -72.000000},
|
||||
},
|
||||
/*
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:TheNet X-1J4 (BFLD)!4903.50N/07201.75Wn",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('!'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
},
|
||||
*/
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:@092345/4903.50N/07201.75W>Test1234",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('@'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(9, 23, 45, 0),
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:=4903.50N/07201.75W#PHG5132",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
PHG: &PowerHeightGain{'5', '1', '3', '2'},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:=4903.50N/07201.75W 225/000g000t050r000p001...h00b10138dU2k",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:@092345/4903.50N/07201.75W>088/036",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('@'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(9, 23, 45, 0),
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:@234517h4903.50N/07201.75W>PHG5132",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('@'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(0, 23, 45, 17),
|
||||
PHG: &PowerHeightGain{'5', '1', '3', '2'},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:@092345z4903.50N/07201.75W>RNG0050",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('@'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(9, 23, 45, 0),
|
||||
Range: 50,
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:/234517h4903.50N/07201.75W>DFS2360",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('/'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(0, 23, 45, 17),
|
||||
DFS: &OmniDFStrength{'2', '3', '6', '0'},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:@092345z4903.50N/07201.75W 090/000g000t066r000p000...dUII",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('@'),
|
||||
Position: &Position{Latitude: 49.058333, Longitude: -72.029167},
|
||||
Time: testTime(9, 23, 45, 00),
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:[IO91SX] 35 miles NNW of London",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('['),
|
||||
Position: &Position{Latitude: 51.958333, Longitude: -0.500000},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL>APRS,qAC:[IO91]",
|
||||
Src: MustParseAddress("N0CALL"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 1,
|
||||
Type: DataType('['),
|
||||
Position: &Position{Latitude: 51.0, Longitude: -2.0},
|
||||
},
|
||||
{
|
||||
Raw: "WX4GSO-9>APN382,qAR,WD4LSS:!3545.18NL07957.08W#PHG5680/R,W,85NC,NCn Mount Shepherd Piedmont Triad NC",
|
||||
Src: MustParseAddress("WX4GSO-9"),
|
||||
Dst: MustParseAddress("APN382"),
|
||||
PathLen: 2,
|
||||
Type: DataType('!'),
|
||||
Position: &Position{Latitude: 35.753000, Longitude: -79.951333},
|
||||
},
|
||||
{
|
||||
Raw: "PA4TW>APRS,qAS,PA4TW-2:=5216.28N/00510.05Er Remco, DMR:2041014, Soms QRV op PI2NOS",
|
||||
Src: MustParseAddress("PA4TW"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 2,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 52.271333, Longitude: 5.167500},
|
||||
},
|
||||
{
|
||||
Raw: "PA4TW-10>APRS,TCPIP*,qAC,FOURTH:=5220.18N/00453.25EIhttp://aprs.pa4tw.nl:14501/",
|
||||
Src: MustParseAddress("PA4TW-10"),
|
||||
Dst: MustParseAddress("APRS"),
|
||||
PathLen: 3,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 52.336333, Longitude: 4.887500},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL-1>T3PY1Y,KQ1L-8*,WIDE1,WIDE2-1,qAR:=/5L!!<*e7> sTComment",
|
||||
Src: MustParseAddress("N0CALL-1"),
|
||||
Dst: MustParseAddress("T3PY1Y"),
|
||||
PathLen: 4,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.5, Longitude: -72.75},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL-1>T3PY1Y,KQ1L-8*,WIDE1,WIDE2-1,qAR:=/5L!!<*e7>7P[",
|
||||
Src: MustParseAddress("N0CALL-1"),
|
||||
Dst: MustParseAddress("T3PY1Y"),
|
||||
PathLen: 4,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.5, Longitude: -72.75},
|
||||
Velocity: &Velocity{88.0, 36.2},
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL-1>T3PY1Y,KQ1L-8*,WIDE1,WIDE2-1,qAR:=/5L!!<*e7>{?!",
|
||||
Src: MustParseAddress("N0CALL-1"),
|
||||
Dst: MustParseAddress("T3PY1Y"),
|
||||
PathLen: 4,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.5, Longitude: -72.75},
|
||||
Range: 20.13,
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL-1>T3PY1Y,KQ1L-8*,WIDE1,WIDE2-1,qAR:=/5L!!<*e7OS]S",
|
||||
Src: MustParseAddress("N0CALL-1"),
|
||||
Dst: MustParseAddress("T3PY1Y"),
|
||||
PathLen: 4,
|
||||
Type: DataType('='),
|
||||
Position: &Position{Latitude: 49.5, Longitude: -72.75},
|
||||
Altitude: 10004,
|
||||
},
|
||||
{
|
||||
Raw: "N0CALL-1>T3PY1Y,KQ1L-8*,WIDE1,WIDE2-1,qAR:@092345z/5L!!<*e7>{?!",
|
||||
Src: MustParseAddress("N0CALL-1"),
|
||||
Dst: MustParseAddress("T3PY1Y"),
|
||||
PathLen: 4,
|
||||
Type: '@',
|
||||
Time: testTime(9, 23, 45, 0),
|
||||
Position: &Position{Latitude: 49.5, Longitude: -72.75},
|
||||
Range: 20.13,
|
||||
},
|
||||
{
|
||||
Raw: "PE1ROG-8>APLC13,qAS,PE1ROG-2:!/49[<P'PC>8pQLoRa___MOBIL___TEST",
|
||||
Src: MustParseAddress("PE1ROG-8"),
|
||||
Dst: MustParseAddress("APLC13"),
|
||||
PathLen: 2,
|
||||
Type: '!',
|
||||
},
|
||||
{
|
||||
Raw: "PE1ROG-1>APPM13,TCPIP*,qAC,T2PRT:>Running on Raspberry Pi with RTL dongle",
|
||||
Src: MustParseAddress("PE1ROG-1"),
|
||||
Dst: MustParseAddress("APPM13"),
|
||||
PathLen: 3,
|
||||
Type: '>',
|
||||
},
|
||||
{
|
||||
Raw: "PD0MZ-4>APE32L,WIDE1-1,qAR,PD0MZ-10:>LoRa APRS Tracker",
|
||||
Src: MustParseAddress("PD0MZ-4"),
|
||||
Dst: MustParseAddress("APE32L"),
|
||||
PathLen: 3,
|
||||
Type: '>',
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Raw, func(t *testing.T) {
|
||||
p, err := ParsePacket(test.Raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !p.Dst.EqualTo(test.Dst) {
|
||||
t.Fatalf("expected dst %s, got %s", test.Dst, p.Dst)
|
||||
}
|
||||
if !p.Src.EqualTo(test.Src) {
|
||||
t.Fatalf("expected src %s, got %s", test.Src, p.Src)
|
||||
}
|
||||
if len(p.Path) != test.PathLen {
|
||||
t.Fatalf("expected path length %d, got %d: %v", test.PathLen, len(p.Path), p.Path)
|
||||
}
|
||||
if p.Payload.Type() != test.Type {
|
||||
t.Fatalf("expected packet type %s [%c], got %s [%c]",
|
||||
test.Type, test.Type,
|
||||
p.Payload.Type(), p.Payload.Type())
|
||||
}
|
||||
if test.Altitude != 0 {
|
||||
if p.Altitude == 0 {
|
||||
t.Fatalf("expected altitude %f, got none", test.Altitude)
|
||||
}
|
||||
if math.Abs(test.Altitude-p.Altitude) > 1.0 {
|
||||
t.Fatalf("expected altitude %f, got %f", test.Altitude, p.Altitude)
|
||||
}
|
||||
}
|
||||
if test.Velocity != nil {
|
||||
if p.Velocity.Course == 0 {
|
||||
t.Fatalf("expected velocity %v, got none", test.Velocity)
|
||||
}
|
||||
if math.Abs(test.Velocity.Course-p.Velocity.Course) > 1.0 {
|
||||
t.Fatalf("expected course %f, got %f", test.Velocity.Course, p.Velocity.Course)
|
||||
}
|
||||
if math.Abs(test.Velocity.Speed-p.Velocity.Speed) > 1.0 {
|
||||
t.Fatalf("expected speed %f, got %f", test.Velocity.Speed, p.Velocity.Speed)
|
||||
}
|
||||
}
|
||||
if test.Range != 0 {
|
||||
if p.Range == 0 {
|
||||
t.Fatalf("expected range %f, got none", test.Range)
|
||||
}
|
||||
if math.Abs(test.Range-p.Range) > 0.1 {
|
||||
t.Fatalf("expected range %f, got %f", test.Range, p.Range)
|
||||
}
|
||||
}
|
||||
if test.Position != nil {
|
||||
if p.Position == nil {
|
||||
t.Fatalf("expected position %s, got none", test.Position)
|
||||
}
|
||||
if d := testDistance(test.Position, p.Position); d > 1.0 {
|
||||
t.Fatalf("expected position %s, got %s with distance %f meter", test.Position, p.Position, d)
|
||||
}
|
||||
}
|
||||
if test.Time != nil {
|
||||
if p.Time == nil {
|
||||
t.Fatalf("expected time %s", test.Time)
|
||||
}
|
||||
if test.Time.Sub(*p.Time) > time.Minute {
|
||||
t.Fatalf("expected time %s, got %s", test.Time, p.Time)
|
||||
}
|
||||
}
|
||||
//t.Logf("%#+v", p)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user