github.com/la5nta/wl2k-go@v0.11.8/catalog/position_report.go (about) 1 // Copyright 2015 Martin Hebnes Pedersen (LA5NTA). All rights reserved. 2 // Use of this source code is governed by the MIT-license that can be 3 // found in the LICENSE file. 4 5 // Package catalog provides helpers for using the Winlink 2000 catalog services. 6 package catalog 7 8 import ( 9 "bytes" 10 "errors" 11 "fmt" 12 "math" 13 "time" 14 15 "github.com/la5nta/wl2k-go/fbb" 16 ) 17 18 type PosReport struct { 19 Date time.Time 20 Lat, Lon *float64 // In decimal degrees 21 Speed *float64 // Unit not specified in winlink docs 22 Course *Course 23 Comment string // Up to 80 characters 24 } 25 26 type Course struct { 27 Digits [3]byte 28 Magnetic bool 29 } 30 31 func NewCourse(degrees int, magnetic bool) (*Course, error) { 32 if degrees < 0 || degrees > 360 { 33 return nil, errors.New("degrees out of bounds [0,360]") 34 } 35 if degrees == 360 { 36 degrees = 0 37 } 38 c := Course{Magnetic: magnetic} 39 copy(c.Digits[:], []byte(fmt.Sprintf("%3d", degrees))) 40 return &c, nil 41 } 42 43 func (c Course) String() string { 44 if c.Magnetic { 45 return fmt.Sprintf("%sM", string(c.Digits[:])) 46 } else { 47 return fmt.Sprintf("%sT", string(c.Digits[:])) 48 } 49 } 50 51 func (p PosReport) Message(mycall string) *fbb.Message { 52 var buf bytes.Buffer 53 fmt.Fprintf(&buf, "DATE: %s\r\n", p.Date.UTC().Format(fbb.DateLayout)) 54 55 if p.Lat != nil && p.Lon != nil { 56 fmt.Fprintf(&buf, "LATITUDE: %s\r\n", decToMinDec(*p.Lat, true)) 57 fmt.Fprintf(&buf, "LONGITUDE: %s\r\n", decToMinDec(*p.Lon, false)) 58 } 59 if p.Speed != nil { 60 fmt.Fprintf(&buf, "SPEED: %f\r\n", *p.Speed) 61 } 62 if p.Course != nil { 63 fmt.Fprintf(&buf, "COURSE: %s\r\n", *p.Course) 64 } 65 if len(p.Comment) > 0 { 66 fmt.Fprintf(&buf, "COMMENT: %s\r\n", p.Comment) 67 } 68 69 msg := fbb.NewMessage(fbb.PositionReport, mycall) 70 71 err := msg.SetBody(buf.String()) 72 if err != nil { 73 panic(err) 74 } 75 76 msg.SetSubject("POSITION REPORT") 77 msg.AddTo("QTH") 78 79 return msg 80 } 81 82 // Format: 23-42.3N 83 func decToMinDec(dec float64, latitude bool) string { 84 var sign byte 85 if latitude && dec > 0 { 86 sign = 'N' 87 } else if latitude && dec < 0 { 88 sign = 'S' 89 } else if !latitude && dec > 0 { 90 sign = 'E' 91 } else if !latitude && dec < 0 { 92 sign = 'W' 93 } else { 94 sign = ' ' 95 } 96 97 deg := int(dec) 98 min := (dec - float64(deg)) * 60.0 99 100 var format string 101 if latitude { 102 format = "%02.0f-%07.4f%c" 103 } else { 104 format = "%03.0f-%07.4f%c" 105 } 106 107 return fmt.Sprintf(format, math.Abs(float64(deg)), math.Abs(min), sign) 108 }