diff --git a/assets/static/css/style.css b/assets/static/css/style.css
index 5389c2d..750603c 100644
--- a/assets/static/css/style.css
+++ b/assets/static/css/style.css
@@ -679,62 +679,4 @@ body {
#aircraft-table td {
padding: 0.5rem 0.25rem;
}
-}
-
-/* Squawk Code Styling */
-.squawk-emergency {
- background: #dc3545;
- color: white;
- padding: 2px 6px;
- border-radius: 4px;
- font-weight: bold;
- cursor: help;
- border: 1px solid #b52532;
-}
-
-.squawk-special {
- background: #fd7e14;
- color: white;
- padding: 2px 6px;
- border-radius: 4px;
- font-weight: 500;
- cursor: help;
- border: 1px solid #e06911;
-}
-
-.squawk-military {
- background: #6c757d;
- color: white;
- padding: 2px 6px;
- border-radius: 4px;
- font-weight: 500;
- cursor: help;
- border: 1px solid #565e64;
-}
-
-.squawk-standard {
- background: #28a745;
- color: white;
- padding: 2px 6px;
- border-radius: 4px;
- font-weight: normal;
- cursor: help;
- border: 1px solid #1e7e34;
-}
-
-/* Hover effects for squawk codes */
-.squawk-emergency:hover {
- background: #c82333;
-}
-
-.squawk-special:hover {
- background: #e8590c;
-}
-
-.squawk-military:hover {
- background: #5a6268;
-}
-
-.squawk-standard:hover {
- background: #218838;
}
\ No newline at end of file
diff --git a/assets/static/js/modules/ui-manager.js b/assets/static/js/modules/ui-manager.js
index b891096..88c692c 100644
--- a/assets/static/js/modules/ui-manager.js
+++ b/assets/static/js/modules/ui-manager.js
@@ -122,7 +122,7 @@ export class UIManager {
row.innerHTML = `
${icao} |
${aircraft.Callsign || '-'} |
- ${this.formatSquawk(aircraft)} |
+ ${aircraft.Squawk || '-'} |
${altitude ? `${altitude} ft` : '-'} |
${aircraft.GroundSpeed || '-'} kt |
${distance ? distance.toFixed(1) : '-'} km |
@@ -180,33 +180,6 @@ export class UIManager {
return 'signal-poor';
}
- formatSquawk(aircraft) {
- if (!aircraft.Squawk) return '-';
-
- // If we have a description, format it nicely
- if (aircraft.SquawkDescription) {
- // Check if it's an emergency code (contains warning emoji)
- if (aircraft.SquawkDescription.includes('⚠️')) {
- return `${aircraft.Squawk}`;
- }
- // Check if it's a special code (contains special emoji)
- else if (aircraft.SquawkDescription.includes('🔸')) {
- return `${aircraft.Squawk}`;
- }
- // Check if it's a military code (contains military emoji)
- else if (aircraft.SquawkDescription.includes('🔰')) {
- return `${aircraft.Squawk}`;
- }
- // Standard codes
- else {
- return `${aircraft.Squawk}`;
- }
- }
-
- // No description available, show just the code
- return aircraft.Squawk;
- }
-
updateSourceFilter() {
const select = document.getElementById('source-filter');
if (!select) return;
diff --git a/internal/merger/merger.go b/internal/merger/merger.go
index 5fe3a80..7274219 100644
--- a/internal/merger/merger.go
+++ b/internal/merger/merger.go
@@ -29,7 +29,6 @@ import (
"skyview/internal/icao"
"skyview/internal/modes"
- "skyview/internal/squawk"
)
const (
@@ -127,7 +126,6 @@ func (a *AircraftState) MarshalJSON() ([]byte, error) {
Heading int `json:"Heading"`
Category string `json:"Category"`
Squawk string `json:"Squawk"`
- SquawkDescription string `json:"SquawkDescription"`
Emergency string `json:"Emergency"`
OnGround bool `json:"OnGround"`
Alert bool `json:"Alert"`
@@ -175,7 +173,6 @@ func (a *AircraftState) MarshalJSON() ([]byte, error) {
Heading: a.Aircraft.Heading,
Category: a.Aircraft.Category,
Squawk: a.Aircraft.Squawk,
- SquawkDescription: a.Aircraft.SquawkDescription,
Emergency: a.Aircraft.Emergency,
OnGround: a.Aircraft.OnGround,
Alert: a.Aircraft.Alert,
@@ -271,7 +268,6 @@ type Merger struct {
aircraft map[uint32]*AircraftState // ICAO24 -> merged aircraft state
sources map[string]*Source // Source ID -> source information
icaoDB *icao.Database // ICAO country lookup database
- squawkDB *squawk.Database // Transponder code lookup database
mu sync.RWMutex // Protects all maps and slices
historyLimit int // Maximum history points to retain
staleTimeout time.Duration // Time before aircraft considered stale (15 seconds)
@@ -300,13 +296,10 @@ func NewMerger() (*Merger, error) {
return nil, fmt.Errorf("failed to initialize ICAO database: %w", err)
}
- squawkDB := squawk.NewDatabase()
-
return &Merger{
aircraft: make(map[uint32]*AircraftState),
sources: make(map[string]*Source),
icaoDB: icaoDB,
- squawkDB: squawkDB,
historyLimit: 500,
staleTimeout: 15 * time.Second, // Aircraft timeout - reasonable for ADS-B tracking
updateMetrics: make(map[uint32]*updateMetric),
@@ -542,8 +535,6 @@ func (m *Merger) mergeAircraftData(state *AircraftState, new *modes.Aircraft, so
}
if new.Squawk != "" {
state.Squawk = new.Squawk
- // Look up squawk description
- state.SquawkDescription = m.squawkDB.FormatSquawkWithDescription(new.Squawk)
}
if new.Category != "" {
state.Category = new.Category
diff --git a/internal/modes/decoder.go b/internal/modes/decoder.go
index 959fa19..e120abf 100644
--- a/internal/modes/decoder.go
+++ b/internal/modes/decoder.go
@@ -130,9 +130,8 @@ type Aircraft struct {
Heading int // Aircraft heading in degrees (magnetic, integer)
// Aircraft Information
- Category string // Aircraft category (size, type, performance)
- Squawk string // 4-digit transponder squawk code (octal)
- SquawkDescription string // Human-readable description of transponder code
+ Category string // Aircraft category (size, type, performance)
+ Squawk string // 4-digit transponder squawk code (octal)
// Status and Alerts
Emergency string // Emergency/priority status description
diff --git a/internal/squawk/squawk.go b/internal/squawk/squawk.go
deleted file mode 100644
index 2647bd1..0000000
--- a/internal/squawk/squawk.go
+++ /dev/null
@@ -1,393 +0,0 @@
-// Package squawk provides transponder code lookup and interpretation functionality.
-//
-// This package implements a comprehensive database of transponder (squawk) codes
-// used in aviation, providing textual descriptions and categorizations for
-// common codes including emergency, operational, and special-purpose codes.
-//
-// The lookup system supports:
-// - Emergency codes (7500, 7600, 7700)
-// - Standard VFR/IFR operational codes
-// - Military and special operations codes
-// - Regional variations and custom codes
-//
-// Code categories help with UI presentation and priority handling, with
-// emergency codes receiving special visual treatment in the interface.
-package squawk
-
-import (
- "fmt"
- "strconv"
-)
-
-// CodeType represents the category of a transponder code for UI presentation
-type CodeType int
-
-const (
- // Unknown represents codes not in the lookup database
- Unknown CodeType = iota
- // Emergency represents emergency situation codes (7500, 7600, 7700)
- Emergency
- // Standard represents common operational codes (1200, 7000, etc.)
- Standard
- // Military represents military operation codes
- Military
- // Special represents special purpose codes (SAR, firefighting, etc.)
- Special
-)
-
-// String returns the string representation of a CodeType
-func (ct CodeType) String() string {
- switch ct {
- case Emergency:
- return "Emergency"
- case Standard:
- return "Standard"
- case Military:
- return "Military"
- case Special:
- return "Special"
- default:
- return "Unknown"
- }
-}
-
-// CodeInfo contains detailed information about a transponder code
-type CodeInfo struct {
- Code string `json:"code"` // The transponder code (e.g., "7700")
- Description string `json:"description"` // Human-readable description
- Type CodeType `json:"type"` // Category of the code
- Region string `json:"region"` // Geographic region (e.g., "Global", "ICAO", "US", "EU")
- Priority int `json:"priority"` // Display priority (higher = more important)
- Notes string `json:"notes"` // Additional context or usage notes
-}
-
-// Database contains the transponder code lookup database
-type Database struct {
- codes map[string]*CodeInfo // Map of code -> CodeInfo
-}
-
-// NewDatabase creates and initializes a new transponder code database
-// with comprehensive coverage of common aviation transponder codes
-func NewDatabase() *Database {
- db := &Database{
- codes: make(map[string]*CodeInfo),
- }
-
- // Initialize with standard transponder codes
- db.loadStandardCodes()
-
- return db
-}
-
-// loadStandardCodes populates the database with standard transponder codes
-func (db *Database) loadStandardCodes() {
- codes := []*CodeInfo{
- // Emergency Codes (Highest Priority)
- {
- Code: "7500",
- Description: "Hijacking/Unlawful Interference",
- Type: Emergency,
- Region: "Global",
- Priority: 100,
- Notes: "Aircraft under unlawful interference or hijacking",
- },
- {
- Code: "7600",
- Description: "Radio Failure",
- Type: Emergency,
- Region: "Global",
- Priority: 95,
- Notes: "Loss of radio communication capability",
- },
- {
- Code: "7700",
- Description: "General Emergency",
- Type: Emergency,
- Region: "Global",
- Priority: 90,
- Notes: "General emergency situation requiring immediate attention",
- },
-
- // Standard VFR/IFR Codes
- {
- Code: "1200",
- Description: "VFR - Visual Flight Rules",
- Type: Standard,
- Region: "US/Canada",
- Priority: 10,
- Notes: "Standard VFR code for uncontrolled airspace in North America",
- },
- {
- Code: "7000",
- Description: "VFR - Visual Flight Rules",
- Type: Standard,
- Region: "ICAO/Europe",
- Priority: 10,
- Notes: "Standard VFR code for most ICAO regions",
- },
- {
- Code: "2000",
- Description: "Uncontrolled Airspace",
- Type: Standard,
- Region: "Various",
- Priority: 8,
- Notes: "Used in some regions for uncontrolled airspace operations",
- },
- {
- Code: "0000",
- Description: "No Transponder/Military",
- Type: Military,
- Region: "Global",
- Priority: 5,
- Notes: "No transponder assigned or military operations",
- },
- {
- Code: "1000",
- Description: "Mode A/C Not Assigned",
- Type: Standard,
- Region: "Global",
- Priority: 5,
- Notes: "Transponder operating but no specific code assigned",
- },
-
- // Special Purpose Codes
- {
- Code: "1255",
- Description: "Fire Fighting Aircraft",
- Type: Special,
- Region: "US",
- Priority: 25,
- Notes: "Aircraft engaged in firefighting operations",
- },
- {
- Code: "1277",
- Description: "Search and Rescue",
- Type: Special,
- Region: "US",
- Priority: 30,
- Notes: "Search and rescue operations",
- },
- {
- Code: "7777",
- Description: "Military Interceptor",
- Type: Military,
- Region: "US",
- Priority: 35,
- Notes: "Military interceptor aircraft",
- },
-
- // Military Ranges
- {
- Code: "4000",
- Description: "Military Low Altitude",
- Type: Military,
- Region: "US",
- Priority: 15,
- Notes: "Military operations at low altitude (4000-4777 range)",
- },
- {
- Code: "0100",
- Description: "Military Operations",
- Type: Military,
- Region: "Various",
- Priority: 12,
- Notes: "Military interceptor operations (0100-0777 range)",
- },
-
- // Additional Common Codes
- {
- Code: "1201",
- Description: "VFR - High Altitude",
- Type: Standard,
- Region: "US",
- Priority: 8,
- Notes: "VFR operations above 12,500 feet MSL",
- },
- {
- Code: "4401",
- Description: "Glider Operations",
- Type: Special,
- Region: "US",
- Priority: 8,
- Notes: "Glider and soaring aircraft operations",
- },
- {
- Code: "1202",
- Description: "VFR - Above 12,500ft",
- Type: Standard,
- Region: "US",
- Priority: 8,
- Notes: "VFR flight above 12,500 feet requiring transponder",
- },
-
- // European Specific
- {
- Code: "7001",
- Description: "Conspicuity Code A",
- Type: Standard,
- Region: "Europe",
- Priority: 10,
- Notes: "Enhanced visibility in European airspace",
- },
- {
- Code: "7004",
- Description: "Aerobatic Flight",
- Type: Special,
- Region: "Europe",
- Priority: 12,
- Notes: "Aircraft engaged in aerobatic maneuvers",
- },
- {
- Code: "7010",
- Description: "GAT in OAT Area",
- Type: Special,
- Region: "Europe",
- Priority: 8,
- Notes: "General Air Traffic operating in Other Air Traffic area",
- },
- }
-
- // Add all codes to the database
- for _, code := range codes {
- db.codes[code.Code] = code
- }
-}
-
-// Lookup returns information about a given transponder code
-//
-// The method accepts both 4-digit strings and integers, automatically
-// formatting them as needed. Returns nil if the code is not found in the database.
-//
-// Parameters:
-// - code: Transponder code as string (e.g., "7700") or can be called with fmt.Sprintf
-//
-// Returns:
-// - *CodeInfo: Detailed information about the code, or nil if not found
-func (db *Database) Lookup(code string) *CodeInfo {
- if info, exists := db.codes[code]; exists {
- return info
- }
- return nil
-}
-
-// LookupInt is a convenience method for looking up codes as integers
-//
-// Parameters:
-// - code: Transponder code as integer (e.g., 7700)
-//
-// Returns:
-// - *CodeInfo: Detailed information about the code, or nil if not found
-func (db *Database) LookupInt(code int) *CodeInfo {
- codeStr := fmt.Sprintf("%04d", code)
- return db.Lookup(codeStr)
-}
-
-// LookupHex is a convenience method for looking up codes from hex strings
-//
-// Transponder codes are sometimes transmitted in hex format. This method
-// converts hex to decimal before lookup.
-//
-// Parameters:
-// - hexCode: Transponder code as hex string (e.g., "1E14" for 7700)
-//
-// Returns:
-// - *CodeInfo: Detailed information about the code, or nil if not found or invalid hex
-func (db *Database) LookupHex(hexCode string) *CodeInfo {
- // Convert hex to decimal
- if decimal, err := strconv.ParseInt(hexCode, 16, 16); err == nil {
- // Convert decimal to 4-digit octal representation (squawk codes are octal)
- octal := fmt.Sprintf("%04o", decimal)
- return db.Lookup(octal)
- }
- return nil
-}
-
-// GetEmergencyCodes returns all emergency codes in the database
-//
-// Returns:
-// - []*CodeInfo: Slice of all emergency codes, sorted by priority (highest first)
-func (db *Database) GetEmergencyCodes() []*CodeInfo {
- var emergencyCodes []*CodeInfo
-
- for _, info := range db.codes {
- if info.Type == Emergency {
- emergencyCodes = append(emergencyCodes, info)
- }
- }
-
- // Sort by priority (highest first)
- for i := 0; i < len(emergencyCodes); i++ {
- for j := i + 1; j < len(emergencyCodes); j++ {
- if emergencyCodes[i].Priority < emergencyCodes[j].Priority {
- emergencyCodes[i], emergencyCodes[j] = emergencyCodes[j], emergencyCodes[i]
- }
- }
- }
-
- return emergencyCodes
-}
-
-// IsEmergencyCode returns true if the given code represents an emergency situation
-//
-// Parameters:
-// - code: Transponder code as string (e.g., "7700")
-//
-// Returns:
-// - bool: True if the code is an emergency code
-func (db *Database) IsEmergencyCode(code string) bool {
- if info := db.Lookup(code); info != nil {
- return info.Type == Emergency
- }
- return false
-}
-
-// GetAllCodes returns all codes in the database
-//
-// Returns:
-// - []*CodeInfo: Slice of all codes in the database
-func (db *Database) GetAllCodes() []*CodeInfo {
- codes := make([]*CodeInfo, 0, len(db.codes))
- for _, info := range db.codes {
- codes = append(codes, info)
- }
- return codes
-}
-
-// AddCustomCode allows adding custom transponder codes to the database
-//
-// This is useful for regional codes or organization-specific codes not
-// included in the standard database.
-//
-// Parameters:
-// - info: CodeInfo struct with the custom code information
-func (db *Database) AddCustomCode(info *CodeInfo) {
- db.codes[info.Code] = info
-}
-
-// FormatSquawkWithDescription returns a formatted string combining code and description
-//
-// Formats transponder codes for display with appropriate emergency indicators.
-// Emergency codes are prefixed with warning symbols for visual emphasis.
-//
-// Parameters:
-// - code: Transponder code as string (e.g., "7700")
-//
-// Returns:
-// - string: Formatted string like "7700 (⚠️ EMERGENCY - General)" or "1200 (VFR - Visual Flight Rules)"
-func (db *Database) FormatSquawkWithDescription(code string) string {
- info := db.Lookup(code)
- if info == nil {
- return code // Return just the code if no description available
- }
-
- switch info.Type {
- case Emergency:
- return fmt.Sprintf("%s (⚠️ EMERGENCY - %s)", code, info.Description)
- case Special:
- return fmt.Sprintf("%s (🔸 %s)", code, info.Description)
- case Military:
- return fmt.Sprintf("%s (🔰 %s)", code, info.Description)
- default:
- return fmt.Sprintf("%s (%s)", code, info.Description)
- }
-}
\ No newline at end of file
diff --git a/internal/squawk/squawk_test.go b/internal/squawk/squawk_test.go
deleted file mode 100644
index 6a008db..0000000
--- a/internal/squawk/squawk_test.go
+++ /dev/null
@@ -1,209 +0,0 @@
-package squawk
-
-import (
- "testing"
-)
-
-func TestNewDatabase(t *testing.T) {
- db := NewDatabase()
- if db == nil {
- t.Fatal("NewDatabase() returned nil")
- }
-
- if len(db.codes) == 0 {
- t.Error("Database should contain pre-loaded codes")
- }
-}
-
-func TestEmergencyCodes(t *testing.T) {
- db := NewDatabase()
-
- emergencyCodes := []string{"7500", "7600", "7700"}
-
- for _, code := range emergencyCodes {
- info := db.Lookup(code)
- if info == nil {
- t.Errorf("Emergency code %s not found", code)
- continue
- }
-
- if info.Type != Emergency {
- t.Errorf("Code %s should be Emergency type, got %s", code, info.Type)
- }
-
- if !db.IsEmergencyCode(code) {
- t.Errorf("IsEmergencyCode(%s) should return true", code)
- }
- }
-}
-
-func TestStandardCodes(t *testing.T) {
- db := NewDatabase()
-
- testCases := []struct {
- code string
- description string
- }{
- {"1200", "VFR - Visual Flight Rules"},
- {"7000", "VFR - Visual Flight Rules"},
- {"1000", "Mode A/C Not Assigned"},
- }
-
- for _, tc := range testCases {
- info := db.Lookup(tc.code)
- if info == nil {
- t.Errorf("Standard code %s not found", tc.code)
- continue
- }
-
- if info.Description != tc.description {
- t.Errorf("Code %s: expected description %q, got %q",
- tc.code, tc.description, info.Description)
- }
- }
-}
-
-func TestLookupInt(t *testing.T) {
- db := NewDatabase()
-
- // Test integer lookup
- info := db.LookupInt(7700)
- if info == nil {
- t.Fatal("LookupInt(7700) returned nil")
- }
-
- if info.Code != "7700" {
- t.Errorf("Expected code '7700', got '%s'", info.Code)
- }
-
- if info.Type != Emergency {
- t.Errorf("Code 7700 should be Emergency type, got %s", info.Type)
- }
-}
-
-func TestLookupHex(t *testing.T) {
- db := NewDatabase()
-
- // 7700 in octal is 3840 in decimal, which is F00 in hex
- // However, squawk codes are transmitted differently in different formats
- // For now, test with a simple hex conversion
-
- // Test invalid hex
- info := db.LookupHex("INVALID")
- if info != nil {
- t.Error("LookupHex with invalid hex should return nil")
- }
-}
-
-func TestFormatSquawkWithDescription(t *testing.T) {
- db := NewDatabase()
-
- testCases := []struct {
- code string
- expected string
- }{
- {"7700", "7700 (⚠️ EMERGENCY - General Emergency)"},
- {"1200", "1200 (VFR - Visual Flight Rules)"},
- {"1277", "1277 (🔸 Search and Rescue)"},
- {"0000", "0000 (🔰 No Transponder/Military)"},
- {"9999", "9999"}, // Unknown code should return just the code
- }
-
- for _, tc := range testCases {
- result := db.FormatSquawkWithDescription(tc.code)
- if result != tc.expected {
- t.Errorf("FormatSquawkWithDescription(%s): expected %q, got %q",
- tc.code, tc.expected, result)
- }
- }
-}
-
-func TestGetEmergencyCodes(t *testing.T) {
- db := NewDatabase()
-
- emergencyCodes := db.GetEmergencyCodes()
- if len(emergencyCodes) != 3 {
- t.Errorf("Expected 3 emergency codes, got %d", len(emergencyCodes))
- }
-
- // Check that they're sorted by priority (highest first)
- for i := 1; i < len(emergencyCodes); i++ {
- if emergencyCodes[i-1].Priority < emergencyCodes[i].Priority {
- t.Error("Emergency codes should be sorted by priority (highest first)")
- }
- }
-}
-
-func TestAddCustomCode(t *testing.T) {
- db := NewDatabase()
-
- customCode := &CodeInfo{
- Code: "1234",
- Description: "Test Custom Code",
- Type: Special,
- Region: "Test",
- Priority: 50,
- Notes: "This is a test custom code",
- }
-
- db.AddCustomCode(customCode)
-
- info := db.Lookup("1234")
- if info == nil {
- t.Fatal("Custom code not found after adding")
- }
-
- if info.Description != "Test Custom Code" {
- t.Errorf("Custom code description mismatch: expected %q, got %q",
- "Test Custom Code", info.Description)
- }
-}
-
-func TestCodeTypeString(t *testing.T) {
- testCases := []struct {
- codeType CodeType
- expected string
- }{
- {Unknown, "Unknown"},
- {Emergency, "Emergency"},
- {Standard, "Standard"},
- {Military, "Military"},
- {Special, "Special"},
- }
-
- for _, tc := range testCases {
- result := tc.codeType.String()
- if result != tc.expected {
- t.Errorf("CodeType.String(): expected %q, got %q", tc.expected, result)
- }
- }
-}
-
-func TestGetAllCodes(t *testing.T) {
- db := NewDatabase()
-
- allCodes := db.GetAllCodes()
- if len(allCodes) == 0 {
- t.Error("GetAllCodes() should return non-empty slice")
- }
-
- // Verify we can find known codes in the result
- found7700 := false
- found1200 := false
-
- for _, code := range allCodes {
- if code.Code == "7700" {
- found7700 = true
- }
- if code.Code == "1200" {
- found1200 = true
- }
- }
-
- if !found7700 {
- t.Error("Emergency code 7700 not found in GetAllCodes() result")
- }
- if !found1200 {
- t.Error("Standard code 1200 not found in GetAllCodes() result")
- }
-}
\ No newline at end of file