Fixed code smells
This commit is contained in:
158
protocol/adsb/fields/bds05.go
Normal file
158
protocol/adsb/fields/bds05.go
Normal file
@@ -0,0 +1,158 @@
|
||||
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
|
||||
}
|
||||
208
protocol/adsb/fields/bds09.go
Normal file
208
protocol/adsb/fields/bds09.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package fields
|
||||
|
||||
// NumericValueStatus is the status of the numeric values, such as air speed, velocity, etc.
|
||||
type NumericValueStatus byte
|
||||
|
||||
const (
|
||||
NVSNoInformation NumericValueStatus = iota // No velocity information
|
||||
NVSRegular // Velocity is computed on the linear scale value of field * factor
|
||||
NVSMaximum // Velocity field value indicates velocity greater the maximum of the scale
|
||||
)
|
||||
|
||||
// ParseHeightDifference reads the Height difference from a 56 bits data field
|
||||
func ParseHeightDifference(data []byte) (int16, NumericValueStatus) {
|
||||
negative := data[6]&0x80 != 0
|
||||
difference := int16(data[6] & 0x7F)
|
||||
|
||||
if difference == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if difference >= 127 {
|
||||
if negative {
|
||||
return -3150, NVSMaximum
|
||||
} else {
|
||||
return 3150, NVSMaximum
|
||||
}
|
||||
}
|
||||
|
||||
difference = (difference - 1) * 25
|
||||
if negative {
|
||||
difference = -difference
|
||||
}
|
||||
|
||||
return difference, NVSRegular
|
||||
}
|
||||
|
||||
// VerticalRateSource is the Source Bit for Vertical Rate definition
|
||||
//
|
||||
// Specified in Doc 9871 / Table A-2-9
|
||||
type VerticalRateSource byte
|
||||
|
||||
const (
|
||||
VerticalRateSourceGNSS VerticalRateSource = iota // GNSS source
|
||||
VerticalRateSourceBarometric // Barometric source
|
||||
)
|
||||
|
||||
// DirectionNorthSouth is the Direction Bit NS Velocity definition
|
||||
//
|
||||
// Specified in Doc 9871 / Table A-2-9
|
||||
type DirectionNorthSouth byte
|
||||
|
||||
func ParseDirectionNorthSouth(data []byte) DirectionNorthSouth {
|
||||
return DirectionNorthSouth((data[3] & 0x80) >> 7)
|
||||
}
|
||||
|
||||
func ParseVelocityNorthSouthNormal(data []byte) (velocity uint16, status NumericValueStatus) {
|
||||
velocity = (uint16(data[3]&0x7F)<<8 | uint16(data[4]&0xE0)) >> 5
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 1023, NVSMaximum
|
||||
}
|
||||
return velocity - 1, NVSRegular
|
||||
}
|
||||
|
||||
func ParseVelocityNorthSouthSupersonic(data []byte) (velocity uint16, status NumericValueStatus) {
|
||||
velocity = (uint16(data[3]&0x7F)<<8 | uint16(data[4]&0xE0)) >> 5
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 4088, NVSMaximum
|
||||
}
|
||||
return (velocity - 1) * 4, NVSRegular
|
||||
}
|
||||
|
||||
const (
|
||||
DNSNorth DirectionNorthSouth = iota // North
|
||||
DNSSouth // South
|
||||
)
|
||||
|
||||
// DirectionEastWest is the Direction Bit EW Velocity definition
|
||||
//
|
||||
// Specified in Doc 9871 / Table A-2-9
|
||||
type DirectionEastWest byte
|
||||
|
||||
func ParseDirectionEastWest(data []byte) DirectionEastWest {
|
||||
return DirectionEastWest((data[1] & 0x04) >> 2)
|
||||
}
|
||||
|
||||
func ParseVelocityEastWestNormal(data []byte) (velocity uint16, status NumericValueStatus) {
|
||||
velocity = (uint16(data[1]&0x03) | uint16(data[2]))
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 1023, NVSMaximum
|
||||
}
|
||||
return velocity - 1, NVSRegular
|
||||
}
|
||||
|
||||
func ParseVelocityEastWestSupersonic(data []byte) (velocity uint16, status NumericValueStatus) {
|
||||
velocity = (uint16(data[1]&0x03) | uint16(data[2]))
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 4088, NVSMaximum
|
||||
}
|
||||
return (velocity - 1) * 4, NVSRegular
|
||||
}
|
||||
|
||||
const (
|
||||
DEWEast DirectionEastWest = iota // East
|
||||
DEWWest // West
|
||||
)
|
||||
|
||||
func ParseIntentChange(data []byte) bool {
|
||||
return (data[1]&0x80)>>7 != 0
|
||||
}
|
||||
|
||||
func ParseIFRCapability(data []byte) bool {
|
||||
return (data[1]&0x40)>>6 != 0
|
||||
}
|
||||
|
||||
// NavigationUncertaintyCategory is the Navigation Uncertainty Category definition
|
||||
//
|
||||
// Specified in Doc 9871 / Table A-2-9
|
||||
type NavigationUncertaintyCategory byte
|
||||
|
||||
const (
|
||||
NUCPUnknown NavigationUncertaintyCategory = iota // Unknown
|
||||
NUCPHorizontalLowerThan10VerticalLowerThan15Point2 // Horizontal < 10m/s and Vertical < 15.2m/s
|
||||
NUCPHorizontalLowerThan3VerticalLowerThan4Point6 // Horizontal < 3m/s and Vertical < 4.6m/s
|
||||
NUCPHorizontalLowerThan1VerticalLowerThan1Point5 // Horizontal < 1m/s and Vertical < 1.5m/s
|
||||
NUCPHorizontalLowerThan0Point3VerticalLowerThan0Point46 // Horizontal < 0.3m/s and Vertical < 0.46m/s
|
||||
)
|
||||
|
||||
func ParseeNavigationUncertaintyCategory(data []byte) NavigationUncertaintyCategory {
|
||||
return NavigationUncertaintyCategory((data[1] & 0x38) >> 3)
|
||||
}
|
||||
|
||||
func ParseMagneticHeading(data []byte) (heading float64, status bool) {
|
||||
status = (data[1]&0x04)>>2 != 0
|
||||
value := uint16(data[1]&0x03)<<8 | uint16(data[2])
|
||||
heading = float64(value) * 360 / 1024.0
|
||||
return
|
||||
}
|
||||
|
||||
func ParseAirspeedNormal(data []byte) (speed uint16, status NumericValueStatus) {
|
||||
velocity := (uint16(data[3]&0x7F)<<8 | uint16(data[4]&0xE0)) >> 5
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 1023, NVSMaximum
|
||||
}
|
||||
return velocity - 1, NVSRegular
|
||||
}
|
||||
|
||||
func ParseAirspeedSupersonic(data []byte) (speed uint16, status NumericValueStatus) {
|
||||
velocity := (uint16(data[3]&0x7F)<<8 | uint16(data[4]&0xE0)) >> 5
|
||||
if velocity == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if velocity >= 1023 {
|
||||
return 4088, NVSMaximum
|
||||
}
|
||||
return (velocity - 1) * 4, NVSRegular
|
||||
}
|
||||
|
||||
func ParseVerticalRateSource(data []byte) VerticalRateSource {
|
||||
return VerticalRateSource((data[4] & 0x10) >> 4)
|
||||
}
|
||||
|
||||
func ParseVerticalRate(data []byte) (rate int16, status NumericValueStatus) {
|
||||
negative := data[4]&0x08 != 0
|
||||
rate = int16(uint16(data[4]&0x07)<<8 | uint16(data[5]&0xFC))
|
||||
if rate == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if rate >= 511 {
|
||||
if negative {
|
||||
return -32640, NVSMaximum
|
||||
}
|
||||
return 32640, NVSMaximum
|
||||
}
|
||||
|
||||
rate = (rate - 1) * 64
|
||||
if negative {
|
||||
rate = -rate
|
||||
}
|
||||
return rate, NVSRegular
|
||||
}
|
||||
|
||||
func ParseHeightDifferenceFromBaro(data []byte) (difference int16, status NumericValueStatus) {
|
||||
negative := data[6]&0x80 != 0
|
||||
difference = int16(data[6] & 0x7F)
|
||||
|
||||
if difference == 0 {
|
||||
return 0, NVSNoInformation
|
||||
} else if difference >= 127 {
|
||||
if negative {
|
||||
return -3150, NVSMaximum
|
||||
} else {
|
||||
return 3150, NVSMaximum
|
||||
}
|
||||
}
|
||||
|
||||
difference = (difference - 1) * 25
|
||||
if negative {
|
||||
difference = -difference
|
||||
}
|
||||
|
||||
return difference, NVSRegular
|
||||
}
|
||||
21
protocol/adsb/fields/bds61.go
Normal file
21
protocol/adsb/fields/bds61.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package fields
|
||||
|
||||
// EmergencyPriorityStatus is the Emergency Priority Status definition
|
||||
//
|
||||
// Specified in Doc 9871 / Table B-2-97a
|
||||
type EmergencyPriorityStatus byte
|
||||
|
||||
const (
|
||||
EPSNoEmergency EmergencyPriorityStatus = iota // No emergency
|
||||
EPSGeneralEmergency // General emergency
|
||||
EPSLifeguardMedical // Lifeguard/medical emergency
|
||||
EPSMinimumFuel // Minimum fuel
|
||||
EPSNoCommunication // No communications
|
||||
EPSUnlawfulInterference // Unlawful interference
|
||||
EPSDownedAircraft // Downed aircraft
|
||||
EPSReserved7 // Reserved
|
||||
)
|
||||
|
||||
func ParseEmergencyPriorityStatus(data []byte) EmergencyPriorityStatus {
|
||||
return EmergencyPriorityStatus((data[1] & 0xE0) >> 5)
|
||||
}
|
||||
176
protocol/adsb/fields/bds62.go
Normal file
176
protocol/adsb/fields/bds62.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package fields
|
||||
|
||||
// VerticalDataAvailableSourceIndicator is the Vertical Data Available / Source Indicator definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.3
|
||||
type VerticalDataAvailableSourceIndicator byte
|
||||
|
||||
const (
|
||||
VDANoValidDataAvailable VerticalDataAvailableSourceIndicator = iota // No data available
|
||||
VDAAutopilot // Autopilot control panel selected value, such as Mode Control Panel (MCP) or Flight Control Unit (FCU)
|
||||
VDAHoldingAltitude // Holding altitude
|
||||
VDAFMS // FMS/RNAV system
|
||||
)
|
||||
|
||||
func ParseVerticalDataAvailableSourceIndicator(data []byte) VerticalDataAvailableSourceIndicator {
|
||||
return VerticalDataAvailableSourceIndicator((data[0]&0x01)<<1 + (data[1]&0x80)>>7)
|
||||
}
|
||||
|
||||
// TargetAltitudeType is the Target Altitude Type definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.4
|
||||
type TargetAltitudeType byte
|
||||
|
||||
const (
|
||||
TATReferencedToPressureAltitude TargetAltitudeType = iota // Referenced to pressure-altitude (flight level)
|
||||
TATReferencedToBarometricAltitude // Referenced to barometric corrected altitude (mean sea level)
|
||||
)
|
||||
|
||||
// ReadTargetAltitudeType reads the TargetAltitudeType from a 56 bits data field
|
||||
func ParseTargetAltitudeType(data []byte) TargetAltitudeType {
|
||||
return TargetAltitudeType((data[1] & 0x40) >> 6)
|
||||
}
|
||||
|
||||
// TargetAltitudeCapability is the Target Altitude Capability definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.5
|
||||
type TargetAltitudeCapability byte
|
||||
|
||||
const (
|
||||
TACAltitudeOnly TargetAltitudeCapability = iota // Holding altitude only
|
||||
TACAltitudeOrAutopilot // Either holding altitude or autopilot control panel selected altitude
|
||||
TACAltitudeOrAutopilotOrFMS // Either holding altitude, autopilot control panel selected altitude, or any FMS/RNAV level-off altitude
|
||||
TACReserved3 // Reserved
|
||||
)
|
||||
|
||||
// ParseTargetAltitudeCapability reads the TargetAltitudeCapability from a 56 bits data field
|
||||
func ParseTargetAltitudeCapability(data []byte) TargetAltitudeCapability {
|
||||
return TargetAltitudeCapability((data[1] & 0x18) >> 3)
|
||||
}
|
||||
|
||||
// VerticalModeIndicator is the Vertical Mode Indicator definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.6
|
||||
type VerticalModeIndicator byte
|
||||
|
||||
const (
|
||||
VMIUnknown VerticalModeIndicator = iota // Unknown mode or information unavailable
|
||||
VMIAcquiringMode // Acquiring Mode
|
||||
VMICapturingMode // Capturing or Maintaining Mode
|
||||
VMIReserved3 // Reserved
|
||||
)
|
||||
|
||||
// ParseVerticalModeIndicator reads the VerticalModeIndicator from a 56 bits data field
|
||||
func ParseVerticalModeIndicator(data []byte) VerticalModeIndicator {
|
||||
return VerticalModeIndicator((data[1] & 0x06) >> 1)
|
||||
}
|
||||
|
||||
// HorizontalDataAvailableSourceIndicator is the Horizontal Data Available / Source Indicator definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.8
|
||||
type HorizontalDataAvailableSourceIndicator byte
|
||||
|
||||
const (
|
||||
HDANoValidDataAvailable HorizontalDataAvailableSourceIndicator = iota // No data available
|
||||
HDAAutopilot // Autopilot control panel selected value, such as Mode Control Panel (MCP) or Flight Control Unit (FCU)
|
||||
HDAHoldingAltitude // Maintaining current heading or track angle (e.g. autopilot mode select)
|
||||
HDAFMS // FMS/RNAV system (indicates track angle specified by leg type)
|
||||
)
|
||||
|
||||
// ParseHorizontalDataAvailableSourceIndicator reads the HorizontalDataAvailableSourceIndicator from a 56 bits data field
|
||||
func ParseHorizontalDataAvailableSourceIndicator(data []byte) HorizontalDataAvailableSourceIndicator {
|
||||
return HorizontalDataAvailableSourceIndicator((data[3] & 0x60) >> 5)
|
||||
}
|
||||
|
||||
// TargetHeadingTrackIndicator is the Target Heading / Track Angle Indicator definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.10
|
||||
type TargetHeadingTrackIndicator byte
|
||||
|
||||
const (
|
||||
TargetTrackHeadingAngle TargetHeadingTrackIndicator = iota // Target heading angle is being reported
|
||||
TargetTrackAngle // Track angle is being reported
|
||||
|
||||
)
|
||||
|
||||
// ParseTargetHeadingTrackIndicator reads the TargetHeadingTrackIndicator from a 56 bits data field
|
||||
func ParseTargetHeadingTrackIndicator(data []byte) TargetHeadingTrackIndicator {
|
||||
return TargetHeadingTrackIndicator((data[4] & 0x08) >> 3)
|
||||
}
|
||||
|
||||
// ReadTargetHeadingTrackAngle reads the TargetAltitude from a 56 bits data field
|
||||
// Specified in Doc 9871 / B.2.3.9.9
|
||||
func ReadTargetHeadingTrackAngle(data []byte) (uint16, NumericValueStatus) {
|
||||
heading := (uint16(data[3]&0x1F)<<8 | uint16(data[2]&0xF0)) >> 4
|
||||
if heading > 359 {
|
||||
return 0, NVSMaximum
|
||||
}
|
||||
return heading, NVSRegular
|
||||
}
|
||||
|
||||
// HorizontalModeIndicator is the Horizontal Mode Indicator definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.11
|
||||
type HorizontalModeIndicator byte
|
||||
|
||||
const (
|
||||
HMIUnknown HorizontalModeIndicator = iota // Unknown mode or information unavailable
|
||||
HMIAcquiringMode // Acquiring Mode
|
||||
HMICapturingMode // Capturing or Maintaining Mode
|
||||
HMIReserved3 // Reserved
|
||||
)
|
||||
|
||||
// ParseHorizontalModeIndicator reads the HorizontalModeIndicator from a 56 bits data field
|
||||
func ParseHorizontalModeIndicator(data []byte) HorizontalModeIndicator {
|
||||
return HorizontalModeIndicator((data[4] & 0x06) >> 1)
|
||||
}
|
||||
|
||||
// NavigationalAccuracyCategoryPositionV1 is the Navigational Accuracy Category Position definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.12
|
||||
type NavigationalAccuracyCategoryPositionV1 byte
|
||||
|
||||
const (
|
||||
NACPV1EPUGreaterThan18Point52Km NavigationalAccuracyCategoryPositionV1 = iota // EPU >= 18.52 km (10 NM) - Unknown accuracy
|
||||
NACPV1EPULowerThan18Point52Km // EPU < 18.52 km (10 NM) - RNP-10 accuracy
|
||||
NACPV1EPULowerThan7Point408Km // EPU < 7.408 km (4 NM) - RNP-4 accuracy
|
||||
NACPV1EPULowerThan3Point704Km // EPU < 3.704 km (2 NM) - RNP-2 accuracy
|
||||
NACPV1EPUGreaterThan1852M // EPU < 1 852 m (1 NM) - RNP-1 accuracy
|
||||
NACPV1EPULowerThan926M // EPU < 926 m (0.5 NM) - RNP-0.5 accuracy
|
||||
NACPV1EPUGreaterThan555Point6M // EPU < 555.6 m ( 0.3 NM) - RNP-0.3 accuracy
|
||||
NACPV1EPULowerThan185Point2M // EPU < 185.2 m (0.1 NM) - RNP-0.1 accuracy
|
||||
NACPV1EPUGreaterThan92Point6M // EPU < 92.6 m (0.05 NM) - e.g. GPS (with SA)
|
||||
NACPV1EPULowerThan30MAndVEPULowerThan45M // EPU < 30 m and VEPU < 45 m - e.g. GPS (SA off)
|
||||
NACPV1EPULowerThan10MAndVEPULowerThan15M // EPU < 10 m and VEPU < 15 m - e.g. WAAS
|
||||
NACPV1EPULowerThan4MAndVEPULowerThan3M // EPU < 3 m and VEPU < 4 m - e.g. LAAS
|
||||
NACPV1Reserved12 // Reserved
|
||||
NACPV1Reserved13 // Reserved
|
||||
NACPV1Reserved14 // Reserved
|
||||
NACPV1Reserved15 // Reserved
|
||||
)
|
||||
|
||||
// ParseNavigationalAccuracyCategoryPositionV1 reads the NavigationalAccuracyCategoryPositionV1 from a 56 bits data field
|
||||
func ParseNavigationalAccuracyCategoryPositionV1(data []byte) NavigationalAccuracyCategoryPositionV1 {
|
||||
return NavigationalAccuracyCategoryPositionV1((data[4]&0x01)<<3 + (data[5]&0xE0)>>5)
|
||||
}
|
||||
|
||||
// NICBaro is the NIC Baro definition
|
||||
//
|
||||
// Specified in Doc 9871 / B.2.3.9.13
|
||||
type NICBaro byte
|
||||
|
||||
const (
|
||||
// NICBGilhamNotCrossChecked indicates that the barometric altitude that is being reported in the Airborne
|
||||
// Position Message is based on a Gilham coded input that has not been cross-checked against another source of
|
||||
// pressure-altitude
|
||||
NICBGilhamNotCrossChecked NICBaro = iota
|
||||
// NICBGilhamCrossCheckedOrNonGilham indicates that the barometric altitude that is being reported in the Airborne
|
||||
// Position Message is either based on a Gilham code input that has been cross-checked against another source of
|
||||
// pressure-altitude and verified as being consistent, or is based on a non-Gilham coded source
|
||||
NICBGilhamCrossCheckedOrNonGilham
|
||||
)
|
||||
|
||||
// ParseNICBaro reads the NICBaro from a 56 bits data field
|
||||
func ParseNICBaro(data []byte) NICBaro {
|
||||
return NICBaro((data[5] & 0x10) >> 4)
|
||||
}
|
||||
78
protocol/adsb/fields/util.go
Normal file
78
protocol/adsb/fields/util.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package fields
|
||||
|
||||
import "errors"
|
||||
|
||||
// GillhamToAltitude convert an altitude given in Gillham bits to an altitude in feet.
|
||||
func GillhamToAltitude(d1, d2, d4, a1, a2, a4, b1, b2, b4, c1, c2, c4 bool) (int32, error) {
|
||||
fiveHundredBits := uint16(0)
|
||||
if d1 {
|
||||
fiveHundredBits |= 0x0100
|
||||
}
|
||||
if d2 {
|
||||
fiveHundredBits |= 0x0080
|
||||
}
|
||||
if d4 {
|
||||
fiveHundredBits |= 0x0040
|
||||
}
|
||||
if a1 {
|
||||
fiveHundredBits |= 0x0020
|
||||
}
|
||||
if a2 {
|
||||
fiveHundredBits |= 0x0010
|
||||
}
|
||||
if a4 {
|
||||
fiveHundredBits |= 0x0008
|
||||
}
|
||||
if b1 {
|
||||
fiveHundredBits |= 0x0004
|
||||
}
|
||||
if b2 {
|
||||
fiveHundredBits |= 0x0002
|
||||
}
|
||||
if b4 {
|
||||
fiveHundredBits |= 0x0001
|
||||
}
|
||||
|
||||
oneHundredBits := uint16(0)
|
||||
if c1 {
|
||||
oneHundredBits |= 0x0004
|
||||
}
|
||||
if c2 {
|
||||
oneHundredBits |= 0x0002
|
||||
}
|
||||
if c4 {
|
||||
oneHundredBits |= 0x0001
|
||||
}
|
||||
|
||||
oneHundred := int32(grayToBinary(oneHundredBits))
|
||||
fiveHundred := int32(grayToBinary(fiveHundredBits))
|
||||
|
||||
// Check for invalid codes.
|
||||
if oneHundred == 5 || oneHundred == 6 || oneHundred == 0 {
|
||||
return 0, errors.New("the bits C1 to to C4 are incorrect")
|
||||
}
|
||||
|
||||
// Remove 7s from OneHundreds.
|
||||
if oneHundred == 7 {
|
||||
oneHundred = 5
|
||||
}
|
||||
|
||||
// Correct order of OneHundreds.
|
||||
if fiveHundred%2 != 0 {
|
||||
oneHundred = 6 - oneHundred
|
||||
}
|
||||
|
||||
// Convert to feet and apply altitude datum offset.
|
||||
return (int32(fiveHundred)*500 + int32(oneHundred)*100) - 1300, nil
|
||||
}
|
||||
|
||||
func grayToBinary(num uint16) uint16 {
|
||||
temp := uint16(0)
|
||||
|
||||
temp = num ^ (num >> 8)
|
||||
temp ^= temp >> 4
|
||||
temp ^= temp >> 2
|
||||
temp ^= temp >> 1
|
||||
|
||||
return temp
|
||||
}
|
||||
52
protocol/adsb/fields/util_test.go
Normal file
52
protocol/adsb/fields/util_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package fields
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGillhamToAltitude(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
Test string
|
||||
Want int32
|
||||
}{
|
||||
{"00000000010", -1000},
|
||||
{"00000001010", -500},
|
||||
{"00000011010", 0},
|
||||
{"00000011110", 100},
|
||||
{"00000010011", 600},
|
||||
{"00000110010", 1000},
|
||||
{"00001001001", 5800},
|
||||
{"00011100100", 10300},
|
||||
{"01100011010", 32000},
|
||||
{"01110000100", 46300},
|
||||
{"10000000011", 126600},
|
||||
{"10000000001", 126700},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Test, func(t *testing.T) {
|
||||
alt, err := GillhamToAltitude(testString2Bits(test.Test))
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
if alt != test.Want {
|
||||
t.Errorf("expected altitude %d, got %d", test.Want, alt)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testString2Bits(s string) (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool) {
|
||||
d2 := s[0] == '1'
|
||||
d4 := s[1] == '1'
|
||||
a1 := s[2] == '1'
|
||||
a2 := s[3] == '1'
|
||||
a4 := s[4] == '1'
|
||||
b1 := s[5] == '1'
|
||||
b2 := s[6] == '1'
|
||||
b4 := s[7] == '1'
|
||||
c1 := s[8] == '1'
|
||||
c2 := s[9] == '1'
|
||||
c4 := s[10] == '1'
|
||||
|
||||
return false, d2, d4, a1, a2, a4, b1, b2, b4, c1, c2, c4
|
||||
}
|
||||
Reference in New Issue
Block a user