package fields // SurveillanceStatus is the surveillance status // // Specified in Doc 9871 / A.2.3.2.6 type SurveillanceStatus byte const ( SSNoCondition SurveillanceStatus = iota // No aircraft category information SSPermanentAlert // Permanent alert (emergency condition) SSTemporaryAlert // Temporary alert (change in Mode A identity code other than emergency condition) SSSPICondition // SPI condition ) // AltitudeSource is the type of source of the Altitude: Barometric or GNSS. type AltitudeSource byte const ( AltitudeBarometric AltitudeSource = iota // Altitude is barometric altitude AltitudeGNSS // Altitude is GNSS height (HAE) ) // AltitudeReportMethod defines how the altitude is reported. type AltitudeReportMethod byte const ( AltitudeReport100FootIncrements AltitudeReportMethod = iota // 100-foot increments AltitudeReport25FootIncrements // 25-foot increments ) // CompactPositionReportingFormat is the CPR (Compact Position Reporting) format definition // // Specified in Doc 9871 / A.2.3.3.3 type CompactPositionReportingFormat byte const ( CPRFormatEven CompactPositionReportingFormat = iota // Even format coding CPRFormatOdd // Odd format coding ) func ParseCompactPositioningReportFormat(data []byte) CompactPositionReportingFormat { bits := (data[2] & 0x04) >> 2 return CompactPositionReportingFormat(bits) } func ParseAltitude(data []byte) (altitude int32, source AltitudeSource, method AltitudeReportMethod, err error) { source = AltitudeBarometric if format := (data[0] & 0xF8) >> 3; 20 <= format && format <= 22 { source = AltitudeGNSS } // Altitude code is a 12 bits fields, so read a uint16 // bit | 8 9 10 11 12 13 14 15| 16 17 18 19 20 21 22 23 | // message | x x x x x x x x| x x x x _ _ _ _ | // 100 foot |C1 A1 C2 A2 C4 A4 B1 Q| B2 D2 B4 D4 _ _ _ _ | // Get the Q bit if qBit := (data[1] & 0x01) != 0; qBit { // If the Q bit equals 1, the 11-bit field represented by bits 8 to 14 and 16 to 18 n := uint16(0) n |= uint16(data[1]&0xFE) << 3 n |= uint16(data[2]&0xF0) >> 4 return 25*int32(n) - 1000, source, AltitudeReport25FootIncrements, nil } // Otherwise, altitude is reported in 100 foot increments c1 := (data[1] & 0x80) != 0 a1 := (data[1] & 0x40) != 0 c2 := (data[1] & 0x20) != 0 a2 := (data[1] & 0x10) != 0 c4 := (data[1] & 0x08) != 0 a4 := (data[1] & 0x04) != 0 b1 := (data[1] & 0x02) != 0 b2 := (data[2] & 0x80) != 0 d2 := (data[2] & 0x40) != 0 b4 := (data[2] & 0x20) != 0 d4 := (data[2] & 0x10) != 0 if altitude, err = GillhamToAltitude(false, d2, d4, a1, a2, a4, b1, b2, b4, c1, c2, c4); err != nil { return } return } // MovementStatus is the status of the Movement information type MovementStatus int const ( // MSNoInformation indicates no information MSNoInformation MovementStatus = 0 // No information MSAircraftStopped MovementStatus = 1 // The aircraft is stopped MSAboveMaximum MovementStatus = 124 // The Movement is above the maximum MSReservedDecelerating MovementStatus = 125 // Reserved MSReservedAccelerating MovementStatus = 126 // Reserved MSReservedBackingUp MovementStatus = 127 // Reserved ) func ParseMovementStatus(data []byte) (float64, MovementStatus) { bits := (data[0]&0x07)<<4 + (data[1]&0xF0)>>4 status := MovementStatus(bits) return status.Speed(), status } // Speed in knots. func (status MovementStatus) Speed() float64 { if status == 0 || status == 1 || status > 124 { return 0 } else if 2 <= status && status <= 8 { return 0.125 + float64(status-2)*0.125 } else if 9 <= status && status <= 12 { return 1 + float64(status-9)*0.25 } else if 13 <= status && status <= 38 { return 2 + float64(status-13)*0.5 } else if 39 <= status && status <= 93 { return 15 + float64(status-39)*1.0 } else if 94 <= status && status <= 108 { return 70 + float64(status-94)*2.0 } else if 109 <= status && status <= 123 { return 100 + float64(status-109)*5.0 } // Movement max return 175 } // EncodedLatitude is the encoded latitude // // Specified in Doc 9871 / C.2.6 type EncodedLatitude uint32 func ParseEncodedLatitude(data []byte) EncodedLatitude { return EncodedLatitude((data[2]&0x02)>>1)<<16 | EncodedLatitude((data[2]&0x01)<<7+(data[3]&0xFE)>>1)<<8 | EncodedLatitude((data[3]&0x01)<<7+(data[4]&0xFE)>>1) } // EncodedLongitude is the encoded longitude // // Specified in Doc 9871 / C.2.6 type EncodedLongitude uint32 func ParseEncodedLongitude(data []byte) EncodedLongitude { return EncodedLongitude(data[4]&0x01)<<16 | EncodedLongitude(data[5])<<8 | EncodedLongitude(data[6]) } func ParseGroundTrackStatus(data []byte) (track float64, status bool) { status = (data[1] & 0x08) != 0 allBits := (uint16(data[1]&0x07)<<8 | uint16(data[2]&0xF0)) >> 4 track = float64(allBits) * 360.0 / 128.0 return } func ParseTimeSynchronizedToUTC(data []byte) bool { return ((data[2] & 0x08) >> 3) != 0 }