-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathigc.go
279 lines (226 loc) · 6.62 KB
/
igc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Package igc parses IGC files.
//
// See https://www.fai.org/sites/default/files/igc_fr_specification_with_al8_2023-2-1_0.pdf.
package igc
import (
"io"
"strconv"
"time"
)
// An Error is an error at a line.
type Error struct {
Line int
Err error
}
func (e *Error) Error() string {
return strconv.Itoa(e.Line) + ": " + e.Err.Error()
}
func (e *Error) Unwrap() error {
return e.Err
}
// A Record is a record.
type Record interface {
Type() byte
Valid() bool
}
// A Source is the data source of an H record.
type Source byte
// Sources.
const (
SourceFlightRecorder Source = 'F'
SourceOther Source = 'O'
SourcePilot Source = 'P'
)
// A Validity is a GPS fix validity.
type Validity byte
// Validities.
const (
Validity2D Validity = 'V'
Validity3D Validity = 'A'
)
// A GPSQualifier is a GPS qualifier.
type GPSQualifier byte
// GPSQualifiers.
const (
GPSQualifierGPS GPSQualifier = '1'
GPSQualifierDGPS GPSQualifier = '2'
)
// An RecordAddition is an addition to a B, K, or N record.
type RecordAddition struct {
TLC string
StartColumn int
FinishColumn int
}
// An ARecord is an A record, which identifies the flight recorder.
type ARecord struct {
ManufacturerID string
UniqueFlightRecorderID string
AdditionalData string
}
func (r *ARecord) Type() byte { return 'A' }
func (r *ARecord) Valid() bool { return r != nil }
// A BRecord is a B record, which contains a fix.
type BRecord struct {
Time time.Time
Lat float64
Lon float64
Validity Validity
AltWGS84 float64
AltBarometric float64
Additions map[string]int
}
func (r *BRecord) Type() byte { return 'B' }
func (r *BRecord) Valid() bool { return r != nil }
// A CRecordDeclaration is a first C record, which contains the first line of a
// pre-declared task.
type CRecordDeclaration struct {
DeclarationTime time.Time
FlightYear int
FlightMonth int
FlightDay int
TaskNumber int
NumberOfTurnpoints int
Text string
}
func (r *CRecordDeclaration) Type() byte { return 'C' }
func (r *CRecordDeclaration) Valid() bool { return r != nil }
// A CRecordWaypoint is a C record, which contains a waypoint in a declared
// task.
type CRecordWaypoint struct {
Lat float64
Lon float64
Text string
}
func (r *CRecordWaypoint) Type() byte { return 'C' }
func (r *CRecordWaypoint) Valid() bool { return r != nil }
// A DRecord is a D record, which contains differential GPS information.
type DRecord struct {
GPSQualifier GPSQualifier
DGPSStationID int
}
func (r *DRecord) Type() byte { return 'D' }
func (r *DRecord) Valid() bool { return r != nil }
// An ERecord is an E record, which contains an event.
type ERecord struct {
Time time.Time
TLC string
Text string
}
func (r *ERecord) Type() byte { return 'E' }
func (r *ERecord) Valid() bool { return r != nil }
// An ERecordWithoutTLC is an E record without a three-letter code, which
// contains an event.
type ERecordWithoutTLC struct {
Time time.Time
Text string
}
func (r *ERecordWithoutTLC) Type() byte { return 'E' }
func (r *ERecordWithoutTLC) Valid() bool { return false }
// An FRecord is an F record, which contains satellite constellation
// information.
type FRecord struct {
Time time.Time
SatelliteIDs []int
}
func (r *FRecord) Type() byte { return 'F' }
func (r *FRecord) Valid() bool { return r != nil }
// A GRecord is a G record, which is a security record.
type GRecord struct {
Text string
}
func (r *GRecord) Type() byte { return 'G' }
// Valid returns whether the G record does not have any syntax errors. Since G
// records have freeform text, they never contain syntax errors, so this
// function always returns true.
//
// To determine whether a G record is valid cryptographically, use
// [github.com/twpayne/go-igc/civlovs] instead.
func (r *GRecord) Valid() bool { return r != nil }
// An HRecord is an H record, which is a header.
type HRecord struct {
Source Source
TLC string
LongName string
Value string
}
func (r *HRecord) Type() byte { return 'H' }
func (r *HRecord) Valid() bool { return r != nil }
// An HRecordWithInvalidSource is an H record, which is a header.
type HRecordWithInvalidSource struct {
Source string
TLC string
LongName string
Value string
}
func (r *HRecordWithInvalidSource) Type() byte { return 'H' }
func (r *HRecordWithInvalidSource) Valid() bool { return false }
// An HFDTERecord is an HFDTE record, which is a header containing the date.
type HFDTERecord struct {
HRecord
Date time.Time
FlightNumber int
}
// An IRecord is an I record, which contains additions to B records.
type IRecord struct {
Additions []RecordAddition
}
func (r *IRecord) Type() byte { return 'I' }
func (r *IRecord) Valid() bool { return r != nil }
// A JRecord is a J record, which contains additions to K records.
type JRecord struct {
Additions []RecordAddition
}
func (r *JRecord) Type() byte { return 'J' }
func (r *JRecord) Valid() bool { return r != nil }
// A KRecord is a K record, which contains information needed less frequently
// than fixes.
type KRecord struct {
Time time.Time
Additions map[string]int
}
func (r *KRecord) Type() byte { return 'K' }
func (r *KRecord) Valid() bool { return r != nil }
// An LRecord is an L record, which contains a log message.
type LRecord struct {
Input string
Text string
}
func (r *LRecord) Type() byte { return 'L' }
func (r *LRecord) Valid() bool { return r != nil }
// An LRecordWithoutTLC is an L record without a three-letter code, which
// contains a log message.
type LRecordWithoutTLC struct {
Text string
}
func (r *LRecordWithoutTLC) Type() byte { return 'L' }
func (r *LRecordWithoutTLC) Valid() bool { return false }
// An MRecord is an M record, which contains additions to N records.
type MRecord struct {
Additions []RecordAddition
}
func (r *MRecord) Type() byte { return 'M' }
func (r *MRecord) Valid() bool { return r != nil }
// A NRecord is a N record, which contains data not signed by the security
// signature.
type NRecord struct {
Time time.Time
Additions map[string]int
}
func (r *NRecord) Type() byte { return 'N' }
func (r *NRecord) Valid() bool { return r != nil }
// An IGC is a parsed IGC file.
type IGC struct {
Records []Record
BRecords []*BRecord
HRecordsByTLC map[string]*HRecord
KRecords []*KRecord
Errs []error
}
// Parse parses an IGC from r.
func Parse(r io.Reader, options ...ParseOption) (*IGC, error) {
return newParser(options...).parse(r)
}
// Parse parses an IGC from lines.
func ParseLines(lines []string, options ...ParseOption) (*IGC, error) {
return newParser(options...).parseLines(lines)
}