simpleSA/SweepHi.ino
2025-02-22 18:13:51 +08:00

395 lines
12 KiB
C++

// Version: 1.0
#ifdef HI_RANGE
/*
* Initialise variables and SI4432 for the high frequency sweep
*/
void initSweepHigh()
{
#ifdef RF_SWITCH
digitalWrite (RF_SWITCH, RF_SWITCH_HIGH_RANGE); // LO RF Switch to mixer
#endif
// set up checkerboard sizes
gridHeight = GRID_HEIGHT;
gridWidth = DISPLAY_POINTS;
yGrid = Y_GRID; // no of grid divisions
yDelta = gridHeight / yGrid; // no of points/division
xGrid = X_GRID;
xOrigin = X_ORIGIN;
yOrigin = Y_ORIGIN;
displayPoints = DISPLAY_POINTS;
scaleX = displayPoints - 2 * CHAR_WIDTH;
xDelta = displayPoints / xGrid;
startFreqMinLimit = START_MIN_HIGH;
stopFreqMaxLimit = STOP_MAX_HIGH;
simpleSA_mode = SA_HIGH_RANGE;
setting.Mode = simpleSA_mode;
setSettingChangeMillis();
init_sweep();
SetRefOutput ( -1 ); // Turn off the ref output
ResetSAMenuStack(); // Put menu stack back to root level
quickSelectionSelected = false;
validateQuickSelect ( 1 ); // make sure quick select is valid
resetMarkers();
// Serial.printf("InitSweepHigh Done ");
// Serial.printf("lo reg 2= %x\n", xmit.ReadByte(2));
}
/*
* This function section handles the high freq range sweep
*/
void doSweepHigh()
{
static uint32_t autoSweepStep = 0;
static uint32_t autoSweepFreq = 0;
static uint32_t autoSweepFreqStep = 0;
static uint32_t nextPointFreq = 0; // Frequency for the next display point. Used for substeps
static unsigned long nowMicros;
static int16_t pointMinGain; // to record minimum gain for the current display point
static int16_t lastMode; // Record last operating mode (sig gen, normal)
static uint32_t actualFreq; // actual frequency
/*
* If paused and at the start of a sweep then do nothing
*/
if (!sweepStartDone && paused)
return;
/*
* If the "sweepStartDone" flag is false or if the "initSweep" flag is true, we need
* to set things up for the sweep.
*/
if (( !sweepStartDone || initSweep || changedSetting ) )
{
if ( initSweep || changedSetting ) // Something has changed, or a first start, so need to owrk out some basic things
{
//Serial.println("InitSweep or changedSetting");
autoSweepFreqStep = ( settingHigh.ScanStop - settingHigh.ScanStart ) / displayPoints; // MHz
vbw = autoSweepFreqStep / 1000.0; // Set the video resolution (kHz)
requiredRBW10 = settingHigh.Bandwidth10; // and the resolution bandwidth (kHz * 10)
if ( requiredRBW10 == 0 ) // If the bandwidth is on "Auto" work out the required RBW
requiredRBW10 = (( settingHigh.ScanStop - settingHigh.ScanStart )) / 29000; // 290 points on display, kHz
if ( requiredRBW10 < 26 ) // If it's less than 2.6KHz
requiredRBW10 = 26; // set it to 2.6KHz
if ( requiredRBW10 > 6207 )
requiredRBW10 = 6207;
if ( requiredRBW10 != old_requiredRBW10 )
{
bandwidth = xmit.SetRBW ( requiredRBW10, &delaytime, &bpfIndex ); // Set it in the receiver Si4432
old_requiredRBW10 = requiredRBW10;
}
/*
* Need multiple readings for each pixel in the display to avoid missing signals.
* Work out how many points needed for the whole sweep:
*/
sweepPoints = (uint32_t)(( settingHigh.ScanStop - settingHigh.ScanStart ) / bandwidth / 1000.0 * OVERLAP + 0.5); // allow for some overlap (filters will have 3dB roll off at edge) and round up
if ( sweepPoints < displayPoints )
sweepPoints = displayPoints; // At least the right number of points for the display
sweepFreqStep = ( settingHigh.ScanStop - settingHigh.ScanStart ) / sweepPoints; // Step for each reading
// pre-calculate adjustment for RSSI values
dBadjust = - 120.0 + settingHigh.LevelOffset - settingHigh.ExternalGain + bpfCalibrations[bpfIndex];
// Serial.printf("SweepHi dBadjust = %f; leveloffset = %f; ext gain = %f, bpfCal = %f\n",
// dBadjust, settingHigh.LevelOffset, settingHigh.ExternalGain, bpfCalibrations[bpfIndex]);
resetAverage = changedSetting;
maxGrid = settingHigh.MaxGrid;
minGrid = settingHigh.MinGrid;
#if ( USE_WIFI )
// Vary number of points to send in each chunk depending on delaytime
// A chunk is sent at the end of each sweep regardless
wiFiPoints = wiFiTargetTime / delaytime;
if (wiFiPoints > MAX_WIFI_POINTS)
wiFiPoints = MAX_WIFI_POINTS;
if (wiFiPoints > displayPoints*OVERLAP)
wiFiPoints = displayPoints*OVERLAP;
// Serial.printf("No of wifiPoints set to %i\n", wiFiPoints);
if ( numberOfWebsocketClients > 0 )
pushSettings ();
#endif // #if ( USE_WIFI )
} // initSweep || changedSetting
autoSweepStep = 0; // Set the step counter to zero
sweepStep = 0;
autoSweepFreq = settingHigh.ScanStart; // Set the start frequency.
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
while (( micros() - setFreqMicros ) < delaytime ) // Make sure enough time has elasped since previous frequency write
{
}
xmit.SetFrequency ( autoSweepFreq ); // set the LO frequency
setFreqMicros = micros(); // Store the time the frequency was changed
/*
* Actual frequency in the SI4432 is rounded and is limited by the possible resolution
*/
actualFreq = xmit.GetFrequency(); // Used for next RSSI command and JSON entry
#if ( USE_WIFI )
if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan
{
initChunkSweepDoc (sweepStep);
jsonDocInitialised = true;
}
else
jsonDocInitialised = false;
#endif // #if ( USE_WIFI )
startFreq = settingHigh.ScanStart; // Start freq for the LO
stopFreq = settingHigh.ScanStop; // Stop freq for the LO
pointMinGain = 100; // Reset min/max values
pointMaxRSSI = 0;
/*
* If an adjustment of the level is requested to obtain correct dBm
*/
if ( setActualPowerRequested )
{
SetPowerLevel ( actualPower );
setActualPowerRequested = false;
// Serial.printf ( "Setting actual Power %f \n", actualPower );
}
/*
* Copy the values for the peaks (marker positions) to the old versions. No need to
* reset the indicies or frequencies; just the "Level".
*/
for ( int i = 0; i < MARKER_COUNT; i++ )
{
marker[i].SetValue(peaks[i].Index, peaks[i].Freq, peaks[i].Level);
peaks[i].Level = 0;
}
DisplayInfo (); // Display axis, top and side bar text
peakLevel = 0; // Reset the peak values for the sweep
peakFreq = 0.0;
peakGain = 100; // Set to higher than gain can ever be
lastMinRSSI = minRSSI;
minRSSI = 300; // Higher than it can be
pointsPastPeak = 0; // Avoid possible peak detection at start of sweep
peakRSSI = 0;
maxRSSI = 0;
sweepStartDone = true; // Make sure this initialize is only done once per sweep
initSweep = false;
changedSetting = false;
lastSweepStartMicros = sweepStartMicros; // Set last time we got here
sweepStartMicros = micros(); // Current time
sweepMicros = sweepStartMicros - lastSweepStartMicros; // Calculate sweep time (no rollover handling)
} // End of "if ( !sweepStartDone ) || initSweep || changedSetting )"
/*
* Here we do the actual sweep. Save the current step and frequencies for the next time
* through, then wait the required amount of time based on the RBW before taking the
* signal strength reading and changing the transmitter (LO) frequency.
*/
oldSweepStep = autoSweepStep;
oldSweepFreq = actualFreq;
/*
* Wait until time to take the next reading. If a long enough wait left
* then check the touchscreen and Websockets while we are waiting
* to improve response
*/
nowMicros = micros();
while (( nowMicros - setFreqMicros ) < delaytime )
{
#if ( USE_WIFI )
if ( ( nowMicros - setFreqMicros + delaytime > MIN_DELAY_WEBSOCKETS ) &&
( (nowMicros - lastWebsocketMicros > websocketInterval) || (numberOfWebsocketClients > 0) ) )
{
// Serial.print("W");
webSocket.loop (); // Check websockets - includes Yield() to allow other events to run
// Serial.println("w");
lastWebsocketMicros = nowMicros;
}
#endif
UiProcess(); // Check the touch screen and encoder
if ( ui_mode != UI_NORMAL )
return; // avoid risk of drawing vertical stripe over menu during remainder of scan
// Serial.println("w");
nowMicros = micros();
}
rxRSSI = xmit.GetRSSI (); // Read the RSSI from the LO SI4432
/*
* Note that there are two different versions of the print statement to send the
* RSSI readings to the serial output. You can change which one is commented out.
*
* The first one produces a tab separated list of just the frequency and RSSI
* reading. That format can be easily read inte something like Excel.
*
* The second one produces a listing more fit for human consumption!
*/
if ( showRSSI ) // Displaying RSSI?
{
// Serial.printf ( "%s\t%03d\n",
// FormatFrequency ( autoSweepFreq) , rxRSSI ); // Send it to the serial output
Serial.printf ( " LO Freq: %s", FormatFrequency ( xmit.GetFrequency() ) );
Serial.printf ( " Sweep Freq: %s (%u)", FormatFrequency ( autoSweepFreq), autoSweepFreq );
Serial.printf ( " Actual Freq %s - RSSI: %03d\n",
FormatFrequency ( actualFreq ), rxRSSI ); // Send it to the serial output
}
if ( (numberOfWebsocketClients > 0) || (settingHigh.ShowGain) )
gainReading = GetPreampGainHigh ( &AGC_On, &AGC_Reg ); // Record the preamp/lna gains
autoSweepFreq += sweepFreqStep; // Increment the frequency
sweepStep++; // and increment the step count
/*
* Change the transmitter frequency for the next reading and record the time for
* the RBW required settling delay.
*/
xmit.SetFrequency ( autoSweepFreq ); // Set the new LO frequency as soon as RSSI read
// Serial.printf("LO Required: %i Actual %i\n", f, xmit.GetFrequency());
setFreqMicros = micros(); // Store the time the LO frequency was changed
#if ( USE_WIFI )
addJsonDataPoint ();
#endif
/*
* Actual frequency in the SI4432 is rounded and is limited by the possible resolution
*/
actualFreq = xmit.GetFrequency(); // Used for next RSSI command and JSON entry
if ( rxRSSI > pointMaxRSSI ) // RSSI > maximum value for this point so far?
{
myActual[autoSweepStep] = rxRSSI; // Yes, save it
pointMaxRSSI = rxRSSI; // Added by G3ZQC - Remember new maximim
pointMaxFreq = oldSweepFreq;
}
if ( gainReading < pointMinGain ) // Gain < minimum gain for this point so far?
{
myGain[autoSweepStep] = gainReading; // Yes, save it
pointMinGain = gainReading; // Added by G3ZQC - Remember new minimum
}
if (rxRSSI < minRSSI) // Detect minimum for sweep
minRSSI = rxRSSI;
/*
* Have we enough readings for this display point? If yes, so do any averaging etc, reset
* the values so peak in the frequency step is recorded and update the display.
*/
if ( autoSweepFreq >= nextPointFreq )
{
nextPointFreq = nextPointFreq + autoSweepFreqStep; // Next display point frequency
autoSweepStep++; // Increment the index
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for the markers
DrawTraces ( oldSweepStep ); // Plot the data points (pass in freq of zero so no low pass filter compensation)
detectPeaks();
pointMinGain = 100; // Reset min/max values
pointMaxRSSI = 0;
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for the markers
if ( settingHigh.SubtractStorage )
rxRSSI = 128 + rxRSSI - myStorage[oldSweepStep];
if ( oldSweepStep > 0 ) // Only push if not first point (two pixel wide img)
img.pushSprite ( xOrigin+oldSweepStep-1, yOrigin );
} // End of "if ( autoSweepFreq >= nextPointFreq )"
if ( sweepStep >= sweepPoints ) // If we have got to the end of the sweep
{
// autoSweepStep = 0;
sweepStartDone = false;
resetAverage = false;
if ( sweepCount < 2 )
sweepCount++; // Used to disable wifi at start
// Serial.printf("MaxRSSI = %i, freq = %i\n", maxRSSI, maxFreq);
oldPeakLevel = maxRSSI; //Save value of peak level for use by the "SetPowerLevel" function
if ( myActual[displayPoints-1] == 0 ) // Ensure a value in last data point
{
myActual[displayPoints-1] = rxRSSI; // Yes, save it
myGain[displayPoints-1] = gainReading;
myFreq[displayPoints-1] = oldSweepFreq;
}
if ( showRSSI == 1 ) // Only show it once?
showRSSI = 0; // Then turn it off
#if ( USE_WIFI )
sendJsonChunk();
#endif
} // End of "if ( sweepStep >= sweepPoints )"
} // End of "doSweepHigh"
#endif // #ifdef HI_RANGE