mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
Initial commit
This commit is contained in:
@@ -48,6 +48,16 @@ $(document).ready(function() {
|
||||
// Cache for radio names to avoid repeated AJAX calls
|
||||
var radioNameCache = {};
|
||||
|
||||
// Global CAT state - stores last received data from radio
|
||||
// This allows other components (like DX Waterfall) to read radio state
|
||||
// without depending on form fields
|
||||
window.catState = {
|
||||
frequency: null, // Hz
|
||||
frequency_rx: null, // Hz (for split operation)
|
||||
mode: null, // String (USB, LSB, CW, etc.)
|
||||
lastUpdate: null // Timestamp of last update
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize WebSocket connection for real-time radio updates
|
||||
* Handles connection, reconnection logic, and error states
|
||||
@@ -490,6 +500,16 @@ $(document).ready(function() {
|
||||
return; // Exit early - do not update any fields with old data
|
||||
}
|
||||
|
||||
// Update global CAT state FIRST before any UI updates
|
||||
// This allows DX Waterfall and other components to read radio state
|
||||
// without depending on form fields
|
||||
if (window.catState) {
|
||||
window.catState.frequency = data.frequency || null;
|
||||
window.catState.frequency_rx = data.frequency_rx || null;
|
||||
window.catState.mode = data.mode ? catmode(data.mode) : null;
|
||||
window.catState.lastUpdate = new Date();
|
||||
}
|
||||
|
||||
// Cache frequently used DOM selectors
|
||||
var $frequency = $('#frequency');
|
||||
var $band = $('#band');
|
||||
@@ -514,6 +534,7 @@ $(document).ready(function() {
|
||||
|
||||
// Force update by clearing catValue (prevents cat2UI from blocking updates)
|
||||
$frequency.removeData('catValue');
|
||||
$mode.removeData('catValue'); // Also clear mode cache
|
||||
cat_updating_frequency = true; // Set flag before CAT update
|
||||
|
||||
// Check if DX Waterfall's CAT frequency handler is available
|
||||
@@ -523,22 +544,20 @@ $(document).ready(function() {
|
||||
cat2UI($frequency,data.frequency,false,true,function(d){
|
||||
$frequency.trigger('change'); // Trigger for other event handlers
|
||||
const newBand = frequencyToBand(d);
|
||||
// Don't auto-update band if user just manually changed it (prevents race condition)
|
||||
if ($band.val() != newBand && (typeof dxWaterfall === 'undefined' || !dxWaterfall.userChangedBand)) {
|
||||
// Auto-update band based on frequency
|
||||
if ($band.val() != newBand) {
|
||||
$band.val(newBand).trigger('change'); // Trigger band change
|
||||
}
|
||||
cat_updating_frequency = false; // Clear flag after updates
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Standard frequency update (no DX Waterfall debounce handling)
|
||||
cat2UI($frequency,data.frequency,false,true,function(d){
|
||||
$frequency.trigger('change');
|
||||
// Don't auto-update band if user just manually changed it (prevents race condition)
|
||||
if ($band.val() != frequencyToBand(d) && (typeof dxWaterfall === 'undefined' || !dxWaterfall.userChangedBand)) {
|
||||
// Auto-update band based on frequency
|
||||
if ($band.val() != frequencyToBand(d)) {
|
||||
$band.val(frequencyToBand(d)).trigger('change');
|
||||
}
|
||||
cat_updating_frequency = false; // Clear flag after updates
|
||||
});
|
||||
}
|
||||
|
||||
@@ -559,6 +578,9 @@ $(document).ready(function() {
|
||||
cat2UI($('#transmit_power'),data.power,false,false);
|
||||
cat2UI($('#selectPropagation'),data.prop_mode,false,false);
|
||||
|
||||
// Clear the CAT updating flag AFTER all updates
|
||||
cat_updating_frequency = false;
|
||||
|
||||
// Data is fresh (timeout check already passed at function start)
|
||||
// Set CAT state for waterfall if dxwaterfall_cat_state is available
|
||||
if (typeof dxwaterfall_cat_state !== 'undefined') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* @fileoverview DX WATERFALL for WaveLog
|
||||
* @version 0.9.1 // also change line 38
|
||||
* @version 0.9.2 // also change line 38
|
||||
* @author Wavelog Team
|
||||
*
|
||||
* @description
|
||||
@@ -36,10 +36,10 @@
|
||||
|
||||
var DX_WATERFALL_CONSTANTS = {
|
||||
// Version
|
||||
VERSION: '0.9.1', // DX Waterfall version (keep in sync with @version in file header)
|
||||
VERSION: '0.9.2', // DX Waterfall version (keep in sync with @version in file header)
|
||||
|
||||
// Debug and logging
|
||||
DEBUG_MODE: false, // Set to true for verbose logging, false for production
|
||||
DEBUG_MODE: true, // Set to true for verbose logging, false for production
|
||||
|
||||
// Timing and debouncing
|
||||
DEBOUNCE: {
|
||||
@@ -114,7 +114,6 @@ var DX_WATERFALL_CONSTANTS = {
|
||||
THRESHOLDS: {
|
||||
FREQUENCY_COMPARISON: 0.1, // Frequency comparison tolerance in kHz
|
||||
FT8_FREQUENCY_TOLERANCE: 5, // FT8 frequency detection tolerance in kHz
|
||||
BAND_CHANGE_THRESHOLD: 1000, // kHz outside band before recalculation
|
||||
MAJOR_TICK_TOLERANCE: 0.05, // Floating point precision for major tick detection
|
||||
SPOT_FREQUENCY_MATCH: 0.01, // Frequency match tolerance for spot navigation (kHz)
|
||||
CAT_FREQUENCY_HZ: 1, // CAT frequency confirmation tolerance (1 Hz for exact tuning)
|
||||
@@ -392,16 +391,9 @@ function handleCATFrequencyUpdate(radioFrequency, updateCallback) {
|
||||
|
||||
// Only invalidate cache and commit if frequency actually changed
|
||||
if (typeof dxWaterfall !== 'undefined' && (frequencyChanged || isInitialLoad)) {
|
||||
// Skip frequency commit if:
|
||||
// 1. User just manually changed the band (2-second cooldown)
|
||||
// 2. Waiting for frequency update after band change - BUT clear the flag now since CAT confirmed!
|
||||
// This prevents race condition where CAT sends old frequency before radio catches up
|
||||
if (dxWaterfall.userChangedBand) {
|
||||
// Also clear waitingForFrequencyUpdate if it's set - this CAT update is likely stale
|
||||
if (dxWaterfall.waitingForFrequencyUpdate) {
|
||||
dxWaterfall.waitingForFrequencyUpdate = false;
|
||||
}
|
||||
} else if (dxWaterfall.waitingForFrequencyUpdate) {
|
||||
// Clear waitingForFrequencyUpdate if band just changed
|
||||
// This CAT update confirms the new frequency after band change
|
||||
if (dxWaterfall.waitingForFrequencyUpdate) {
|
||||
// CAT has confirmed the new frequency - clear the waiting flag and commit it
|
||||
dxWaterfall.waitingForFrequencyUpdate = false;
|
||||
dxWaterfall.waitingForData = false;
|
||||
@@ -1417,11 +1409,6 @@ var DX_WATERFALL_UTILS = {
|
||||
DX_WATERFALL_UTILS.qsoForm.clearForm();
|
||||
}
|
||||
|
||||
// Check if frequency is far outside current band and update band if needed
|
||||
if (waterfallContext.isFrequencyFarOutsideBand(targetSpot.frequency)) {
|
||||
waterfallContext.updateBandFromFrequency(targetSpot.frequency);
|
||||
}
|
||||
|
||||
// CRITICAL: Set mode FIRST before calling setFrequency
|
||||
// setFrequency reads the mode from $('#mode').val(), so the mode must be set first
|
||||
var radioMode = this.determineRadioMode(targetSpot);
|
||||
@@ -1553,8 +1540,6 @@ var dxWaterfall = {
|
||||
// DATA MANAGEMENT PROPERTIES
|
||||
// ========================================
|
||||
dxSpots: [],
|
||||
lastBand: null,
|
||||
lastMode: null,
|
||||
initialFetchDone: false,
|
||||
totalSpotsCount: 0,
|
||||
|
||||
@@ -1620,12 +1605,13 @@ var dxWaterfall = {
|
||||
|
||||
// State flags
|
||||
programmaticModeChange: false,
|
||||
programmaticBandUpdate: false,
|
||||
userChangedBand: false,
|
||||
initializationComplete: false,
|
||||
lastPopulatedSpot: null,
|
||||
pendingSpotSelection: null,
|
||||
|
||||
// Band tracking - tracks which band we currently have spots for
|
||||
currentSpotBand: null, // The band we last fetched spots for
|
||||
|
||||
// Display configuration
|
||||
displayConfig: {
|
||||
isSplit: false,
|
||||
@@ -1861,9 +1847,7 @@ var dxWaterfall = {
|
||||
_loadSettings: function() {
|
||||
this.loadSettingsFromCookies();
|
||||
|
||||
// Initialize lastBand and lastMode to prevent false change detection
|
||||
this.lastBand = this.getCurrentBand();
|
||||
this.lastMode = this.getCurrentMode();
|
||||
// Initialize band cache for edge calculations
|
||||
this.cachedBandForEdges = this.getCurrentBand();
|
||||
},
|
||||
|
||||
@@ -1948,6 +1932,9 @@ var dxWaterfall = {
|
||||
// Commit the current frequency value (called on blur or Enter key)
|
||||
// This prevents the waterfall from shifting while the user is typing
|
||||
commitFrequency: function() {
|
||||
// This function is primarily for the fallback case when CAT is not available
|
||||
// When CAT is active, the waterfall reads from window.catState.frequency
|
||||
|
||||
// Safety check: return early if waterfall is not initialized (destroyed or not yet ready)
|
||||
if (!this.$freqCalculated || !this.$qrgUnit) {
|
||||
return;
|
||||
@@ -1957,30 +1944,15 @@ var dxWaterfall = {
|
||||
var currentUnit = this.$qrgUnit.text() || 'kHz';
|
||||
|
||||
// If this is a valid frequency, save it as the last valid committed frequency
|
||||
// (used as fallback when CAT not available)
|
||||
var freqValue = parseFloat(currentInput) || 0;
|
||||
if (freqValue > 0) {
|
||||
this.lastValidCommittedFreq = currentInput;
|
||||
this.lastValidCommittedUnit = currentUnit;
|
||||
|
||||
// CRITICAL: Update band from frequency BEFORE refresh() is called
|
||||
// This ensures programmaticBandUpdate flag is set before hasParametersChanged() runs
|
||||
// BUT only do this if the band actually needs to change (frequency is outside current band)
|
||||
var currentFreqKhz = DX_WATERFALL_UTILS.frequency.convertToKhz(freqValue, currentUnit);
|
||||
|
||||
// Store the committed frequency in kHz for comparison checks
|
||||
var currentFreqKhz = DX_WATERFALL_UTILS.frequency.convertToKhz(freqValue, currentUnit);
|
||||
this.committedFrequencyKHz = currentFreqKhz;
|
||||
if (currentFreqKhz > 0) {
|
||||
var expectedBand = this.getFrequencyBand(currentFreqKhz);
|
||||
var currentBand = this.getCurrentBand();
|
||||
|
||||
// Only update band if frequency's band differs from current band
|
||||
// This prevents overriding manual band changes when frequency is already in that band
|
||||
// ALSO: Don't auto-update band if user just manually changed it (userChangedBand cooldown active)
|
||||
// This prevents race condition where CAT sends old frequency before radio catches up to new band
|
||||
if (expectedBand && currentBand && expectedBand !== currentBand && !this.userChangedBand) {
|
||||
this.updateBandFromFrequency(currentFreqKhz);
|
||||
}
|
||||
}
|
||||
|
||||
// If we're still waiting for CAT frequency and user manually set a frequency, cancel the wait
|
||||
// Only cancel if initialization is complete (don't cancel during initial page load)
|
||||
@@ -1997,10 +1969,7 @@ var dxWaterfall = {
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate the cached frequency to force recalculation
|
||||
this.lastQrgUnit = null;
|
||||
|
||||
// Force an immediate refresh to update the display with the new frequency
|
||||
// Force a refresh to update the display (mainly for non-CAT usage)
|
||||
if (this.canvas && this.ctx) {
|
||||
this.refresh();
|
||||
}
|
||||
@@ -2011,112 +1980,26 @@ var dxWaterfall = {
|
||||
}
|
||||
},
|
||||
|
||||
// Check if band or mode has changed
|
||||
hasParametersChanged: function() {
|
||||
// Get current values from form elements FIRST to detect immediate changes
|
||||
var currentBand = this.getCurrentBand();
|
||||
var currentMode = this.getCurrentMode();
|
||||
|
||||
// Check if band changed (even during cooldown) and reset dataReceived flag immediately
|
||||
// This prevents old band data from being displayed while waiting for new band to fetch
|
||||
var bandChanged = (currentBand !== this.lastBand);
|
||||
if (bandChanged && this.lastBand !== null) {
|
||||
// Band changed - immediately mark as waiting for new data
|
||||
this.dataReceived = false;
|
||||
this.waitingForData = true;
|
||||
}
|
||||
|
||||
// Check for invalid states that should prevent spot fetching
|
||||
var middleFreq = this.getCachedMiddleFreq(); // Returns frequency in kHz
|
||||
var isFrequencyInvalid = middleFreq <= 0;
|
||||
var isBandInvalid = !currentBand || currentBand === '' || currentBand.toLowerCase() === 'select';
|
||||
|
||||
// Early return: If frequency or band is invalid, don't fetch spots
|
||||
if (isFrequencyInvalid || isBandInvalid) {
|
||||
this.waitingForData = true;
|
||||
this.dataReceived = false;
|
||||
this.relevantSpots = [];
|
||||
this.currentSpotIndex = 0;
|
||||
this.lastSpotInfoKey = null;
|
||||
if (this.spotInfoDiv) {
|
||||
this.spotInfoDiv.innerHTML = ' ';
|
||||
}
|
||||
// Update tracking but don't trigger fetch
|
||||
this.lastBand = currentBand;
|
||||
this.lastMode = currentMode;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for changes
|
||||
bandChanged = this.lastBand !== currentBand;
|
||||
var modeChanged = this.lastMode !== currentMode;
|
||||
|
||||
// Update zoom menu when mode changes (but don't trigger spot fetch)
|
||||
if (modeChanged) {
|
||||
this.updateZoomMenu();
|
||||
}
|
||||
|
||||
// Early return: Only band changes should trigger spot fetching
|
||||
// Mode changes should NOT trigger fetching (mode is just a display filter)
|
||||
if (!bandChanged) {
|
||||
this.lastBand = currentBand;
|
||||
this.lastMode = currentMode;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Band changed - invalidate caches
|
||||
this.bandLimitsCache = null;
|
||||
this.cachedBandForEdges = currentBand;
|
||||
this.cache.visibleSpots = null;
|
||||
this.cache.visibleSpotsParams = null;
|
||||
|
||||
// Early return: If this is initial load (lastBand is null), don't reset state
|
||||
if (this.lastBand === null) {
|
||||
this.lastBand = currentBand;
|
||||
this.lastMode = currentMode;
|
||||
return bandChanged;
|
||||
}
|
||||
|
||||
// Band changed after initial load - reset waiting state
|
||||
this.waitingForData = true;
|
||||
this.dataReceived = false;
|
||||
this.dxSpots = [];
|
||||
this.totalSpotsCount = 0;
|
||||
this.relevantSpots = [];
|
||||
this.currentSpotIndex = 0;
|
||||
this.lastSpotInfoKey = null;
|
||||
if (this.spotInfoDiv) {
|
||||
this.spotInfoDiv.innerHTML = ' ';
|
||||
}
|
||||
this.operationStartTime = Date.now();
|
||||
this.updateZoomMenu();
|
||||
|
||||
// Handle programmatic vs manual band changes
|
||||
if (this.programmaticBandUpdate) {
|
||||
// Programmatic (CAT) change - reset flag and cancel any manual cooldown
|
||||
this.programmaticBandUpdate = false;
|
||||
if (this.userChangedBand) {
|
||||
this.userChangedBand = false;
|
||||
}
|
||||
} else if (!this.userChangedBand) {
|
||||
// Manual change with no cooldown active - set cooldown
|
||||
this.userChangedBand = true;
|
||||
var self = this;
|
||||
setTimeout(function() {
|
||||
self.userChangedBand = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
this.lastBand = currentBand;
|
||||
this.lastMode = currentMode;
|
||||
|
||||
return bandChanged;
|
||||
},
|
||||
|
||||
// Get cached middle frequency to avoid repeated DOM access and parsing
|
||||
// Always returns frequency in kHz for internal calculations
|
||||
getCachedMiddleFreq: function() {
|
||||
// Use committed frequency values (only updated on blur/Enter) to prevent shifting while typing
|
||||
// PRIORITY 1: Use CAT state if available (radio controls waterfall)
|
||||
// The waterfall should display what the radio is tuned to, not what's in the form
|
||||
if (window.catState && window.catState.frequency && window.catState.frequency > 0) {
|
||||
var freqHz = window.catState.frequency;
|
||||
var freqKhz = freqHz / 1000;
|
||||
|
||||
// Cache the CAT frequency
|
||||
this.cache.middleFreq = freqKhz;
|
||||
|
||||
// Update split operation state and get display configuration
|
||||
this.updateSplitOperationState();
|
||||
|
||||
return this.displayConfig.centerFrequency;
|
||||
}
|
||||
|
||||
// FALLBACK: Use committed frequency values (only updated on blur/Enter) to prevent shifting while typing
|
||||
// This is used when CAT is not available (no radio connected)
|
||||
// Strategy:
|
||||
// 1. If we have a valid committed frequency from this session, always use last VALID commit
|
||||
// 2. Otherwise use real-time values (initial load before any commits)
|
||||
@@ -2153,9 +2036,13 @@ var dxWaterfall = {
|
||||
|
||||
// Update split operation state and configure display parameters
|
||||
updateSplitOperationState: function() {
|
||||
// Check if frequency_rx field exists and has a value
|
||||
// Prefer CAT state for frequency_rx (radio controls split operation)
|
||||
var frequencyRxValue = null;
|
||||
if (DX_WATERFALL_UTILS.fieldMapping.hasOptionalField('frequency_rx')) {
|
||||
|
||||
if (window.catState && window.catState.frequency_rx) {
|
||||
frequencyRxValue = window.catState.frequency_rx;
|
||||
} else if (DX_WATERFALL_UTILS.fieldMapping.hasOptionalField('frequency_rx')) {
|
||||
// Fallback to form field if CAT not available
|
||||
var $frequencyRx = DX_WATERFALL_UTILS.fieldMapping.getField('frequency_rx', true);
|
||||
frequencyRxValue = $frequencyRx.val();
|
||||
}
|
||||
@@ -2264,10 +2151,8 @@ var dxWaterfall = {
|
||||
// Force immediate cache refresh and visual update
|
||||
this.lastFrequencyRefreshTime = 0;
|
||||
|
||||
// Only refresh from DOM if CAT is available - otherwise keep waterfall frequency independent
|
||||
if (isCATAvailable()) {
|
||||
this.refreshFrequencyCache();
|
||||
}
|
||||
// Note: refreshFrequencyCache() no longer needed here
|
||||
// Waterfall reads frequency from window.catState (CAT data), not form fields
|
||||
|
||||
if (this.canvas && this.ctx) {
|
||||
this.refresh();
|
||||
@@ -3019,7 +2904,9 @@ var dxWaterfall = {
|
||||
|
||||
// Get band limits for current band and region
|
||||
getBandLimits: function() {
|
||||
var currentBand = this.getCurrentBand();
|
||||
// Use the band we have spots for, not the form selector
|
||||
// This prevents drawing wrong band limits when form is changed manually
|
||||
var currentBand = this.currentSpotBand || this.getCurrentBand();
|
||||
var currentRegion = this.continentToRegion(this.currentContinent);
|
||||
var regionKey = 'region' + currentRegion;
|
||||
|
||||
@@ -3063,29 +2950,6 @@ var dxWaterfall = {
|
||||
return limits;
|
||||
},
|
||||
|
||||
// Check if frequency is more than 1000 kHz outside current band limits
|
||||
// Returns true if band should be recalculated
|
||||
isFrequencyFarOutsideBand: function(frequencyKhz) {
|
||||
var bandLimits = this.getBandLimits();
|
||||
|
||||
// If no band limits available, don't trigger recalculation
|
||||
if (!bandLimits) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var threshold = DX_WATERFALL_CONSTANTS.THRESHOLDS.BAND_CHANGE_THRESHOLD;
|
||||
var lowerThreshold = bandLimits.start_khz - threshold;
|
||||
var upperThreshold = bandLimits.end_khz + threshold;
|
||||
|
||||
// Check if frequency is more than threshold outside the band
|
||||
if (frequencyKhz < lowerThreshold || frequencyKhz > upperThreshold) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Recalculate and update band based on frequency
|
||||
// Get band name for a given frequency in kHz
|
||||
getFrequencyBand: function(frequencyKhz) {
|
||||
// Check if frequencyToBand function exists
|
||||
@@ -3100,55 +2964,15 @@ var dxWaterfall = {
|
||||
return band && band !== '' ? band : null;
|
||||
},
|
||||
|
||||
updateBandFromFrequency: function(frequencyKhz) {
|
||||
var newBand = this.getFrequencyBand(frequencyKhz);
|
||||
|
||||
if (newBand) {
|
||||
// Check if the band exists in the select options
|
||||
var bandExists = this.$bandSelect.find('option[value="' + newBand + '"]').length > 0;
|
||||
|
||||
if (bandExists) {
|
||||
// Set flag to prevent band change event handler from running
|
||||
// This prevents form reset during CAT/WebSocket frequency updates
|
||||
window.programmaticBandChange = true;
|
||||
|
||||
// CRITICAL: Set waterfall flag IMMEDIATELY before the band changes
|
||||
// This ensures hasParametersChanged() can detect this was programmatic
|
||||
this.programmaticBandUpdate = true;
|
||||
|
||||
// Update the band dropdown (in the QSO form)
|
||||
this.$bandSelect.val(newBand);
|
||||
|
||||
// Reset flags after a short delay to allow event to process
|
||||
var self = this;
|
||||
setTimeout(function() {
|
||||
window.programmaticBandChange = false;
|
||||
// Keep waterfall flag longer to survive the parameter check
|
||||
}, 50);
|
||||
} else {
|
||||
// Band doesn't exist in dropdown, select the first available option as fallback
|
||||
var firstOption = this.$bandSelect.find('option:first').val();
|
||||
if (firstOption) {
|
||||
window.programmaticBandChange = true;
|
||||
this.programmaticBandUpdate = true;
|
||||
this.$bandSelect.val(firstOption);
|
||||
var self = this;
|
||||
setTimeout(function() {
|
||||
window.programmaticBandChange = false;
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// ========================================
|
||||
// CANVAS DRAWING AND RENDERING FUNCTIONS
|
||||
// ========================================
|
||||
|
||||
// Draw band mode indicators (colored lines below ruler showing CW/DIGI/PHONE segments)
|
||||
drawBandModeIndicators: function() {
|
||||
// Get current region and band
|
||||
var currentBand = this.getCurrentBand();
|
||||
// Use the band we have spots for, not the form selector
|
||||
// This prevents drawing wrong band mode indicators when form is changed manually
|
||||
var currentBand = this.currentSpotBand || this.getCurrentBand();
|
||||
var currentRegion = this.continentToRegion(this.currentContinent);
|
||||
var regionKey = 'region' + currentRegion;
|
||||
|
||||
@@ -3384,7 +3208,13 @@ var dxWaterfall = {
|
||||
// Set userInitiatedFetch flag
|
||||
this.userInitiatedFetch = userInitiated === true;
|
||||
|
||||
var band = this.getCurrentBand();
|
||||
// Calculate band from current frequency (independent of form selector)
|
||||
var currentFreqKhz = this.getCachedMiddleFreq();
|
||||
var band = null;
|
||||
|
||||
if (currentFreqKhz > 0) {
|
||||
band = this.getFrequencyBand(currentFreqKhz);
|
||||
}
|
||||
|
||||
// If band is invalid or empty, use a default band for initial fetch
|
||||
if (!band || band === '' || band.toLowerCase() === 'select') {
|
||||
@@ -3483,9 +3313,9 @@ var dxWaterfall = {
|
||||
cache: false,
|
||||
success: function(data) {
|
||||
// Check if band has changed since this fetch was initiated
|
||||
// If it has, discard this data (it's stale)
|
||||
var currentBand = self.getCurrentBand();
|
||||
if (band !== currentBand) {
|
||||
// Compare against currentSpotBand (what we're displaying) not form selector
|
||||
var currentDisplayBand = self.currentSpotBand || band;
|
||||
if (band !== currentDisplayBand) {
|
||||
// Clear safety timeout even for stale data
|
||||
if (self.safetyTimeoutId) {
|
||||
clearTimeout(self.safetyTimeoutId);
|
||||
@@ -3539,6 +3369,9 @@ var dxWaterfall = {
|
||||
self.lastFetchContinent = de;
|
||||
self.lastFetchAge = age;
|
||||
|
||||
// Track which band we currently have spots for
|
||||
self.currentSpotBand = band;
|
||||
|
||||
// Invalidate caches when spots are updated
|
||||
self.cache.visibleSpots = null;
|
||||
self.cache.visibleSpotsParams = null;
|
||||
@@ -3628,11 +3461,16 @@ var dxWaterfall = {
|
||||
|
||||
// Get current mode from form or default to All
|
||||
getCurrentMode: function() {
|
||||
// Prefer CAT state if available (radio controls mode)
|
||||
if (window.catState && window.catState.mode) {
|
||||
return window.catState.mode;
|
||||
}
|
||||
|
||||
// Fallback to form field if CAT not available
|
||||
// Safety check: return default if not initialized
|
||||
if (!this.$modeSelect) {
|
||||
return 'All';
|
||||
}
|
||||
// Try to get mode from form - adjust selector based on your HTML structure
|
||||
var mode = this.$modeSelect.val() || 'All';
|
||||
return mode;
|
||||
},
|
||||
@@ -4865,7 +4703,7 @@ var dxWaterfall = {
|
||||
// NOTE: Removed targetFrequencyHz blocking - waterfall updates immediately on click
|
||||
// Stale CAT updates are ignored in handleCATFrequencyUpdate() instead
|
||||
|
||||
// Check if band or mode has changed and fetch new spots if needed
|
||||
// Check if we need to do initial fetch or band has changed via CAT
|
||||
// Skip during CAT operations to prevent interference
|
||||
if (!this.catTuning && !this.frequencyChanging) {
|
||||
// Force initial fetch if we haven't done one yet (even with invalid frequency/band)
|
||||
@@ -4875,24 +4713,46 @@ var dxWaterfall = {
|
||||
this.initialFetchDone = true; // Set flag BEFORE fetch to prevent duplicate calls
|
||||
this.fetchDxSpots(true, false); // Initial fetch, but not user-initiated (background)
|
||||
}
|
||||
} else if (this.hasParametersChanged()) {
|
||||
this.fetchDxSpots(true, true); // User changed band/mode - mark as user-initiated
|
||||
} else {
|
||||
// Check if radio has changed to a different band (via CAT frequency updates)
|
||||
// Calculate band from current frequency, not from form selector
|
||||
var currentFreqKhz = this.getCachedMiddleFreq();
|
||||
var calculatedBand = null;
|
||||
|
||||
if (currentFreqKhz > 0) {
|
||||
calculatedBand = this.getFrequencyBand(currentFreqKhz);
|
||||
}
|
||||
|
||||
// If we have a valid calculated band and it differs from what we have spots for, fetch new spots
|
||||
if (calculatedBand && calculatedBand !== '' && calculatedBand.toLowerCase() !== 'select' &&
|
||||
this.currentSpotBand && calculatedBand !== this.currentSpotBand) {
|
||||
// Radio frequency changed to different band - fetch spots for new band
|
||||
DX_WATERFALL_UTILS.log.debug('[DX Waterfall] Band changed via frequency: ' + this.currentSpotBand + ' → ' + calculatedBand);
|
||||
|
||||
// IMMEDIATELY update currentSpotBand to prevent infinite loop
|
||||
// The refresh() runs 60fps, so we must update this before next cycle
|
||||
this.currentSpotBand = calculatedBand;
|
||||
|
||||
// Mark that we're waiting for new band data
|
||||
this.waitingForData = true;
|
||||
this.dataReceived = false;
|
||||
this.operationStartTime = Date.now(); // Start timer for visual feedback
|
||||
|
||||
// Fetch spots for new band (not user-initiated, but automatic via CAT)
|
||||
this.fetchDxSpots(true, false);
|
||||
|
||||
// Invalidate band-related caches
|
||||
this.bandLimitsCache = null;
|
||||
this.cachedBandForEdges = calculatedBand;
|
||||
}
|
||||
}
|
||||
// NOTE: Removed hasParametersChanged() check - waterfall no longer monitors form band/mode changes
|
||||
// Waterfall operates independently but will follow radio band changes via CAT
|
||||
// Spots are fetched only on: initial load, radio band change (CAT), periodic refresh, or explicit user action
|
||||
}
|
||||
|
||||
// Periodically refresh frequency cache to catch changes
|
||||
// Skip during CAT operations to prevent interference
|
||||
if (!this.catTuning && !this.frequencyChanging) {
|
||||
this.refreshFrequencyCache();
|
||||
}
|
||||
|
||||
// Check if current frequency is far outside band limits and update band if needed
|
||||
// This handles manual frequency entry in the input field
|
||||
// Skip if user just manually changed the band to prevent reverting their choice
|
||||
var currentFreq = this.getCachedMiddleFreq();
|
||||
if (currentFreq > 0 && !this.userChangedBand && this.isFrequencyFarOutsideBand(currentFreq)) {
|
||||
this.updateBandFromFrequency(currentFreq);
|
||||
}
|
||||
// Note: refreshFrequencyCache() no longer needed here
|
||||
// Waterfall reads frequency from window.catState (CAT data), not form fields
|
||||
|
||||
// Update canvas internal dimensions to match current CSS dimensions
|
||||
this.updateDimensions();
|
||||
@@ -5526,7 +5386,8 @@ var dxWaterfall = {
|
||||
var hours = String(this.lastUpdateTime.getHours()).padStart(2, '0');
|
||||
var minutes = String(this.lastUpdateTime.getMinutes()).padStart(2, '0');
|
||||
var updateTimeStr = hours + ':' + minutes;
|
||||
var currentBand = this.getCurrentBand();
|
||||
// Display the band we have spots for, not the form selector
|
||||
var currentBand = this.currentSpotBand || this.getCurrentBand();
|
||||
|
||||
zoomHTML += '<span style="font-size: 11px; color: #888888;">';
|
||||
zoomHTML += displayedSpotsCount + '/' + this.totalSpotsCount + ' ' + currentBand + ' ' + this.currentContinent + ' ' + lang_dxwaterfall_spots + ' @' + updateTimeStr + 'LT';
|
||||
@@ -5736,7 +5597,8 @@ var dxWaterfall = {
|
||||
this.lastSpotCollectionTime = currentTime;
|
||||
|
||||
var currentFreq = this.getCachedMiddleFreq();
|
||||
var currentBand = this.getCurrentBand();
|
||||
// Use the band we have spots for, not the form selector
|
||||
var currentBand = this.currentSpotBand || this.getCurrentBand();
|
||||
var currentMode = this.getCurrentMode();
|
||||
|
||||
// Filter spots for current band
|
||||
@@ -6186,7 +6048,6 @@ var dxWaterfall = {
|
||||
this.initialFetchDone = false;
|
||||
this.waitingForCATFrequency = true;
|
||||
this.userEditingFrequency = false;
|
||||
this.userChangedBand = false;
|
||||
this.programmaticModeChange = false;
|
||||
this.zoomChanging = false;
|
||||
this.spotNavigating = false;
|
||||
@@ -6215,12 +6076,11 @@ var dxWaterfall = {
|
||||
// Reset spot info key
|
||||
this.lastSpotInfoKey = null;
|
||||
|
||||
// Clear band/mode tracking
|
||||
this.lastBand = null;
|
||||
this.lastMode = null;
|
||||
// Clear band tracking
|
||||
this.lastFetchBand = null;
|
||||
this.lastFetchContinent = null;
|
||||
this.lastFetchAge = null;
|
||||
this.currentSpotBand = null; // Reset the band we have spots for
|
||||
|
||||
// Reset timestamps
|
||||
this.lastUpdateTime = null;
|
||||
@@ -6346,6 +6206,13 @@ function setMode(mode, skipTrigger) {
|
||||
// @param fromWaterfall - True if this change was initiated by waterfall (clicking spot/tune icon), false for external calls
|
||||
function setFrequency(frequencyInKHz, fromWaterfall) {
|
||||
|
||||
// PROTECTION: If user is manually updating frequency from form, don't tune radio
|
||||
// This prevents form changes from controlling the radio (radio should control form)
|
||||
if (typeof window.user_updating_frequency !== 'undefined' && window.user_updating_frequency) {
|
||||
DX_WATERFALL_UTILS.log.info('[setFrequency] Skipping radio tune - user manually updating form');
|
||||
return;
|
||||
}
|
||||
|
||||
// Input validation
|
||||
if (!frequencyInKHz || typeof frequencyInKHz !== 'number') {
|
||||
DX_WATERFALL_UTILS.log.warn('[setFrequency] Invalid frequency parameter:', frequencyInKHz);
|
||||
@@ -6509,8 +6376,8 @@ function setFrequency(frequencyInKHz, fromWaterfall) {
|
||||
dxWaterfall.frequencyChanging = false;
|
||||
dxWaterfall.catTuningStartTime = null;
|
||||
dxWaterfall.spotNavigating = false; // Clear navigation flag on timeout
|
||||
// Force immediate cache refresh and visual update when timeout occurs
|
||||
dxWaterfall.refreshFrequencyCache();
|
||||
// Force visual update when timeout occurs
|
||||
// Note: refreshFrequencyCache() not needed - waterfall reads from catState
|
||||
if (dxWaterfall.canvas && dxWaterfall.ctx) {
|
||||
dxWaterfall.ctx.clearRect(0, 0, dxWaterfall.canvas.width, dxWaterfall.canvas.height);
|
||||
dxWaterfall.refresh();
|
||||
@@ -6884,10 +6751,6 @@ function setFrequency(frequencyInKHz, fromWaterfall) {
|
||||
window.dxwaterfall_cat_debounce_lock = 1;
|
||||
}
|
||||
|
||||
if (dxWaterfall.isFrequencyFarOutsideBand(clickedSpot.frequency)) {
|
||||
dxWaterfall.updateBandFromFrequency(clickedSpot.frequency);
|
||||
}
|
||||
|
||||
// CRITICAL: Set mode FIRST (without triggering change event), THEN set frequency
|
||||
// This ensures setFrequency() reads the correct mode from the dropdown
|
||||
var radioMode = DX_WATERFALL_UTILS.navigation.determineRadioMode(clickedSpot);
|
||||
@@ -6933,11 +6796,6 @@ function setFrequency(frequencyInKHz, fromWaterfall) {
|
||||
return; // Ignore clicks in invalid frequency range
|
||||
}
|
||||
|
||||
// Check if frequency is far outside current band and update band if needed
|
||||
if (dxWaterfall.isFrequencyFarOutsideBand(clickedFreq)) {
|
||||
dxWaterfall.updateBandFromFrequency(clickedFreq);
|
||||
}
|
||||
|
||||
// Set the frequency to where user clicked
|
||||
setFrequency(clickedFreq, true);
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ async function set_qrg() {
|
||||
async function set_new_qrg() {
|
||||
let new_qrg = $('#freq_calculated').val();
|
||||
|
||||
// Set flag to indicate this is a manual form update (not from CAT/radio)
|
||||
// This prevents the radio from being tuned when user manually enters frequency
|
||||
window.user_updating_frequency = true;
|
||||
|
||||
// Trim and validate input
|
||||
if (new_qrg !== null && new_qrg !== undefined) {
|
||||
new_qrg = new_qrg.trim();
|
||||
@@ -77,12 +81,15 @@ async function set_new_qrg() {
|
||||
const result = await $.get(base_url + 'index.php/qso/band_to_freq/' + $('#band').val() + '/' + $('.mode').val());
|
||||
$('#frequency').val(result);
|
||||
await set_qrg();
|
||||
window.user_updating_frequency = false; // Clear flag
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch default frequency:', error);
|
||||
window.user_updating_frequency = false; // Clear flag
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.user_updating_frequency = false; // Clear flag
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,10 +141,11 @@ async function set_new_qrg() {
|
||||
$('#freq_calculated').val(parsed_qrg);
|
||||
$('#band').val(frequencyToBand(qrg_hz));
|
||||
|
||||
// Tune the radio to the new frequency if CAT is available (using global selectedRadioId)
|
||||
if (typeof tuneRadioToFrequency === 'function') {
|
||||
tuneRadioToFrequency(null, qrg_hz); // null = use global selectedRadioId
|
||||
}
|
||||
// Clear the manual update flag
|
||||
window.user_updating_frequency = false;
|
||||
|
||||
// DO NOT tune the radio - let the radio control the frequency
|
||||
// The form follows the radio, not the other way around
|
||||
}
|
||||
|
||||
$('#frequency').on('change', function () {
|
||||
|
||||
@@ -2245,87 +2245,9 @@ $('#band').on('change', function () {
|
||||
// Clear the QSO form when band is manually changed
|
||||
$('#btn_reset').click();
|
||||
|
||||
// Set flag to prevent waterfall from auto-reverting the band change
|
||||
if (typeof dxWaterfall !== 'undefined') {
|
||||
dxWaterfall.userChangedBand = true;
|
||||
if (dxWaterfall.userChangedBandTimer) {
|
||||
clearTimeout(dxWaterfall.userChangedBandTimer);
|
||||
}
|
||||
dxWaterfall.userChangedBandTimer = setTimeout(function() {
|
||||
dxWaterfall.userChangedBand = false;
|
||||
}, 10000);
|
||||
|
||||
// Reset operation timer when band is manually changed
|
||||
dxWaterfall.operationStartTime = Date.now();
|
||||
|
||||
// Set waiting flags to prevent waterfall from rendering with wrong band edges
|
||||
// This will be cleared after the frequency is loaded
|
||||
dxWaterfall.waitingForData = true;
|
||||
dxWaterfall.dataReceived = false;
|
||||
dxWaterfall.waitingForFrequencyUpdate = true; // Prevent spot fetch from clearing waitingForData
|
||||
|
||||
// Invalidate frequency cache to prevent using stale frequency during band change
|
||||
// This forces getCachedMiddleFreq() to wait for new frequency
|
||||
if (dxWaterfall.lastValidCommittedFreq) {
|
||||
dxWaterfall.lastValidCommittedFreq = null;
|
||||
dxWaterfall.cache.middleFreq = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if current frequency is already in the selected band
|
||||
const currentFreq = $('#frequency').val();
|
||||
const currentBand = currentFreq ? frequencyToBand(currentFreq) : '';
|
||||
|
||||
// Only fetch default frequency if current frequency is not already in the selected band
|
||||
if (!currentFreq || currentBand !== selectedBand) {
|
||||
$.get(base_url + 'index.php/qso/band_to_freq/' + selectedBand + '/' + $('.mode').val(), function (result) {
|
||||
// Set the frequency
|
||||
$('#frequency').val(result);
|
||||
|
||||
// Update the displayed frequency field with proper units
|
||||
set_qrg();
|
||||
|
||||
// Tune the radio to the new frequency FIRST (using global selectedRadioId)
|
||||
// Use skipWaterfall=true to force direct radio tuning when band is manually changed
|
||||
if (typeof tuneRadioToFrequency === 'function') {
|
||||
tuneRadioToFrequency(null, result, null, null, null, true); // skipWaterfall=true
|
||||
}
|
||||
|
||||
// DO NOT clear waitingForFrequencyUpdate yet - wait for CAT to confirm the frequency
|
||||
// The CAT update handler in footer.php will clear it when the radio responds
|
||||
// This prevents the waterfall from rendering with stale frequency data
|
||||
});
|
||||
} else {
|
||||
// Frequency is already in the selected band, just update display
|
||||
set_qrg();
|
||||
|
||||
// Still tune the radio to the current frequency (user may have changed band but frequency stayed the same)
|
||||
if (typeof tuneRadioToFrequency === 'function') {
|
||||
const currentFreqHz = $('#frequency').val();
|
||||
if (currentFreqHz) {
|
||||
tuneRadioToFrequency(null, currentFreqHz, null, null, null, true); // skipWaterfall=true
|
||||
}
|
||||
}
|
||||
|
||||
// Clear waiting flags immediately since no frequency change needed
|
||||
if (typeof dxWaterfall !== 'undefined') {
|
||||
dxWaterfall.waitingForData = false;
|
||||
dxWaterfall.waitingForFrequencyUpdate = false;
|
||||
|
||||
// Update zoom menu after band change completes
|
||||
if (dxWaterfall.updateZoomMenu) {
|
||||
dxWaterfall.updateZoomMenu(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#frequency_rx').val("");
|
||||
$('#band_rx').val("");
|
||||
$("#selectPropagation").val("");
|
||||
$("#sat_name").val("");
|
||||
$("#sat_mode").val("");
|
||||
$("#callsign").blur();
|
||||
stop_az_ele_ticker();
|
||||
// Band selector is now display-only - it follows the radio frequency
|
||||
// Manual band changes do NOT update the frequency or tune the radio
|
||||
// The radio controls the form, not the other way around
|
||||
});
|
||||
|
||||
/* On Key up Calculate Bearing and Distance */
|
||||
@@ -2944,12 +2866,18 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
|
||||
// Handle manual frequency entry - tune radio when user changes frequency
|
||||
// Handle manual frequency entry - DO NOT tune radio (form follows radio, not vice versa)
|
||||
$('#freq_calculated').on('change', function() {
|
||||
// Skip if CAT is currently updating - don't interfere with radio updates
|
||||
if (typeof cat_updating_frequency !== 'undefined' && cat_updating_frequency) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set_new_qrg() is defined in qrg_handler.js and will:
|
||||
// 1. Parse the frequency value and convert to Hz
|
||||
// 2. Update #frequency (hidden field)
|
||||
// 3. Tune the radio via tuneRadioToFrequency()
|
||||
// 3. Update #band selector to match the frequency
|
||||
// NOTE: Does NOT tune the radio - manual form changes are display-only
|
||||
if (typeof set_new_qrg === 'function') {
|
||||
set_new_qrg();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user