Skip to content

Commit

Permalink
Implement Aircraft Operational Status V2 (Airborne / Surface) Message
Browse files Browse the repository at this point in the history
  • Loading branch information
Douglasdc3 committed Nov 16, 2020
1 parent e722e0b commit bc0e655
Show file tree
Hide file tree
Showing 10 changed files with 464 additions and 6 deletions.
7 changes: 7 additions & 0 deletions src/main/java/aero/t2s/modes/constants/AcasState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package aero.t2s.modes.constants;

public enum AcasState {
RA_NOT_ACTIVE,
RA_ACTIVE,
;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package aero.t2s.modes.constants;

public enum GeometricVerticalAccuracy {
UNKNOWN("Unknown or > 150m"),
LESS_THAN_150M("<=1 150M"),
LESS_THAN_45M("<= 45M"),
RESERVED("RESERVED (V3 will have a value < 45m)"),
;

private String probability;

GeometricVerticalAccuracy(String probability) {
this.probability = probability;
}

public static GeometricVerticalAccuracy from(int code) {
switch (code) {
case 0: return UNKNOWN;
case 1: return LESS_THAN_150M;
case 2: return LESS_THAN_45M;
case 3: return RESERVED;
default: throw new IllegalArgumentException("GVA " + code + " is not valid");
}
}

@Override
public String toString() {
return probability;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package aero.t2s.modes.constants;

public enum NavigationIntegrityCategory {
UNKNOWN("Rc unknown"),
RC_20_NM("Rc < 20 NM (37.04 km)"),
RC_8_NM("Rc < 8 NM (14.816 km)"),
RC_4_NM("Rc < 4 NM (7.408 km)"),
RC_2_NM("Rc < 2 NM (3.704 km)"),
RC_1_NM("Rc < 1 NM (1852 m)"),
RC_0_6_NM("Rc < 0.6 NM (1111.2 m)"),
RC_0_5_NM("Rc < 0.5 NM (926 m)"),
RC_0_3_NM("Rc < 0.3 NM (555.6 m)"),
RC_0_2_NM("Rc < 0.2 NM (370.4 m)"),
RC_0_1_NM("Rc < 0.1 NM (185.2 m)"),
RC_75_M("Rc < 75m"),
RC_25_M("Rc < 25m"),
RC_7_5_M("Rc < 7.5m"),
RESERVED_1("Reserved"),
RESERVED_2("Reserved"),
RESERVED_3("Reserved"),
RESERVED_4("Reserved"),
;

private String radiusContainment;

NavigationIntegrityCategory(String radiusContainment) {
this.radiusContainment = radiusContainment;
}

public static NavigationIntegrityCategory airborne(int nic, int nicA, int nicB) {
switch (nic) {
case 0: return UNKNOWN;
case 1: return RC_20_NM;
case 2: return RC_8_NM;
case 3: return RC_4_NM;
case 4: return RC_2_NM;
case 5: return RC_1_NM;
case 6:
if (nicA == 1) {
return RC_0_6_NM;
} else {
return nicB == 1 ? RC_0_3_NM : RC_0_5_NM;
}
case 7: return RC_0_2_NM;
case 8: return RC_0_1_NM;
case 9: return RC_75_M;
case 10: return RC_25_M;
case 11: return RC_7_5_M;
case 12: return RESERVED_1;
case 13: return RESERVED_2;
case 14: return RESERVED_3;
case 15: return RESERVED_4;
default: return UNKNOWN;
}
}

public static NavigationIntegrityCategory surface(int nic, int nicA) {
switch (nic) {
case 0: return UNKNOWN;
case 6:
if (nicA == 1) {
return RC_0_3_NM;
} else {
return RC_0_6_NM;
}
case 7: return RC_0_2_NM;
case 8: return RC_0_1_NM;
case 9: return RC_75_M;
case 10: return RC_25_M;
case 11: return RC_7_5_M;
case 12: return RESERVED_1;
case 13: return RESERVED_2;
case 14: return RESERVED_3;
case 15: return RESERVED_4;
default: return UNKNOWN;
}
}

@Override
public String toString() {
return radiusContainment;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package aero.t2s.modes.constants;

public enum TargetChangeReportCapability {
NO_CAPABILITY,
SUPPORT_TC_PLUS_ZERO,
SUPPORT_MULTIPLE_TC,
RESERVED
;

public static TargetChangeReportCapability from(int code) {
switch (code) {
case 0: return NO_CAPABILITY;
case 1: return SUPPORT_TC_PLUS_ZERO;
case 2: return SUPPORT_MULTIPLE_TC;
case 3: return RESERVED;
default:
throw new IllegalArgumentException("Target Change Report Capability " + code + " is not valid");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,76 @@
package aero.t2s.modes.decoder.df.df17;

import aero.t2s.modes.NotImplementedException;
import aero.t2s.modes.Track;
import aero.t2s.modes.constants.Version;
import aero.t2s.modes.constants.*;
import aero.t2s.modes.decoder.df.df17.data.AirborneCapability;
import aero.t2s.modes.decoder.df.df17.data.AirborneOperationalMode;

public class AircraftOperationalStatusVersion2Airborne extends AircraftOperationalStatusVersion2 {
private AirborneCapability capability;
private AirborneOperationalMode operationalMode;
private SourceIntegrityLevelSupplement SILsupp;
private BarometricAltitudeIntegrityCode NICbaro;
private NavigationIntegrityCategory NICp;
private SourceIntegrityLevel SIL;
private Angle horizontalSource;
private GeometricVerticalAccuracy gva;

public AircraftOperationalStatusVersion2Airborne(short[] data) {
super(data);
}

@Override
public AircraftOperationalStatusVersion2Airborne decode() {
throw new NotImplementedException("AircraftOperationalStatusVersion2Airborne not implemented");
capability = new AirborneCapability((data[5] << 8) | data[6]);
operationalMode = new AirborneOperationalMode((data[7] << 8) | data[8]);

int NICsuppA = (data[9] & 0b00010000) >>> 4;
int NACp = (data[9] & 0b00001111);
NICp = NavigationIntegrityCategory.airborne(NACp, NICsuppA, 0);

gva = GeometricVerticalAccuracy.from((data[10] & 0b11000000) >>> 6);
SIL = SourceIntegrityLevel.from((data[10] & 0b000110000) >>> 4);
NICbaro = BarometricAltitudeIntegrityCode.from((data[10] & 0b00001000) >>> 3);
horizontalSource = (data[10] & 0b00000100) != 0 ? Angle.TRUE_HEADING : Angle.MAGNETIC_HEADING;
SILsupp = SourceIntegrityLevelSupplement.from((data[10] & 0b00000010) >>> 1);

return this;
}

@Override
public void apply(Track track) {
track.setVersion(Version.VERSION2);
}

public AirborneCapability getCapability() {
return capability;
}

public AirborneOperationalMode getOperationalMode() {
return operationalMode;
}

public SourceIntegrityLevelSupplement getSILsupp() {
return SILsupp;
}

public BarometricAltitudeIntegrityCode getNICbaro() {
return NICbaro;
}

public NavigationIntegrityCategory getNICp() {
return NICp;
}

public SourceIntegrityLevel getSIL() {
return SIL;
}

public Angle getHorizontalSource() {
return horizontalSource;
}

public GeometricVerticalAccuracy getGva() {
return gva;
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,83 @@
package aero.t2s.modes.decoder.df.df17;

import aero.t2s.modes.NotImplementedException;
import aero.t2s.modes.Track;
import aero.t2s.modes.constants.Version;
import aero.t2s.modes.constants.*;
import aero.t2s.modes.decoder.df.df17.data.SurfaceCapability;
import aero.t2s.modes.decoder.df.df17.data.SurfaceOperationalMode;

public class AircraftOperationalStatusVersion2Surface extends AircraftOperationalStatusVersion2 {
private SurfaceCapability surfaceCapability;
private SurfaceOperationalMode operationalMode;
private LengthWidthCode lengthWidthCode;
private NavigationIntegrityCategory NICp;
private Angle horizontalSource;
private SourceIntegrityLevelSupplement SILsupp;
private SourceIntegrityLevel SIL;

public AircraftOperationalStatusVersion2Surface(short[] data) {
super(data);
}

@Override
public AircraftOperationalStatusVersion2Surface decode() {
throw new NotImplementedException("AircraftOperationalStatusVersion2Airborne not implemented");
surfaceCapability = new SurfaceCapability((data[5] << 4) | (data[6] & 0b11110000) >>> 4);
lengthWidthCode = LengthWidthCode.from(data[6] & 0b00001111);
operationalMode = new SurfaceOperationalMode((data[7] << 8) | data[8]);

SIL = SourceIntegrityLevel.from((data[10] & 0b000110000) >>> 4);
SILsupp = SourceIntegrityLevelSupplement.from((data[10] & 0b00000010) >>> 1);

int NICsuppA = (data[9] & 0b00010000) >>> 4;
int NACp = (data[9] & 0b00001111);
NICp = NavigationIntegrityCategory.surface(NACp, NICsuppA);

if ((data[10] & 0b00001000) != 0) {
if ((data[10] & 0b00000100) != 0) {
horizontalSource = Angle.TRUE_TRACK;
} else {
horizontalSource = Angle.MAGNETIC_TRACK;
}
} else {
if ((data[10] & 0b00000100) != 0) {
horizontalSource = Angle.TRUE_HEADING;
} else {
horizontalSource = Angle.MAGNETIC_HEADING;
}
}

return this;
}

@Override
public void apply(Track track) {
track.setVersion(Version.VERSION2);
}

public SurfaceCapability getSurfaceCapability() {
return surfaceCapability;
}

public SurfaceOperationalMode getOperationalMode() {
return operationalMode;
}

public LengthWidthCode getLengthWidthCode() {
return lengthWidthCode;
}

public NavigationIntegrityCategory getNICp() {
return NICp;
}

public Angle getHorizontalSource() {
return horizontalSource;
}

public SourceIntegrityLevelSupplement getSILsupp() {
return SILsupp;
}

public SourceIntegrityLevel getSIL() {
return SIL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package aero.t2s.modes.decoder.df.df17.data;

import aero.t2s.modes.constants.TargetChangeReportCapability;

public class AirborneCapability {
private boolean acasOperational;
private boolean receive1090ES;
private boolean sendAirReferencedVelocityReport;
private boolean sendTargetSateReport;
private TargetChangeReportCapability targetChangeReportCapability;
private boolean uatReceive;

public AirborneCapability(int data) {
acasOperational = (data & 0b0010000000000000) != 0;
receive1090ES = (data & 0b0001000000000000) != 0;
sendAirReferencedVelocityReport = (data & 0b0000001000000000) != 0;
sendTargetSateReport = (data & 0b0000000100000000) != 0;
targetChangeReportCapability = TargetChangeReportCapability.from((data & 0b0000000011000000) >>> 6);
uatReceive = (data & 0b0000000000100000) != 0;
}

public boolean isAcasOperational() {
return acasOperational;
}

public boolean isReceive1090ES() {
return receive1090ES;
}

public boolean isSendAirReferencedVelocityReport() {
return sendAirReferencedVelocityReport;
}

public boolean isSendTargetSateReport() {
return sendTargetSateReport;
}

public TargetChangeReportCapability getTargetChangeReportCapability() {
return targetChangeReportCapability;
}

public boolean isUatReceive() {
return uatReceive;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package aero.t2s.modes.decoder.df.df17.data;

import aero.t2s.modes.constants.AcasState;
import aero.t2s.modes.constants.SourceIntegrityLevel;

public class AirborneOperationalMode {
private AcasState acasRA;
private boolean acasIdent;
private boolean singleAntennaFlag;
private SourceIntegrityLevel systemDesignAssurance;

public AirborneOperationalMode(int data) {
acasRA = (data & 0b0010000000000000) != 0 ? AcasState.RA_ACTIVE : AcasState.RA_NOT_ACTIVE;
acasIdent = (data & 0b0001000000000000) != 0;
singleAntennaFlag = (data & 0b0000010000000000) != 0;
systemDesignAssurance = SourceIntegrityLevel.from((data & 0b0000001100000000) >>> 8);
}

public AcasState getAcasRA() {
return acasRA;
}

public boolean isAcasIdent() {
return acasIdent;
}

public boolean isSingleAntennaFlag() {
return singleAntennaFlag;
}

public SourceIntegrityLevel getSystemDesignAssurance() {
return systemDesignAssurance;
}
}
Loading

0 comments on commit bc0e655

Please sign in to comment.