Added Radio.ID and refactored the Stats interface
Some checks failed
Run tests / test (1.25) (push) Failing after 1m0s
Run tests / test (stable) (push) Failing after 1m0s

This commit is contained in:
2026-03-17 08:33:06 +01:00
parent 8ec85821e4
commit 27e2da1943
15 changed files with 2045 additions and 22 deletions

View File

@@ -0,0 +1,219 @@
package aprs
import (
"errors"
"fmt"
)
var (
ErrLatitude = errors.New("aprs: invalid latitude")
ErrLongitude = errors.New("aprs: invalid longitude")
)
// Latitude is the north-south position. Positive values are North, negative are South.
type Latitude float64
func LatitudeFromDMH(degrees, minutes, hundreths int, north bool) Latitude {
v := float64(degrees) + float64(minutes)/60 + float64(hundreths)/6000
for v > 90 {
v -= 180
}
for v < -90 {
v += 180
}
if north {
return Latitude(v)
}
return -Latitude(v)
}
func (lat Latitude) DMH() (degrees, minutes, hundreths int, north bool) {
degrees = int(lat)
minutes = int((float64(lat) - float64(degrees)) * 60)
hundreths = int((float64(lat) - float64(degrees) - float64(minutes)/60) * 6000)
if hundreths == 100 {
hundreths = 0
minutes += 1
}
if minutes == 60 {
minutes = 0
degrees += 1
}
north = lat >= 0
return
}
func (lat *Latitude) ParseCompressed(b []byte) error {
if len(b) != 4 {
return ErrLatitude
}
n, err := base91Decode(string(b))
if err != nil {
return err
}
*lat = Latitude(90 - float64(n)/380926)
return nil
}
func (lat *Latitude) ParseUncompressed(b []byte) error {
if len(b) != 8 || b[4] != '.' {
return ErrLatitude
}
var north bool
switch b[7] {
case 'N':
north = true
case 'S':
north = false
default:
return ErrLatitude
}
var (
degrees, minutes, hundreths int
err error
)
if degrees, err = parseBytesWithSpaces(b[0:2]); err != nil {
return err
}
if minutes, err = parseBytesWithSpaces(b[2:4]); err != nil {
return err
}
if hundreths, err = parseBytesWithSpaces(b[5:7]); err != nil {
return err
}
*lat = LatitudeFromDMH(degrees, minutes, hundreths, north)
return nil
}
func (lat Latitude) Compressed(b []byte) {
v := int((90 - float64(lat)) * 380926.0)
base91Encode(b, v)
}
func (lat Latitude) Uncompressed(b []byte) {
var (
degrees, minutes, hundreths, north = lat.DMH()
v = fmt.Sprintf("%02d%02d.%02d", degrees, minutes, hundreths)
)
if north {
v += "N"
} else {
v += "S"
}
copy(b, []byte(b))
}
// Longitude is the east-west position. Positive values are East, negative are West.
type Longitude float64
func LongitudeFromDMH(degrees, minutes, hundreths int, east bool) Longitude {
v := float64(degrees) + float64(minutes)/60 + float64(hundreths)/6000
for v > 180 {
v -= 360
}
for v < -180 {
v += 360
}
if east {
return Longitude(v)
}
return -Longitude(v)
}
func (long Longitude) DMH() (degrees, minutes, hundreths int, east bool) {
degrees = int(long)
minutes = int((float64(long) - float64(degrees)) * 60)
hundreths = int((float64(long) - float64(degrees) - float64(minutes)/60) * 6000)
if hundreths == 100 {
hundreths = 0
minutes += 1
}
if minutes == 60 {
minutes = 0
degrees += 1
}
east = long >= 0
return
}
func (long *Longitude) ParseCompressed(b []byte) error {
if len(b) != 4 {
return ErrLatitude
}
n, err := base91Decode(string(b))
if err != nil {
return err
}
*long = Longitude(float64(n)/190463.0 - 180)
return nil
}
func (long *Longitude) ParseUncompressed(b []byte) error {
if len(b) != 9 || b[5] != '.' {
return ErrLongitude
}
var east bool
switch b[8] {
case 'E':
east = true
case 'W':
east = false
default:
return ErrLongitude
}
var (
degrees, minutes, hundreths int
err error
)
if degrees, err = parseBytesWithSpaces(b[0:3]); err != nil {
return err
}
if minutes, err = parseBytesWithSpaces(b[3:5]); err != nil {
return err
}
if hundreths, err = parseBytesWithSpaces(b[6:8]); err != nil {
return err
}
*long = LongitudeFromDMH(degrees, minutes, hundreths, east)
return nil
}
func (long Longitude) Compressed(b []byte) {
v := int((180 + float64(long)) * 190463)
base91Encode(b, v)
}
func (long Longitude) Uncompressed(b []byte) {
var (
degrees, minutes, hundreths, east = long.DMH()
v = fmt.Sprintf("%03d%02d.%02d", degrees, minutes, hundreths)
)
if east {
v += "E"
} else {
v += "W"
}
copy(b, []byte(b))
}