diff --git a/assets/static/js/modules/aircraft-manager.js b/assets/static/js/modules/aircraft-manager.js
index 37e9e0f..ac92646 100644
--- a/assets/static/js/modules/aircraft-manager.js
+++ b/assets/static/js/modules/aircraft-manager.js
@@ -362,6 +362,10 @@ export class AircraftManager {
diff --git a/internal/merger/merger.go b/internal/merger/merger.go
index f561d95..fdb0c52 100644
--- a/internal/merger/merger.go
+++ b/internal/merger/merger.go
@@ -112,29 +112,31 @@ func (a *AircraftState) MarshalJSON() ([]byte, error) {
// Create a struct that mirrors AircraftState but with ICAO24 as string
return json.Marshal(&struct {
// From embedded modes.Aircraft
- ICAO24 string `json:"ICAO24"`
- Callsign string `json:"Callsign"`
- Latitude float64 `json:"Latitude"`
- Longitude float64 `json:"Longitude"`
- Altitude int `json:"Altitude"`
- BaroAltitude int `json:"BaroAltitude"`
- GeomAltitude int `json:"GeomAltitude"`
- VerticalRate int `json:"VerticalRate"`
- GroundSpeed int `json:"GroundSpeed"`
- Track int `json:"Track"`
- Heading int `json:"Heading"`
- Category string `json:"Category"`
- Squawk string `json:"Squawk"`
- Emergency string `json:"Emergency"`
- OnGround bool `json:"OnGround"`
- Alert bool `json:"Alert"`
- SPI bool `json:"SPI"`
- NACp uint8 `json:"NACp"`
- NACv uint8 `json:"NACv"`
- SIL uint8 `json:"SIL"`
- SelectedAltitude int `json:"SelectedAltitude"`
- SelectedHeading float64 `json:"SelectedHeading"`
- BaroSetting float64 `json:"BaroSetting"`
+ ICAO24 string `json:"ICAO24"`
+ Callsign string `json:"Callsign"`
+ Latitude float64 `json:"Latitude"`
+ Longitude float64 `json:"Longitude"`
+ Altitude int `json:"Altitude"`
+ BaroAltitude int `json:"BaroAltitude"`
+ GeomAltitude int `json:"GeomAltitude"`
+ VerticalRate int `json:"VerticalRate"`
+ GroundSpeed int `json:"GroundSpeed"`
+ Track int `json:"Track"`
+ Heading int `json:"Heading"`
+ Category string `json:"Category"`
+ Squawk string `json:"Squawk"`
+ Emergency string `json:"Emergency"`
+ OnGround bool `json:"OnGround"`
+ Alert bool `json:"Alert"`
+ SPI bool `json:"SPI"`
+ NACp uint8 `json:"NACp"`
+ NACv uint8 `json:"NACv"`
+ SIL uint8 `json:"SIL"`
+ TransponderCapability string `json:"TransponderCapability"`
+ TransponderLevel uint8 `json:"TransponderLevel"`
+ SelectedAltitude int `json:"SelectedAltitude"`
+ SelectedHeading float64 `json:"SelectedHeading"`
+ BaroSetting float64 `json:"BaroSetting"`
// From AircraftState
Sources map[string]*SourceData `json:"sources"`
@@ -156,29 +158,31 @@ func (a *AircraftState) MarshalJSON() ([]byte, error) {
Flag string `json:"flag"`
}{
// Copy all fields from Aircraft
- ICAO24: fmt.Sprintf("%06X", a.Aircraft.ICAO24),
- Callsign: a.Aircraft.Callsign,
- Latitude: a.Aircraft.Latitude,
- Longitude: a.Aircraft.Longitude,
- Altitude: a.Aircraft.Altitude,
- BaroAltitude: a.Aircraft.BaroAltitude,
- GeomAltitude: a.Aircraft.GeomAltitude,
- VerticalRate: a.Aircraft.VerticalRate,
- GroundSpeed: a.Aircraft.GroundSpeed,
- Track: a.Aircraft.Track,
- Heading: a.Aircraft.Heading,
- Category: a.Aircraft.Category,
- Squawk: a.Aircraft.Squawk,
- Emergency: a.Aircraft.Emergency,
- OnGround: a.Aircraft.OnGround,
- Alert: a.Aircraft.Alert,
- SPI: a.Aircraft.SPI,
- NACp: a.Aircraft.NACp,
- NACv: a.Aircraft.NACv,
- SIL: a.Aircraft.SIL,
- SelectedAltitude: a.Aircraft.SelectedAltitude,
- SelectedHeading: a.Aircraft.SelectedHeading,
- BaroSetting: a.Aircraft.BaroSetting,
+ ICAO24: fmt.Sprintf("%06X", a.Aircraft.ICAO24),
+ Callsign: a.Aircraft.Callsign,
+ Latitude: a.Aircraft.Latitude,
+ Longitude: a.Aircraft.Longitude,
+ Altitude: a.Aircraft.Altitude,
+ BaroAltitude: a.Aircraft.BaroAltitude,
+ GeomAltitude: a.Aircraft.GeomAltitude,
+ VerticalRate: a.Aircraft.VerticalRate,
+ GroundSpeed: a.Aircraft.GroundSpeed,
+ Track: a.Aircraft.Track,
+ Heading: a.Aircraft.Heading,
+ Category: a.Aircraft.Category,
+ Squawk: a.Aircraft.Squawk,
+ Emergency: a.Aircraft.Emergency,
+ OnGround: a.Aircraft.OnGround,
+ Alert: a.Aircraft.Alert,
+ SPI: a.Aircraft.SPI,
+ NACp: a.Aircraft.NACp,
+ NACv: a.Aircraft.NACv,
+ SIL: a.Aircraft.SIL,
+ TransponderCapability: a.Aircraft.TransponderCapability,
+ TransponderLevel: a.Aircraft.TransponderLevel,
+ SelectedAltitude: a.Aircraft.SelectedAltitude,
+ SelectedHeading: a.Aircraft.SelectedHeading,
+ BaroSetting: a.Aircraft.BaroSetting,
// Copy all fields from AircraftState
Sources: a.Sources,
diff --git a/internal/modes/decoder.go b/internal/modes/decoder.go
index a8d5afb..f2ab232 100644
--- a/internal/modes/decoder.go
+++ b/internal/modes/decoder.go
@@ -138,6 +138,10 @@ type Aircraft struct {
NACv uint8 // Navigation Accuracy Category - Velocity (0-4)
SIL uint8 // Surveillance Integrity Level (0-3)
+ // Transponder Information
+ TransponderCapability string // Transponder capability level (from DF11 messages)
+ TransponderLevel uint8 // Transponder level (0-7 from capability field)
+
// Autopilot/Flight Management
SelectedAltitude int // MCP/FCU selected altitude in feet
SelectedHeading float64 // MCP/FCU selected heading in degrees
@@ -231,12 +235,29 @@ func (d *Decoder) Decode(data []byte) (*Aircraft, error) {
}
switch df {
+ case DF0:
+ // Short Air-Air Surveillance (ACAS)
+ aircraft.Altitude = d.decodeAltitude(data)
+ // Additional ACAS-specific data could be extracted here
case DF4, DF20:
aircraft.Altitude = d.decodeAltitude(data)
case DF5, DF21:
aircraft.Squawk = d.decodeSquawk(data)
+ case DF11:
+ // All-Call Reply - extract capability and interrogator identifier
+ d.decodeAllCallReply(data, aircraft)
+ case DF16:
+ // Long Air-Air Surveillance (ACAS with altitude)
+ aircraft.Altitude = d.decodeAltitude(data)
+ // Additional ACAS-specific data could be extracted here
case DF17, DF18:
return d.decodeExtendedSquitter(data, aircraft)
+ case DF19:
+ // Military Extended Squitter - similar to DF17/18 but with military codes
+ return d.decodeMilitaryExtendedSquitter(data, aircraft)
+ case DF24:
+ // Comm-D Enhanced Length Message - variable length data
+ d.decodeCommD(data, aircraft)
}
return aircraft, nil
@@ -940,3 +961,106 @@ func (d *Decoder) decodeGroundSpeed(movement uint8) float64 {
}
return 0
}
+
+// decodeAllCallReply extracts capability and interrogator identifier from DF11 messages.
+//
+// DF11 All-Call Reply messages contain:
+// - Capability (CA) field (3 bits): transponder capabilities and modes
+// - Interrogator Identifier (II) field (4 bits): which radar interrogated
+// - ICAO24 address (24 bits): aircraft identifier
+//
+// The capability field indicates transponder features and operational modes:
+// - 0: Level 1 transponder
+// - 1: Level 2 transponder
+// - 2: Level 2+ transponder with additional capabilities
+// - 3: Level 2+ transponder with enhanced surveillance
+// - 4: Level 2+ transponder with enhanced surveillance and extended squitter
+// - 5: Level 2+ transponder with enhanced surveillance, extended squitter, and enhanced surveillance capability
+// - 6: Level 2+ transponder with enhanced surveillance, extended squitter, and enhanced surveillance capability
+// - 7: Level 2+ transponder, downlink request value is 0, or the flight status is alert, SPI, or emergency
+//
+// Parameters:
+// - data: 7-byte DF11 message
+// - aircraft: Aircraft struct to populate
+func (d *Decoder) decodeAllCallReply(data []byte, aircraft *Aircraft) {
+ if len(data) < 7 {
+ return
+ }
+
+ // Extract Capability (CA) - bits 6-8 of first byte
+ capability := (data[0] >> 0) & 0x07
+
+ // Extract Interrogator Identifier (II) - would be in control field if present
+ // For DF11, this information is typically implied by the interrogating radar
+
+ // Store transponder capability information in dedicated fields
+ aircraft.TransponderLevel = capability
+ switch capability {
+ case 0:
+ aircraft.TransponderCapability = "Level 1 Transponder"
+ case 1:
+ aircraft.TransponderCapability = "Level 2 Transponder"
+ case 2, 3:
+ aircraft.TransponderCapability = "Level 2+ Transponder"
+ case 4, 5, 6:
+ aircraft.TransponderCapability = "Enhanced Transponder"
+ case 7:
+ aircraft.TransponderCapability = "Alert/Emergency Status"
+ }
+}
+
+// decodeMilitaryExtendedSquitter processes DF19 military extended squitter messages.
+//
+// DF19 messages have the same structure as DF17/18 ADS-B extended squitter but
+// may contain military-specific type codes or enhanced data formats.
+// This implementation treats them similarly to civilian extended squitter
+// but could be extended for military-specific capabilities.
+//
+// Parameters:
+// - data: 14-byte DF19 message
+// - aircraft: Aircraft struct to populate
+//
+// Returns updated Aircraft struct or error for malformed messages.
+func (d *Decoder) decodeMilitaryExtendedSquitter(data []byte, aircraft *Aircraft) (*Aircraft, error) {
+ if len(data) != 14 {
+ return nil, fmt.Errorf("invalid military extended squitter length: %d bytes", len(data))
+ }
+
+ // For now, treat military extended squitter similar to civilian
+ // Could be enhanced to handle military-specific type codes
+ return d.decodeExtendedSquitter(data, aircraft)
+}
+
+// decodeCommD extracts data from DF24 Comm-D Enhanced Length Messages.
+//
+// DF24 messages are variable-length data link communications that can contain:
+// - Weather information and updates
+// - Flight plan modifications
+// - Controller-pilot data link messages
+// - Air traffic management information
+// - Future air navigation system data
+//
+// Due to the complexity and variety of DF24 message content, this implementation
+// provides basic structure extraction. Full decoding would require extensive
+// knowledge of specific data link protocols and message formats.
+//
+// Parameters:
+// - data: Variable-length DF24 message (minimum 7 bytes)
+// - aircraft: Aircraft struct to populate
+func (d *Decoder) decodeCommD(data []byte, aircraft *Aircraft) {
+ if len(data) < 7 {
+ return
+ }
+
+ // DF24 messages contain variable data that would require protocol-specific decoding
+ // For now, we note that this is a data communication message but don't overwrite aircraft category
+ // Could set a separate field for message type if needed in the future
+
+ // The actual message content would require:
+ // - Protocol identifier extraction
+ // - Message type determination
+ // - Format-specific field extraction
+ // - Possible message reassembly for multi-part messages
+ //
+ // This could be extended based on specific requirements and available documentation
+}