commit
9348e1d97f
540
Bandscope.ino
540
Bandscope.ino
@ -1,9 +1,23 @@
|
||||
|
||||
uint32_t colourTest;
|
||||
|
||||
/*
|
||||
* Initialise variables and SI4432 for the low frequency sweep
|
||||
*/
|
||||
void initBandscope()
|
||||
{
|
||||
// set up checkerboard sizes
|
||||
waterfallHeight = WATERFALL_HEIGHT;
|
||||
gridHeight = SCREEN_HEIGHT - waterfallHeight - 10;
|
||||
gridWidth = SCREEN_WIDTH;
|
||||
yGrid = Y_GRID; // no of grid divisions
|
||||
yDelta = gridHeight / yGrid; // no of points/division
|
||||
xGrid = X_GRID;
|
||||
xOrigin = 0;
|
||||
yOrigin = 0;
|
||||
displayPoints = setting.BandscopePoints;
|
||||
xDelta = SCREEN_WIDTH / xGrid;
|
||||
|
||||
ClearDisplay ();
|
||||
/*
|
||||
* Set up the "img" Sprite. This is the image for the graph. It makes for faster display
|
||||
@ -22,25 +36,25 @@ void initBandscope()
|
||||
img.setTextSize ( 1 );
|
||||
img.setColorDepth ( 16 );
|
||||
img.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
img.createSprite ( 2, GRID_HEIGHT + 1 ); // Only 2 columns wide
|
||||
img.createSprite ( 2, gridHeight + 1 ); // Only 2 columns wide
|
||||
|
||||
|
||||
/*
|
||||
* The "tSprite" is used for displaying the data above the scan grid.
|
||||
* The "tSprite" is used for displaying the data above the scan grid - we don't use it in this mode
|
||||
* The "sSprite" is for displaying the sidebar stuff, but reused here for the waterfall
|
||||
*/
|
||||
|
||||
tSprite.deleteSprite();
|
||||
tSprite.setRotation ( 0 );
|
||||
tSprite.setTextSize ( 1 );
|
||||
tSprite.setColorDepth ( 16 );
|
||||
tSprite.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
tSprite.createSprite ( tft.width() - X_ORIGIN, Y_ORIGIN );
|
||||
|
||||
sSprite.deleteSprite();
|
||||
sSprite.setColorDepth (16); // we don't need 16bit but its faster
|
||||
sSprite.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
sSprite.createSprite ( gridWidth, waterfallHeight ); // Full width
|
||||
sSprite.setScrollRect(0, 0, gridWidth, waterfallHeight, TFT_BLACK);
|
||||
/*
|
||||
* Create and draw the sprite for the gain scale
|
||||
*/
|
||||
CreateGainScale ();
|
||||
CreateGridScale ();
|
||||
|
||||
// Make sure everything will be reset
|
||||
old_settingAttenuate = -1000;
|
||||
@ -65,9 +79,7 @@ void initBandscope()
|
||||
|
||||
tinySA_mode = BANDSCOPE;
|
||||
setting.Mode = tinySA_mode;
|
||||
Serial.println("before reset bandscope stack");
|
||||
ResetBandscopeMenuStack(); // Put menu stack back to root level
|
||||
Serial.println("End of initBandscope");
|
||||
}
|
||||
|
||||
|
||||
@ -75,9 +87,37 @@ void initBandscope()
|
||||
|
||||
/*
|
||||
* This function section handles the fast bandscope sweep
|
||||
* The display is split and shows a waterfall
|
||||
* Number of points is reduced, and frequency change is done using an offset to aallow the delay time between
|
||||
* changing frequency and taking a reading to be reduced
|
||||
* The display is split and shows a waterfall.
|
||||
* The number of points is reduced, and frequency change is done using an offset to allow the
|
||||
* delay time between changing frequency and taking a reading to be reduced.
|
||||
*
|
||||
* Frequency scheme:
|
||||
* When the LO frequency is < 480MHz the LO can be adjusted +- 80kHz from the
|
||||
* nominal frequency in 156.25Hz steps, ie +- 512 steps.
|
||||
* Actually this is not possible! +-511 steps is
|
||||
*
|
||||
*
|
||||
* If the LO is above 480MHz the the adjustment is +-160kHz in 312.5Hz steps.
|
||||
* If the IF is 434MHz then 480MHz -> 46Mhz for the signal being analysed, so fine
|
||||
* for most of the HF bands.
|
||||
*
|
||||
* In bandscope mode the RBW is fixed at the minimum 2.6kHz, span at 200kHz and
|
||||
* there are 80 data points
|
||||
*
|
||||
* 200kHz -> 2.5kHz steps between each reading or 16 * 156.25Hz if in low band
|
||||
*
|
||||
* Start by setting the LO to the frequency for the start of the sweep plus 80kHz
|
||||
* and set the offset value at -80kHz.
|
||||
* At each reading increment the offset value by 16 (8 in high band).
|
||||
* In this mode the delay time between reading is set at a shorter value than
|
||||
* normally used by the RBW as the LO does not turn off at each change in offset, unlike
|
||||
* a normal frequency change.
|
||||
* When the offset value reaches +80kHz then we need to reset the LO (using normal delaytime)
|
||||
* and continue until we get to the end of the sweep.
|
||||
*
|
||||
* Due to the limitation of not being able to do +-512, or +-16 stesp, we will use +-31 steps per frequency
|
||||
* jump instead
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@ -87,12 +127,10 @@ void doBandscope()
|
||||
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 setFreqMicros;
|
||||
static unsigned long nowMicros;
|
||||
static unsigned long bandscopeDelay;
|
||||
|
||||
static uint32_t sweepStep; // Step count
|
||||
static uint32_t sweepFreqStep;
|
||||
|
||||
static int16_t pointMinGain; // to record minimum gain for the current display point
|
||||
static int16_t pointMaxRSSI; // to record max RSSI of the samples in the current display point
|
||||
@ -100,14 +138,7 @@ static uint32_t pointMaxFreq; // record frequency where maximum occurred
|
||||
|
||||
static int16_t lastMode; // Record last operating mode (sig gen, normal)
|
||||
|
||||
static uint16_t currentPointRSSI;
|
||||
static uint16_t peakRSSI;
|
||||
static uint16_t prevPointRSSI;
|
||||
static uint32_t peakFreq;
|
||||
static uint16_t peakIndex;
|
||||
static uint16_t pointsPastPeak;
|
||||
static uint16_t pointsPastDip;
|
||||
static uint16_t minRSSI; // Minimum level for the sweep
|
||||
static uint16_t minRSSI = 255; // Minimum level for the sweep
|
||||
static uint16_t lastMinRSSI; // Minimum level for the previous sweep
|
||||
|
||||
static bool resetAverage; // Flag to indicate a setting has changed and average valuesneeds to be reset
|
||||
@ -134,20 +165,17 @@ static uint16_t chunkIndex;
|
||||
{
|
||||
if ( initSweep || changedSetting ) // Something has changed, or a first start, so need to owrk out some basic things
|
||||
{
|
||||
Serial.println("InitBandscope or changedSetting");
|
||||
sweepPoints = setting.BandscopePoints;
|
||||
autoSweepFreqStep = ( setting.BandscopeSpan ) / sweepPoints;
|
||||
offsetFreqIncrement = autoSweepFreqStep; // 2500 Hz for 200kHz span, 80 points per sweep
|
||||
|
||||
vbw = autoSweepFreqStep / 1000.0; // Set the video resolution
|
||||
ownrbw = 2.6; // and fix the resolution bandwidth to 2.6kHz
|
||||
|
||||
bandwidth = rcvr.SetRBW ( ownrbw * 10.0, &delaytime ); // Set it in the receiver Si4432
|
||||
bandwidth = rcvr.SetRBW ( setting.BandscopeRBW10, &delaytime ); // Set it in the receiver Si4432
|
||||
|
||||
//Serial.printf("set rcvr Freq get:%u, tempIF:%u\n", rcvr.GetFrequency(), tempIF);
|
||||
rcvr.SetFrequency ( setting.IF_Freq ); // Set the RX Si4432 to the IF frequency
|
||||
|
||||
|
||||
sweepFreqStep = autoSweepFreqStep; // Step for each reading
|
||||
// sweepFreqStep = autoSweepFreqStep; // Step for each reading
|
||||
|
||||
if ( setting.Attenuate != old_settingAttenuate )
|
||||
{
|
||||
@ -158,6 +186,9 @@ static uint16_t chunkIndex;
|
||||
|
||||
resetAverage = changedSetting;
|
||||
|
||||
maxGrid = setting.BandscopeMaxGrid;
|
||||
minGrid = setting.BandscopeMinGrid;
|
||||
|
||||
|
||||
#ifdef USE_WIFI
|
||||
// Vary number of points to send in each chunk depending on delaytime
|
||||
@ -167,28 +198,34 @@ static uint16_t chunkIndex;
|
||||
wiFiPoints = MAX_WIFI_POINTS;
|
||||
if (wiFiPoints > setting.BandscopePoints)
|
||||
wiFiPoints = setting.BandscopePoints;
|
||||
Serial.printf("No of wifiPoints set to %i\n", wiFiPoints);
|
||||
// Serial.printf("No of wifiPoints set to %i\n", wiFiPoints);
|
||||
|
||||
if ( numberOfWebsocketClients > 0 )
|
||||
pushBandscopeSettings ();
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
|
||||
|
||||
} // initSweep || changedSetting
|
||||
|
||||
autoSweepStep = 0; // Set the step counter to zero
|
||||
autoSweepFreq = setting.BandscopeStart; // Set the start frequency.
|
||||
|
||||
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
|
||||
|
||||
|
||||
while (( micros() - setFreqMicros ) < delaytime ) // Make sure enough time has elasped since previous frequency write
|
||||
{
|
||||
}
|
||||
|
||||
resetOffsets();
|
||||
|
||||
// set the offset value in the SI4432
|
||||
xmit.SetOffset(offsetValue);
|
||||
|
||||
setFreqMicros = micros(); // Store the time the frequency was changed
|
||||
xmit.SetFrequency ( setting.IF_Freq + autoSweepFreq ); // set the LO frequency, tempIF is offset if spur reduction on
|
||||
|
||||
// set the LO frequency (offsetFreq is -ve at start!)
|
||||
uint32_t xmitFreq = setting.IF_Freq + autoSweepFreq - offsetFreq;
|
||||
// Serial.printf("XmitFreq %i\n", xmitFreq);
|
||||
xmit.SetFrequency ( xmitFreq );
|
||||
// delay will vary depending on whether or not the nominal frequency is changed
|
||||
bandscopeDelay = delaytime; // long delay
|
||||
|
||||
|
||||
#ifdef USE_WIFI
|
||||
@ -212,49 +249,16 @@ static uint16_t chunkIndex;
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
sweepStep = 0;
|
||||
// sweepStep = 0;
|
||||
startFreq = setting.BandscopeStart + setting.IF_Freq; // Start freq for the LO
|
||||
stopFreq = setting.BandscopeSpan + startFreq; // Stop freq for the LO
|
||||
|
||||
Serial.printf(" start %i; stop %i; points %i \n", startFreq, stopFreq, sweepPoints );
|
||||
// Serial.printf(" start %i; stop %i; points %i \n", startFreq, stopFreq, sweepPoints );
|
||||
|
||||
if ( setActualPowerRequested )
|
||||
{
|
||||
SetPowerLevel ( actualPower );
|
||||
setActualPowerRequested = false;
|
||||
|
||||
// Serial.printf ( "Setting actual Power %f \n", actualPower );
|
||||
}
|
||||
|
||||
pointMinGain = 100; // Reset min/max values
|
||||
pointMaxRSSI = 0;
|
||||
|
||||
|
||||
/*
|
||||
* 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++ )
|
||||
{
|
||||
oldPeaks[i].Level = peaks[i].Level;
|
||||
oldPeaks[i].Index = peaks[i].Index;
|
||||
oldPeaks[i].Freq = peaks[i].Freq;
|
||||
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
|
||||
minRSSI = 255; // real value should always be less
|
||||
|
||||
|
||||
|
||||
pointsPastPeak = 0; // Avoid possible peak detection at start of sweep
|
||||
peakRSSI = 0;
|
||||
DisplayBandscopeInfo (); // Display axis and other info
|
||||
|
||||
sweepStartDone = true; // Make sure this initialize is only done once per sweep
|
||||
initSweep = false;
|
||||
@ -282,20 +286,17 @@ static uint16_t chunkIndex;
|
||||
*/
|
||||
nowMicros = micros();
|
||||
|
||||
while (( nowMicros - setFreqMicros ) < delaytime )
|
||||
while (( nowMicros - setFreqMicros ) < bandscopeDelay )
|
||||
{
|
||||
|
||||
if ( ( nowMicros - setFreqMicros + delaytime > 200 ) &&
|
||||
( (nowMicros - lastWebsocketMicros > websocketInterval) || (numberOfWebsocketClients > 0) ) )
|
||||
{
|
||||
// Serial.print("W");
|
||||
webSocket.loop (); // Check websockets - includes Yield() to allow other events to run
|
||||
// Serial.println("w");
|
||||
webSocket.loop (); // Check websockets - includes Yield() to allow other tasks to run
|
||||
lastWebsocketMicros = nowMicros;
|
||||
}
|
||||
if ( nowMicros - setFreqMicros > 100 ) // Wait some time to allow DMA sprite write to finish!
|
||||
UiProcessTouch (); // Check the touch screen
|
||||
// Serial.println("w");
|
||||
nowMicros = micros();
|
||||
}
|
||||
|
||||
@ -311,29 +312,44 @@ static uint16_t chunkIndex;
|
||||
* The second one produces a listing more fit for human consumption!
|
||||
*/
|
||||
|
||||
// if ( showRSSI ) // Displaying RSSI?
|
||||
// {
|
||||
if ( showRSSI ) // Displaying RSSI?
|
||||
{
|
||||
// Serial.printf ( "%s\t%03d\n",
|
||||
// FormatFrequency ( autoSweepFreq) , rxRSSI ); // Send it to the serial output
|
||||
Serial.printf ( "Freq: %s - RSSI: %03d\n",
|
||||
FormatFrequency ( autoSweepFreq) , rxRSSI ); // Send it to the serial output
|
||||
// }
|
||||
}
|
||||
|
||||
if ( (numberOfWebsocketClients > 0) || (setting.ShowGain) )
|
||||
gainReading = GetPreampGain ( &AGC_On, &AGC_Reg ); // Record the preamp/lna gains
|
||||
|
||||
autoSweepFreq += sweepFreqStep; // Increment the frequency
|
||||
sweepStep++; // and increment the step count
|
||||
autoSweepFreq += autoSweepFreqStep; // Increment the frequency
|
||||
autoSweepStep++; // and increment the step count
|
||||
|
||||
offsetFreq += offsetFreqIncrement;
|
||||
offsetValue += offsetIncrement;
|
||||
|
||||
/*
|
||||
* Change the transmitter frequency for the next reading and record the time for
|
||||
* Change the local oscillator frequency for the next reading and record the time for
|
||||
* the RBW required settling delay.
|
||||
*/
|
||||
uint32_t f = setting.IF_Freq + autoSweepFreq;
|
||||
|
||||
setFreqMicros = micros(); // Store the time the LO frequency was changed
|
||||
xmit.SetFrequency ( f ); // Set the new LO frequency as soon as RSSI read
|
||||
|
||||
if (offsetValue >= 512) // reached offset limits
|
||||
{
|
||||
resetOffsets();
|
||||
xmit.SetOffset(offsetValue);
|
||||
uint32_t f = setting.IF_Freq + autoSweepFreq - offsetFreq;
|
||||
// Serial.printf("Sweep setFreq %i\n", f);
|
||||
xmit.SetFrequency ( f ); // Set the new LO frequency as soon as RSSI read
|
||||
bandscopeDelay = delaytime;
|
||||
}
|
||||
else
|
||||
{
|
||||
xmit.SetOffset(offsetValue);
|
||||
bandscopeDelay = offsetDelayTime;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_WIFI
|
||||
@ -376,7 +392,7 @@ static uint16_t chunkIndex;
|
||||
chunkIndex = 0;
|
||||
jsonDocument.clear();
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = sweepStep;
|
||||
jsonDocument["StartIndex"] = autoSweepStep;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
Points = jsonDocument.createNestedArray ("Points" ); // Add Points array
|
||||
@ -386,164 +402,110 @@ static uint16_t chunkIndex;
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
myActual[autoSweepStep] = rxRSSI;
|
||||
if (rxRSSI < minRSSI) // Detect minimum for sweep
|
||||
minRSSI = rxRSSI;
|
||||
|
||||
myGain[autoSweepStep] = gainReading;
|
||||
|
||||
DrawCheckerBoard ( oldSweepStep ); // Draw the grid for the point in the sweep we have just read
|
||||
uint16_t pixelsPerPoint = SCREEN_WIDTH / displayPoints;
|
||||
for (uint16_t i = 0; i< pixelsPerPoint; i++) {
|
||||
|
||||
uint16_t tmp = oldSweepStep * pixelsPerPoint + i;
|
||||
|
||||
myActual[tmp] = rxRSSI;
|
||||
|
||||
myGain[tmp] = gainReading;
|
||||
|
||||
DrawCheckerBoard ( tmp ); // Draw the grid
|
||||
|
||||
if ( resetAverage || setting.Average == AV_OFF ) // Store data, either as read or as rolling average
|
||||
myData[oldSweepStep] = myActual[oldSweepStep];
|
||||
|
||||
myData[tmp] = myActual[oldSweepStep];
|
||||
else
|
||||
{
|
||||
switch ( setting.Average )
|
||||
{
|
||||
case AV_MIN:
|
||||
if ( myData[oldSweepStep] > myActual[oldSweepStep] )
|
||||
myData[oldSweepStep] = myActual[oldSweepStep];
|
||||
if ( myData[tmp] > myActual[oldSweepStep] )
|
||||
myData[tmp] = myActual[oldSweepStep];
|
||||
break;
|
||||
|
||||
|
||||
case AV_MAX:
|
||||
if ( myData[oldSweepStep] < myActual[oldSweepStep] )
|
||||
myData[oldSweepStep] = myActual[oldSweepStep];
|
||||
if ( myData[tmp] < myActual[oldSweepStep] )
|
||||
myData[tmp] = myActual[oldSweepStep];
|
||||
break;
|
||||
|
||||
|
||||
case AV_2:
|
||||
myData[oldSweepStep] = ( myData[oldSweepStep] + myActual[oldSweepStep] ) / 2;
|
||||
myData[tmp] = ( myData[tmp] + myActual[oldSweepStep] ) / 2;
|
||||
break;
|
||||
|
||||
|
||||
case AV_4:
|
||||
myData[oldSweepStep] = ( myData[oldSweepStep]*3 + myActual[oldSweepStep] ) / 4;
|
||||
myData[tmp] = ( myData[tmp]*3 + myActual[oldSweepStep] ) / 4;
|
||||
break;
|
||||
|
||||
|
||||
case AV_8:
|
||||
myData[oldSweepStep] = ( myData[oldSweepStep]*7 + myActual[oldSweepStep] ) / 8;
|
||||
myData[tmp] = ( myData[tmp]*7 + myActual[oldSweepStep] ) / 8;
|
||||
break;
|
||||
}
|
||||
DisplayPoint ( myData, oldSweepStep, AVG_COLOR );
|
||||
DisplayPoint ( myData, tmp, AVG_COLOR );
|
||||
}
|
||||
|
||||
|
||||
if ( setting.ShowSweep )
|
||||
DisplayPoint ( myActual, oldSweepStep, DB_COLOR );
|
||||
|
||||
DisplayPoint ( myActual, tmp, DB_COLOR );
|
||||
|
||||
if ( setting.ShowGain )
|
||||
displayGainPoint ( myGain, oldSweepStep, GAIN_COLOR );
|
||||
|
||||
displayGainPoint ( myGain, tmp, GAIN_COLOR );
|
||||
|
||||
if ( setting.ShowStorage )
|
||||
DisplayPoint ( myStorage, oldSweepStep, STORAGE_COLOR );
|
||||
|
||||
if ( setting.SubtractStorage )
|
||||
rxRSSI = 128 + rxRSSI - myStorage[oldSweepStep];
|
||||
|
||||
|
||||
/*
|
||||
* Record the peak values but not if freq low enough to detect the LO
|
||||
*/
|
||||
|
||||
if ( peakLevel < myData[oldSweepStep] )
|
||||
DisplayPoint ( myStorage, tmp, STORAGE_COLOR );
|
||||
|
||||
// If in the first few points show the scale
|
||||
if ( ( tmp < 4 * CHAR_WIDTH ) && (tmp > 0) )
|
||||
{
|
||||
peakIndex = oldSweepStep;
|
||||
peakLevel = myData[oldSweepStep];
|
||||
peakFreq = oldSweepFreq;
|
||||
|
||||
// Serial.printf( "peakLevel set %i, index %i\n", peakLevel, oldSweepStep);
|
||||
// displayPeakData ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save values used by peak detection. Need to save the previous value as we only
|
||||
* know we have a peak once past it!
|
||||
*/
|
||||
|
||||
prevPointRSSI = currentPointRSSI;
|
||||
currentPointRSSI = myData[oldSweepStep];
|
||||
|
||||
|
||||
/*
|
||||
* Peak point detection. Four peaks, used to position the markers
|
||||
*/
|
||||
if ( currentPointRSSI >= prevPointRSSI ) // Level or ascending
|
||||
{
|
||||
pointsPastDip ++;
|
||||
if ( pointsPastDip == PAST_PEAK_LIMIT )
|
||||
{
|
||||
pointsPastPeak = 0;
|
||||
}
|
||||
|
||||
if ( currentPointRSSI > peakRSSI )
|
||||
{
|
||||
peakRSSI = currentPointRSSI; // Store values
|
||||
peakFreq = oldSweepFreq;
|
||||
peakIndex = oldSweepStep;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
pointsPastPeak ++; // only a true peak if value decreased for a number of consecutive points
|
||||
|
||||
if ( pointsPastPeak == PAST_PEAK_LIMIT ) // We have a peak
|
||||
{
|
||||
pointsPastDip = 0;
|
||||
|
||||
/*
|
||||
* Is this peak bigger than previous ones? Only check if bigger than smallest peak so far
|
||||
*/
|
||||
|
||||
if ( peakRSSI > peaks[MARKER_COUNT-1].Level )
|
||||
{
|
||||
for ( uint16_t p = 0; p < MARKER_COUNT; p++ )
|
||||
{
|
||||
if ( peakRSSI > peaks[p].Level )
|
||||
{
|
||||
for ( uint16_t n = 3; n > p; n-- ) // Shuffle lower level peaks down
|
||||
memcpy ( &peaks[n], &peaks[n-1], sizeof ( peak_t ));
|
||||
|
||||
peaks[p].Level = peakRSSI; // Save the peak values
|
||||
peaks[p].Freq = peakFreq;
|
||||
peaks[p].Index = peakIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peakRSSI = 0; // Reset peak values ready for next peak
|
||||
} // We have a peak
|
||||
} // Descending
|
||||
|
||||
|
||||
/*
|
||||
* Draw the markers if main sweep is displayed. The markers know if they are enabled or not
|
||||
* Only paint if sweep step is in range where there will be a marker
|
||||
*/
|
||||
|
||||
if ( setting.ShowSweep || setting.Average != AV_OFF )
|
||||
{
|
||||
for ( int p = 0; p < MARKER_COUNT; p++ )
|
||||
if (( abs ( oldSweepStep - oldPeaks[p].Index )
|
||||
<= MARKER_SPRITE_HEIGHT / 2 ) && ( oldPeaks[p].Level > (lastMinRSSI + MARKER_NOISE_LIMIT) ))
|
||||
|
||||
marker[p].Paint ( &img, oldPeaks[p].Index - oldSweepStep,
|
||||
rssiToImgY ( oldPeaks[p].Level ) );
|
||||
}
|
||||
|
||||
// If in the last few points and gain trace is displayed show the gain scale
|
||||
if ( setting.ShowGain && (oldSweepStep > setting.BandscopePoints - 2 * CHAR_WIDTH) )
|
||||
{
|
||||
int16_t scaleX = setting.BandscopePoints - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
int16_t scaleX = -tmp + 1; // relative to the img sprite
|
||||
img.setPivot( scaleX, 0);
|
||||
gainScaleSprite.pushRotated ( &img, 0, TFT_BLACK ); // Send the sprite to the target sprite, with transparent colour
|
||||
}
|
||||
|
||||
if ( tmp > 0 ) // Only push if not first point (two pixel wide img)
|
||||
img.pushSprite ( xOrigin + tmp - 1 , yOrigin );
|
||||
|
||||
if ( oldSweepStep > 0 ) // Only push if not first point (two pixel wide img)
|
||||
img.pushSprite ( X_ORIGIN+oldSweepStep-1, Y_ORIGIN );
|
||||
/*
|
||||
* put data into the top row of the waterfall
|
||||
* 16 bit colours have 5 bits for Red, 6 bits for Green, 5 bits for Blue
|
||||
* We will just change the green level here for first test
|
||||
*/
|
||||
uint32_t level = (uint32_t)( (float)(rxRSSI - setting.WaterfallMin) * setting.WaterfallGain) ; // testing colours
|
||||
if (rxRSSI < setting.WaterfallMin)
|
||||
level = 0;
|
||||
uint32_t green = level;
|
||||
uint32_t red = 0;
|
||||
uint32_t blue = 0;
|
||||
if (green > 63)
|
||||
{
|
||||
green = 63;
|
||||
red = level - 63;
|
||||
if ( red > 31 )
|
||||
{
|
||||
red = 31;
|
||||
blue = level - 63 - 31;
|
||||
if ( blue > 31 )
|
||||
blue = 31;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pixelColour = (red << 11) + (green << 5) + blue;
|
||||
|
||||
if (colourTest > 0) // delete at some stage
|
||||
pixelColour = colourTest;
|
||||
|
||||
// Serial.printf("rxRSSI %i; red %i; green %i; blue %i; colour %i \n", rxRSSI, red, green, blue, pixelColour);
|
||||
sSprite.drawPixel ( tmp, 0, pixelColour );
|
||||
|
||||
}
|
||||
|
||||
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for XML file creation
|
||||
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for XML file creation
|
||||
|
||||
|
||||
if ( sweepStep >= sweepPoints ) // If we have got to the end of the sweep
|
||||
if ( autoSweepStep >= sweepPoints ) // If we have got to the end of the sweep
|
||||
{
|
||||
// autoSweepStep = 0;
|
||||
sweepStartDone = false;
|
||||
@ -552,8 +514,6 @@ static uint16_t chunkIndex;
|
||||
if ( sweepCount < 2 )
|
||||
sweepCount++; // Used to disable wifi at start
|
||||
|
||||
oldPeakLevel = peakLevel; //Save value of peak level for use by the "SetPowerLevel" function
|
||||
|
||||
if ( myActual[setting.BandscopePoints-1] == 0 ) // Ensure a value in last data point
|
||||
{
|
||||
myActual[setting.BandscopePoints-1] = rxRSSI; // Yes, save it
|
||||
@ -565,7 +525,6 @@ static uint16_t chunkIndex;
|
||||
showRSSI = 0; // Then turn it off
|
||||
|
||||
#ifdef USE_WIFI
|
||||
|
||||
if (( numberOfWebsocketClients > 0) && jsonDocInitialised && (chunkIndex > 0) )
|
||||
{
|
||||
String wsBuffer;
|
||||
@ -579,8 +538,147 @@ static uint16_t chunkIndex;
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
}
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
} // End of "if ( sweepStep >= sweepPoints )"
|
||||
} // End of "doSweepLow"
|
||||
// scroll the waterfall down one pixel
|
||||
sSprite.scroll( 0, 1 );
|
||||
sSprite.pushSprite( 0, gridHeight + 1 );
|
||||
|
||||
} // End of "if ( autoSweepStep >= sweepPoints )"
|
||||
|
||||
} // End of "doBandscope"
|
||||
|
||||
|
||||
/*
|
||||
* "DisplayBandscopeInfo" - Draws the frequency info below the checkerboard. Called
|
||||
* when a setting is changed to set axis labels
|
||||
*/
|
||||
|
||||
void DisplayBandscopeInfo ()
|
||||
{
|
||||
const char *averageText[] = { " OFF", " MIN", " MAX", " 2", " 4", " 8" };
|
||||
const char *referenceOutText[] = { " 30", " 15", " 10", " 4", " 3", " 2", " 1" };
|
||||
|
||||
double fStart;
|
||||
double fCenter;
|
||||
double fStop;
|
||||
|
||||
// enum { SA_LOW_RANGE, SA_HIGH_RANGE, SIG_GEN_LOW_RANGE, SIG_GEN_HIGH_RANGE, IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR };
|
||||
tSprite.fillSprite ( BLACK );
|
||||
tSprite.setTextColor ( WHITE );
|
||||
|
||||
|
||||
/*
|
||||
* Update frequency labels at bottom if changed
|
||||
*/
|
||||
|
||||
tft.setTextColor ( WHITE,BLACK );
|
||||
tft.setTextSize ( 1 );
|
||||
|
||||
fStart = (double)( setting.BandscopeStart / 1000000.0 ); // Start freq
|
||||
fCenter = (double)( ( setting.BandscopeStart + setting.BandscopeSpan/2.0 ) / 1000000.0 );
|
||||
fStop = (double)( (setting.BandscopeStart + setting.BandscopeSpan ) / 1000000.0 ) ; // Stop freq
|
||||
|
||||
if ( old_startFreq != fStart || old_stopFreq != fStop )
|
||||
{
|
||||
// Serial.printf("DisplayBandscopeInfo fStart %f; old_startFreq %f \n", fStart, old_startFreq);
|
||||
// Serial.printf("DisplayBandscopeInfo fStop %f; old_stopFreq %f \n", fStop, old_stopFreq);
|
||||
|
||||
tft.fillRect ( xOrigin, SCREEN_HEIGHT -
|
||||
CHAR_HEIGHT, SCREEN_WIDTH - xOrigin - 1, SCREEN_HEIGHT - 1, BLACK );
|
||||
|
||||
// Show operating mode
|
||||
tft.setCursor ( xOrigin + 50, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setTextColor ( DB_COLOR );
|
||||
tft.printf ( "Mode:%s", modeText[setting.Mode] );
|
||||
tft.setTextColor ( WHITE );
|
||||
|
||||
tft.setCursor ( xOrigin + 2, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
|
||||
tft.print ( fStart );
|
||||
|
||||
tft.setCursor ( SCREEN_WIDTH - 25, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.print ( fStop );
|
||||
|
||||
|
||||
/*
|
||||
* Show the center frequency:
|
||||
*/
|
||||
tft.setCursor ( SCREEN_WIDTH / 2 - 20 + xOrigin, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.print ( fCenter );
|
||||
tft.print ( "(MHz)" );
|
||||
|
||||
old_startFreq = fStart; // Save current frequency range
|
||||
old_stopFreq = fStop; // For next time
|
||||
}
|
||||
|
||||
tft.setCursor ( 220, SCREEN_HEIGHT - CHAR_HEIGHT ); // Show sweep time
|
||||
tft.printf ( "%6ums", sweepMicros / 1000 );
|
||||
|
||||
|
||||
/*
|
||||
* We use the "tSprite" to paint the data at the top of the screen to avoid
|
||||
* flicker.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Show marker values:
|
||||
*
|
||||
* The "xPos" and "yPos" arrays are the coordinates of where to place the marker data.
|
||||
*
|
||||
* The "posIndex" variable keeps track of the next available position for the marker
|
||||
* data. If we want fixed positions for each marker, then change the "xPos" and "yPos"
|
||||
* indicies to use "m".
|
||||
*/
|
||||
|
||||
int xPos[MARKER_COUNT] = { 20, 20, 160, 160 };
|
||||
int yPos[MARKER_COUNT] = { 0, CHAR_HEIGHT, 0, CHAR_HEIGHT };
|
||||
int posIndex = 0;
|
||||
|
||||
for ( int m = 0; m < MARKER_COUNT; m++ )
|
||||
{
|
||||
tSprite.setCursor ( xPos[m], yPos[m] );
|
||||
if (( marker[m].isEnabled()) && ( setting.ShowSweep || setting.Average != AV_OFF ))
|
||||
{
|
||||
tSprite.setTextColor ( WHITE );
|
||||
tSprite.printf ( "%u:%5.1fdBm %8.4fMHz", marker[m].Index()+1,
|
||||
rssiTodBm ( oldPeaks[m].Level ), oldPeaks[m].Freq / 1000000.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tSprite.setTextColor ( DARKGREY );
|
||||
tSprite.printf ( "%u:", marker[m].Index()+1 );
|
||||
}
|
||||
posIndex++;
|
||||
}
|
||||
|
||||
int x = tSprite.width () - 45;
|
||||
tSprite.setTextColor ( WHITE );
|
||||
|
||||
tSprite.pushSprite ( xOrigin, 0 ); // Write sprite to the display
|
||||
|
||||
updateSidebar = false;
|
||||
} // End of "DisplayBandscopeInfo"
|
||||
|
||||
|
||||
void resetOffsets ()
|
||||
{
|
||||
if (setting.BandscopeStart < 480000000) // low range. Assume never change range mid sweep!
|
||||
{
|
||||
offsetStep = -31;
|
||||
offsetIncrement = 16; // 16 * 156.25 = 2500
|
||||
}
|
||||
else // high range
|
||||
{
|
||||
offsetStep = -63;
|
||||
offsetIncrement = 8; // 8 * 312.5 = 2500
|
||||
}
|
||||
|
||||
if (setting.BandscopeSpan == 400000) // wider span, same no of points
|
||||
offsetIncrement = offsetIncrement * 2;
|
||||
|
||||
|
||||
offsetFreq = offsetStep * offsetFreqIncrement;
|
||||
offsetValue = offsetStep * offsetIncrement;
|
||||
}
|
||||
|
37
IFsweep.ino
37
IFsweep.ino
@ -8,6 +8,16 @@
|
||||
*/
|
||||
void initIF_Sweep()
|
||||
{
|
||||
// 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;
|
||||
xDelta = displayPoints / xGrid;
|
||||
|
||||
init_sweep();
|
||||
|
||||
@ -62,10 +72,10 @@ static uint16_t chunkIndex;
|
||||
if ( initSweep || changedSetting ) // Something has changed, or a first start, so need to work out some basic things
|
||||
{
|
||||
Serial.println("Init IFSweep or changedSetting");
|
||||
autoSweepFreqStep = ( stopFreq_IF - startFreq_IF ) / DISPLAY_POINTS;
|
||||
autoSweepFreqStep = ( stopFreq_IF - startFreq_IF ) / displayPoints;
|
||||
|
||||
vbw = autoSweepFreqStep / 1000.0; // Set the video resolution
|
||||
// ownrbw = ((float) ( stopFreq_IF - startFreq_IF )) / DISPLAY_POINTS / 1000.0; // kHz
|
||||
// ownrbw = ((float) ( stopFreq_IF - startFreq_IF )) / displayPoints / 1000.0; // kHz
|
||||
//
|
||||
// if ( ownrbw < 2.6 ) // If it's less than 2.6KHz
|
||||
// ownrbw = 2.6; // set it to 2.6KHz
|
||||
@ -81,7 +91,7 @@ static uint16_t chunkIndex;
|
||||
|
||||
bandwidth = rcvr.SetRBW ( 106.0, &delaytime ); // Set it in the receiver Si4432. delaytime is returned
|
||||
|
||||
sweepPoints = DISPLAY_POINTS; // At least the right number of points for the display
|
||||
sweepPoints = displayPoints; // At least the right number of points for the display
|
||||
|
||||
sweepFreqStep = ( stopFreq_IF - startFreq_IF ) / sweepPoints; // Step for each reading
|
||||
|
||||
@ -89,14 +99,17 @@ static uint16_t chunkIndex;
|
||||
|
||||
xmit.SetPowerReference ( setting.ReferenceOut ); // Set the GPIO reference output
|
||||
|
||||
maxGrid = setting.MaxGrid;
|
||||
minGrid = setting.MinGrid;
|
||||
|
||||
#ifdef 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 > DISPLAY_POINTS*OVERLAP)
|
||||
wiFiPoints = DISPLAY_POINTS*OVERLAP;
|
||||
if (wiFiPoints > displayPoints*OVERLAP)
|
||||
wiFiPoints = displayPoints*OVERLAP;
|
||||
// Serial.printf("No of wifiPoints set to %i\n", wiFiPoints);
|
||||
|
||||
pushIFSweepSettings();
|
||||
@ -445,15 +458,15 @@ static uint16_t chunkIndex;
|
||||
}
|
||||
|
||||
// If in the last few points and gain trace is displayed show the gain scale
|
||||
if ( setting.ShowGain && (oldSweepStep > DISPLAY_POINTS - 2 * CHAR_WIDTH) )
|
||||
if ( setting.ShowGain && (oldSweepStep > displayPoints - 2 * CHAR_WIDTH) )
|
||||
{
|
||||
int16_t scaleX = DISPLAY_POINTS - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
int16_t scaleX = displayPoints - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
img.setPivot( scaleX, 0);
|
||||
gainScaleSprite.pushRotated ( &img, 0, TFT_BLACK ); // Send the sprite to the target sprite, with transparent colour
|
||||
}
|
||||
|
||||
if ( oldSweepStep > 0 ) // Only push if not first point (two pixel wide img)
|
||||
img.pushSprite ( X_ORIGIN+oldSweepStep-1, Y_ORIGIN );
|
||||
img.pushSprite ( xOrigin+oldSweepStep-1, yOrigin );
|
||||
|
||||
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for XML file creation
|
||||
|
||||
@ -469,11 +482,11 @@ static uint16_t chunkIndex;
|
||||
|
||||
oldPeakLevel = peakLevel; //Save value of peak level for use by the "SetPowerLevel" function
|
||||
|
||||
if ( myActual[DISPLAY_POINTS-1] == 0 ) // Ensure a value in last data point
|
||||
if ( myActual[displayPoints-1] == 0 ) // Ensure a value in last data point
|
||||
{
|
||||
myActual[DISPLAY_POINTS-1] = rxRSSI; // Yes, save it
|
||||
myGain[DISPLAY_POINTS-1] = gainReading;
|
||||
myFreq[DISPLAY_POINTS-1] = oldSweepFreq;
|
||||
myActual[displayPoints-1] = rxRSSI; // Yes, save it
|
||||
myGain[displayPoints-1] = gainReading;
|
||||
myFreq[displayPoints-1] = oldSweepFreq;
|
||||
}
|
||||
|
||||
if ( showRSSI == 1 ) // Only show it once?
|
||||
|
509
RXsweep.ino
Normal file
509
RXsweep.ino
Normal file
@ -0,0 +1,509 @@
|
||||
|
||||
/*
|
||||
* RX sweep fixes the LO and sweeps the receiver from a start value to an stop value to
|
||||
* measure the RX FIR bandpass pass filter response. This eleimates any effect from the SAW
|
||||
* and low pass filters before the receiver.
|
||||
* It requires a fixed strength and frequency signal, and this is provided
|
||||
* by setting the reference output to say 15MHz. Avoid 30Mhz due to some stray clock signal
|
||||
* The input should be connected to the reference signal output with an external cable
|
||||
*/
|
||||
void initRX_Sweep()
|
||||
{
|
||||
// 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;
|
||||
xDelta = displayPoints / xGrid;
|
||||
|
||||
init_sweep();
|
||||
SetRXsweepSpan (setting.Bandwidth10 * 1000); // 10 * bandwidth
|
||||
|
||||
tinySA_mode = RX_SWEEP;
|
||||
setting.Mode = tinySA_mode;
|
||||
|
||||
ResetRXsweepMenuStack(); // Put menu stack back to root level
|
||||
|
||||
}
|
||||
|
||||
|
||||
void doRX_Sweep()
|
||||
{
|
||||
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 setFreqMicros;
|
||||
static unsigned long nowMicros;
|
||||
|
||||
static uint32_t sweepStep; // Step count
|
||||
static uint32_t sweepFreqStep;
|
||||
|
||||
static int16_t pointMinGain; // to record minimum gain for the current display point
|
||||
static int16_t pointMaxRSSI; // to record max RSSI of the samples in the current display point
|
||||
static uint32_t pointMaxFreq; // record frequency where maximum occurred
|
||||
|
||||
static int16_t lastMode; // Record last operating mode (sig gen, normal)
|
||||
|
||||
static uint16_t currentPointRSSI;
|
||||
static uint16_t peakRSSI;
|
||||
static uint16_t prevPointRSSI;
|
||||
static uint32_t peakFreq;
|
||||
static uint16_t peakIndex;
|
||||
static uint16_t pointsPastPeak;
|
||||
static uint16_t pointsPastDip;
|
||||
static uint16_t minRSSI; // Minimum level for the sweep
|
||||
static uint16_t lastMinRSSI; // Minimum level for the previous sweep
|
||||
|
||||
static bool jsonDocInitialised = false;
|
||||
static uint16_t chunkIndex;
|
||||
|
||||
/*
|
||||
* If paused and at the start of a sweep then do nothing
|
||||
*/
|
||||
if (!sweepStartDone && paused)
|
||||
return;
|
||||
|
||||
|
||||
if (( !sweepStartDone || initSweep || changedSetting ) )
|
||||
{
|
||||
if ( initSweep || changedSetting ) // Something has changed, or a first start, so need to work out some basic things
|
||||
{
|
||||
Serial.println("Init RXSweep or changedSetting");
|
||||
autoSweepFreqStep = ( stopFreq_RX - startFreq_RX ) / displayPoints;
|
||||
|
||||
vbw = autoSweepFreqStep / 1000.0; // Set the video resolution
|
||||
|
||||
/*
|
||||
* Use the RBW setting. If zero then it is meaningless, use smallest instead
|
||||
*/
|
||||
bandwidth = rcvr.SetRBW ( setting.Bandwidth10, &delaytime ); // Set it in the receiver Si4432. delaytime is returned
|
||||
|
||||
sweepPoints = displayPoints;
|
||||
|
||||
sweepFreqStep = ( stopFreq_RX - startFreq_RX ) / sweepPoints; // Step for each reading
|
||||
|
||||
att.SetAtten ( 0 ); // Set the internal attenuator
|
||||
|
||||
xmit.SetPowerReference ( setting.ReferenceOut ); // Set the GPIO reference output
|
||||
|
||||
maxGrid = setting.MaxGrid;
|
||||
minGrid = setting.MinGrid;
|
||||
|
||||
#ifdef 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);
|
||||
|
||||
pushIFSweepSettings();
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
|
||||
} // initSweep || changedSetting
|
||||
|
||||
autoSweepStep = 0; // Set the step counter to zero
|
||||
autoSweepFreq = startFreq_RX; // Set the start frequency.
|
||||
|
||||
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
|
||||
|
||||
|
||||
while (( micros() - setFreqMicros ) < delaytime ) // Make sure enough time has elasped since previous frequency write
|
||||
{
|
||||
}
|
||||
|
||||
//Serial.printf("set rcvr Freq get:%u, tempIF:%u\n", rcvr.GetFrequency(), tempIF);
|
||||
rcvr.SetFrequency ( autoSweepFreq ); // Set the RX Si4432 to the start of the sweep
|
||||
|
||||
setFreqMicros = micros(); // Store the time the frequency was changed
|
||||
xmit.SetFrequency ( sigFreq_RX + setting.IF_Freq ); // set the LO frequency to the IF plus reference
|
||||
|
||||
// Serial.printf("autoSweepFreq init: %u\n", autoSweepFreq);
|
||||
|
||||
|
||||
#ifdef USE_WIFI
|
||||
|
||||
if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan
|
||||
{
|
||||
jsonDocument.clear ();
|
||||
chunkIndex = 0;
|
||||
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = 0;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
|
||||
else
|
||||
jsonDocInitialised = false;
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
sweepStep = 0;
|
||||
startFreq = startFreq_RX; // Start freq for the RX
|
||||
stopFreq = stopFreq_RX; // Stop freq for the RX
|
||||
|
||||
pointMinGain = 100; // Reset min/max values
|
||||
pointMaxRSSI = 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
|
||||
|
||||
|
||||
/*
|
||||
* 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++ )
|
||||
{
|
||||
oldPeaks[i].Level = peaks[i].Level;
|
||||
oldPeaks[i].Index = peaks[i].Index;
|
||||
oldPeaks[i].Freq = peaks[i].Freq;
|
||||
peaks[i].Level = 0;
|
||||
}
|
||||
|
||||
pointsPastPeak = 0; // Avoid possible peak detection at start of sweep
|
||||
peakRSSI = 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.
|
||||
*/
|
||||
|
||||
uint16_t oldSweepStep = autoSweepStep;
|
||||
uint32_t oldSweepFreq = autoSweepFreq;
|
||||
|
||||
/*
|
||||
* Wait until time to take the next reading. If a long wait then check the touchscreen
|
||||
* and Websockets while we are waiting to improve response
|
||||
*/
|
||||
nowMicros = micros();
|
||||
|
||||
while (( nowMicros - setFreqMicros ) < delaytime )
|
||||
{
|
||||
|
||||
if ( ( nowMicros - setFreqMicros + delaytime > 200 ) &&
|
||||
( (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;
|
||||
}
|
||||
if ( nowMicros - setFreqMicros > 100 ) // Wait some time to allow DMA sprite write to finish!
|
||||
UiProcessTouch (); // Check the touch screen
|
||||
// Serial.println("w");
|
||||
nowMicros = micros();
|
||||
}
|
||||
|
||||
int rxRSSI = rcvr.GetRSSI (); // Read the RSSI from the RX 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 ( "Freq: %s - RSSI: %03d\n",
|
||||
FormatFrequency ( autoSweepFreq) , rxRSSI ); // Send it to the serial output
|
||||
}
|
||||
|
||||
if ( (numberOfWebsocketClients > 0) || (setting.ShowGain) )
|
||||
gainReading = GetPreampGain ( &AGC_On, &AGC_Reg ); // Record the preamp/lna gains
|
||||
|
||||
autoSweepFreq += sweepFreqStep; // Increment the frequency
|
||||
sweepStep++; // and increment the step count
|
||||
|
||||
// Serial.printf("autoSweepFreq: %u Step: %u\n", autoSweepFreq, sweepStep);
|
||||
|
||||
|
||||
/*
|
||||
* Change the transmitter frequency for the next reading and record the time for
|
||||
* the RBW required settling delay.
|
||||
*
|
||||
* Not we also set the lo here to simulate the effect on the filters in a real sweep
|
||||
*/
|
||||
|
||||
setFreqMicros = micros(); // Store the time the LO frequency was changed
|
||||
xmit.SetFrequency ( sigFreq_RX + setting.IF_Freq ); // set the LO frequency to the IF plus reference
|
||||
rcvr.SetFrequency ( autoSweepFreq ); // Set the RX Si4432 to the IF frequency
|
||||
|
||||
// Serial.printf("Step: %i Required: %i Actual %i\n", sweepStep, autoSweepFreq, rcvr.GetFrequency());
|
||||
|
||||
#ifdef USE_WIFI
|
||||
|
||||
if ( numberOfWebsocketClients > 0 )
|
||||
{
|
||||
if ( jsonDocInitialised )
|
||||
{
|
||||
JsonObject dataPoint = Points.createNestedObject (); // Add an object to the Json array to be pushed to the client
|
||||
dataPoint["x"] = oldSweepFreq/1000000.0; // Set the x(frequency) value
|
||||
dataPoint["y"] = rxRSSI; // Set the y (RSSI) value
|
||||
// Serial.printf ( "Add point chunkIndex %u, sweepStep %u of %u \n", chunkIndex, sweepStep, sweepPoints);
|
||||
chunkIndex++; // increment no of data points in current WiFi chunk
|
||||
|
||||
if ( chunkIndex >= wiFiPoints ) // Send the chunk of data and start new jSon document
|
||||
{
|
||||
String wsBuffer;
|
||||
|
||||
if ( wsBuffer )
|
||||
{
|
||||
// Serial.print("D");
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
// Serial.printf("J%u", wsBuffer.length() );
|
||||
unsigned long s = millis();
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
if (millis() - s > 1000)
|
||||
{
|
||||
Serial.println("webSocketTimeout");
|
||||
Serial.println(wsBuffer);
|
||||
numberOfWebsocketClients = 0;
|
||||
}
|
||||
// Serial.print("j");
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println("No buffer :(");
|
||||
}
|
||||
}
|
||||
if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document
|
||||
{
|
||||
chunkIndex = 0;
|
||||
jsonDocument.clear();
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = sweepStep;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
Points = jsonDocument.createNestedArray ("Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
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
|
||||
|
||||
pointMinGain = 100; // Reset min/max values
|
||||
pointMaxRSSI = 0;
|
||||
|
||||
DrawCheckerBoard ( oldSweepStep ); // Draw the grid for the point in the sweep we have just read
|
||||
|
||||
DisplayPoint ( myActual, oldSweepStep, DB_COLOR );
|
||||
|
||||
if ( setting.ShowGain )
|
||||
displayGainPoint ( myGain, oldSweepStep, GAIN_COLOR );
|
||||
|
||||
/*
|
||||
* Record the peak values
|
||||
*/
|
||||
|
||||
if ( oldSweepStep > 0)
|
||||
{
|
||||
if ( peakLevel < myActual[oldSweepStep] )
|
||||
{
|
||||
peakIndex = oldSweepStep;
|
||||
peakLevel = myActual[oldSweepStep];
|
||||
peakFreq = oldSweepFreq;
|
||||
|
||||
// Serial.printf( "peakLevel set %i, index %i\n", peakLevel, oldSweepStep);
|
||||
// displayPeakData ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save values used by peak detection. Need to save the previous value as we only
|
||||
* know we have a peak once past it!
|
||||
*/
|
||||
|
||||
prevPointRSSI = currentPointRSSI;
|
||||
currentPointRSSI = myActual[oldSweepStep];
|
||||
|
||||
|
||||
/*
|
||||
* Peak point detection. Four peaks, used to position the markers
|
||||
*/
|
||||
if ( currentPointRSSI >= prevPointRSSI ) // Level or ascending
|
||||
{
|
||||
pointsPastDip ++;
|
||||
if ( pointsPastDip == PAST_PEAK_LIMIT )
|
||||
{
|
||||
pointsPastPeak = 0;
|
||||
}
|
||||
|
||||
if ( currentPointRSSI > peakRSSI )
|
||||
{
|
||||
peakRSSI = currentPointRSSI; // Store values
|
||||
peakFreq = oldSweepFreq;
|
||||
peakIndex = oldSweepStep;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
pointsPastPeak ++; // only a true peak if value decreased for a number of consecutive points
|
||||
|
||||
if ( pointsPastPeak == PAST_PEAK_LIMIT ) // We have a peak
|
||||
{
|
||||
pointsPastDip = 0;
|
||||
|
||||
/*
|
||||
* Is this peak bigger than previous ones? Only check if bigger than smallest peak so far
|
||||
*/
|
||||
|
||||
if ( peakRSSI > peaks[MARKER_COUNT-1].Level )
|
||||
{
|
||||
for ( uint16_t p = 0; p < MARKER_COUNT; p++ )
|
||||
{
|
||||
if ( peakRSSI > peaks[p].Level )
|
||||
{
|
||||
for ( uint16_t n = 3; n > p; n-- ) // Shuffle lower level peaks down
|
||||
memcpy ( &peaks[n], &peaks[n-1], sizeof ( peak_t ));
|
||||
|
||||
peaks[p].Level = peakRSSI; // Save the peak values
|
||||
peaks[p].Freq = peakFreq;
|
||||
peaks[p].Index = peakIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peakRSSI = 0; // Reset peak values ready for next peak
|
||||
} // We have a peak
|
||||
} // Descending
|
||||
} // if (( autoSweepFreq > 1000000 ) && (oldSweepStep > 0))
|
||||
|
||||
|
||||
/*
|
||||
* Draw the markers if main sweep is displayed. The markers know if they are enabled or not
|
||||
* Only paint if sweep step is in range where there will be a marker
|
||||
*/
|
||||
|
||||
for ( int p = 0; p < MARKER_COUNT; p++ )
|
||||
{
|
||||
if (( abs ( oldSweepStep - oldPeaks[p].Index )
|
||||
<= MARKER_SPRITE_HEIGHT / 2 ) && ( oldPeaks[p].Level > (lastMinRSSI + MARKER_NOISE_LIMIT) ))
|
||||
|
||||
marker[p].Paint ( &img, oldPeaks[p].Index - oldSweepStep,
|
||||
rssiToImgY ( oldPeaks[p].Level ) );
|
||||
}
|
||||
|
||||
// If in the last few points and gain trace is displayed show the gain scale
|
||||
if ( setting.ShowGain && (oldSweepStep > displayPoints - 2 * CHAR_WIDTH) )
|
||||
{
|
||||
int16_t scaleX = displayPoints - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
img.setPivot( scaleX, 0);
|
||||
gainScaleSprite.pushRotated ( &img, 0, TFT_BLACK ); // Send the sprite to the target sprite, with transparent colour
|
||||
}
|
||||
|
||||
if ( oldSweepStep > 0 ) // Only push if not first point (two pixel wide img)
|
||||
img.pushSprite ( xOrigin+oldSweepStep-1, yOrigin );
|
||||
|
||||
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for XML file creation
|
||||
|
||||
} // End of "if ( autoSweepFreq >= nextPointFreq )"
|
||||
|
||||
if ( sweepStep >= sweepPoints ) // If we have got to the end of the sweep
|
||||
{
|
||||
// autoSweepStep = 0;
|
||||
sweepStartDone = false;
|
||||
|
||||
if ( sweepCount < 2 )
|
||||
sweepCount++; // Used to disable wifi at start
|
||||
|
||||
oldPeakLevel = peakLevel; //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
|
||||
|
||||
#ifdef USE_WIFI
|
||||
|
||||
if (( numberOfWebsocketClients > 0) && jsonDocInitialised && (chunkIndex > 0) )
|
||||
{
|
||||
String wsBuffer;
|
||||
|
||||
if (wsBuffer)
|
||||
{
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
}
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
} // End of "if ( sweepStep >= sweepPoints )"
|
||||
|
||||
|
||||
}
|
@ -17,11 +17,14 @@ void initSigLow()
|
||||
//img.unloadFont(); // Free up memory from any previous incarnation of img
|
||||
img.deleteSprite();
|
||||
img.setColorDepth ( 16 );
|
||||
img.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
img.createSprite ( 320, 55 ); // used for frequency display
|
||||
img.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
img.createSprite ( 320, 55 ); // used for frequency display
|
||||
img.loadFont(SA_FONT_LARGE);
|
||||
|
||||
SetRX ( 1 ); // LO and RX both in receive until turned on by UI
|
||||
|
||||
xmit.SetOffset ( 0 ); // make sure frequency offset registers are zero
|
||||
rcvr.SetOffset ( 0 );
|
||||
|
||||
#ifdef SI_TG_IF_CS
|
||||
if (tgIF_OK) {
|
||||
@ -47,7 +50,7 @@ void initSigLow()
|
||||
setting.Mode = tinySA_mode;
|
||||
|
||||
tft.unloadFont();
|
||||
tft.setCursor ( X_ORIGIN + 50, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setCursor ( xOrigin + 50, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setTextSize(1);
|
||||
tft.setTextColor ( YELLOW );
|
||||
tft.printf ( "Mode:%s", modeText[setting.Mode] );
|
||||
|
69
SweepLo.ino
69
SweepLo.ino
@ -4,6 +4,17 @@
|
||||
*/
|
||||
void initSweepLow()
|
||||
{
|
||||
// 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;
|
||||
xDelta = displayPoints / xGrid;
|
||||
|
||||
init_sweep();
|
||||
|
||||
tinySA_mode = SA_LOW_RANGE;
|
||||
@ -47,6 +58,9 @@ static uint16_t peakRSSI;
|
||||
static uint16_t prevPointRSSI;
|
||||
static uint32_t peakFreq;
|
||||
static uint16_t peakIndex;
|
||||
static uint16_t maxRSSI;
|
||||
static uint32_t maxFreq;
|
||||
static uint16_t maxIndex;
|
||||
static uint16_t pointsPastPeak;
|
||||
static uint16_t pointsPastDip;
|
||||
static uint16_t minRSSI; // Minimum level for the sweep
|
||||
@ -56,6 +70,7 @@ static bool resetAverage; // Flag to indicate a setting has changed and avera
|
||||
|
||||
static bool jsonDocInitialised = false;
|
||||
static uint16_t chunkIndex;
|
||||
static uint32_t offsetIF; // IF frequency offset by half the bandwidth to position in the centre of the filter
|
||||
|
||||
|
||||
|
||||
@ -77,7 +92,7 @@ static uint16_t chunkIndex;
|
||||
if ( initSweep || changedSetting ) // Something has changed, or a first start, so need to owrk out some basic things
|
||||
{
|
||||
//Serial.println("InitSweep or changedSetting");
|
||||
autoSweepFreqStep = ( setting.ScanStop - setting.ScanStart ) / DISPLAY_POINTS;
|
||||
autoSweepFreqStep = ( setting.ScanStop - setting.ScanStart ) / displayPoints;
|
||||
|
||||
vbw = autoSweepFreqStep / 1000.0; // Set the video resolution
|
||||
ownrbw = setting.Bandwidth10 / 10.0; // and the resolution bandwidth
|
||||
@ -97,6 +112,12 @@ static uint16_t chunkIndex;
|
||||
old_ownrbw = ownrbw;
|
||||
}
|
||||
|
||||
/*
|
||||
* The FIR filters in the SI4432 are centred above the nominal IF frequency as that is where the signals are meant to be.
|
||||
* To make sure we are not on the edge of the filters offset the IF frequency down by half the bandwidth
|
||||
*/
|
||||
offsetIF = setting.IF_Freq - setting.Bandwidth10 * 50; // bW10 is in kHz * 10, so * 100-> kHz, halved
|
||||
|
||||
/*
|
||||
* Need multiple readings for each pixel in the display to avoid missing signals.
|
||||
* Work out how many points needed for the whole sweep:
|
||||
@ -104,8 +125,8 @@ static uint16_t chunkIndex;
|
||||
|
||||
sweepPoints = (uint32_t)(( setting.ScanStop - setting.ScanStart ) / bandwidth / 1000.0 * OVERLAP + 0.5); // allow for some overlap (filters will have 3dB roll off at edge) and round up
|
||||
|
||||
if ( sweepPoints < DISPLAY_POINTS )
|
||||
sweepPoints = DISPLAY_POINTS; // At least the right number of points for the display
|
||||
if ( sweepPoints < displayPoints )
|
||||
sweepPoints = displayPoints; // At least the right number of points for the display
|
||||
|
||||
sweepFreqStep = ( setting.ScanStop - setting.ScanStart ) / sweepPoints; // Step for each reading
|
||||
|
||||
@ -120,14 +141,17 @@ static uint16_t chunkIndex;
|
||||
|
||||
xmit.SetPowerReference ( setting.ReferenceOut ); // Set the GPIO reference output if wanted
|
||||
|
||||
maxGrid = setting.MaxGrid;
|
||||
minGrid = setting.MinGrid;
|
||||
|
||||
#ifdef 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 > DISPLAY_POINTS*OVERLAP)
|
||||
wiFiPoints = DISPLAY_POINTS*OVERLAP;
|
||||
if (wiFiPoints > displayPoints*OVERLAP)
|
||||
wiFiPoints = displayPoints*OVERLAP;
|
||||
//Serial.printf("No of wifiPoints set to %i\n", wiFiPoints);
|
||||
|
||||
if ( numberOfWebsocketClients > 0 )
|
||||
@ -169,11 +193,13 @@ static uint16_t chunkIndex;
|
||||
uint32_t IF_Shift = ownrbw * 1000; // bandwidth in Hz
|
||||
if (IF_Shift > MAX_IF_SHIFT)
|
||||
IF_Shift = MAX_IF_SHIFT;
|
||||
tempIF = setting.IF_Freq - IF_Shift;
|
||||
tempIF = offsetIF - IF_Shift;
|
||||
} else {
|
||||
tempIF = setting.IF_Freq;
|
||||
tempIF = offsetIF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
spurToggle = !spurToggle;
|
||||
//Serial.printf("tempIF %u, spurOffset=%i, spur:%i, Toggle:%i\n", tempIF, tempIF - setting.IF_Freq, setting.Spur, spurToggle);
|
||||
|
||||
@ -269,6 +295,7 @@ static uint16_t chunkIndex;
|
||||
|
||||
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;
|
||||
@ -347,7 +374,7 @@ static uint16_t chunkIndex;
|
||||
uint32_t f = tempIF + autoSweepFreq;
|
||||
|
||||
xmit.SetFrequency ( f ); // Set the new LO frequency as soon as RSSI read
|
||||
// Serial.printf("Required: %i Actual %i\n", tempIF+autoSweepFreq, xmit.GetFrequency());
|
||||
// Serial.printf("LO Required: %i Actual %i\n", tempIF+autoSweepFreq, xmit.GetFrequency());
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
if (tgLO_OK && (trackGenSetting.Mode == 1) )
|
||||
@ -496,11 +523,11 @@ static uint16_t chunkIndex;
|
||||
|
||||
if (( autoSweepFreq > MARKER_MIN_FREQUENCY ) && (oldSweepStep > 0))
|
||||
{
|
||||
if ( peakLevel < myData[oldSweepStep] )
|
||||
if ( maxRSSI <= myActual[oldSweepStep] )
|
||||
{
|
||||
peakIndex = oldSweepStep;
|
||||
peakLevel = myData[oldSweepStep];
|
||||
peakFreq = oldSweepFreq;
|
||||
maxIndex = oldSweepStep;
|
||||
maxRSSI = myActual[oldSweepStep];
|
||||
maxFreq = oldSweepFreq;
|
||||
|
||||
// Serial.printf( "peakLevel set %i, index %i\n", peakLevel, oldSweepStep);
|
||||
// displayPeakData ();
|
||||
@ -586,15 +613,15 @@ static uint16_t chunkIndex;
|
||||
}
|
||||
|
||||
// If in the last few points and gain trace is displayed show the gain scale
|
||||
if ( setting.ShowGain && (oldSweepStep > DISPLAY_POINTS - 2 * CHAR_WIDTH) )
|
||||
if ( setting.ShowGain && (oldSweepStep > displayPoints - 2 * CHAR_WIDTH) )
|
||||
{
|
||||
int16_t scaleX = DISPLAY_POINTS - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
int16_t scaleX = displayPoints - 2 * CHAR_WIDTH - oldSweepStep + 1; // relative to the img sprite
|
||||
img.setPivot( scaleX, 0);
|
||||
gainScaleSprite.pushRotated ( &img, 0, TFT_BLACK ); // Send the sprite to the target sprite, with transparent colour
|
||||
}
|
||||
|
||||
if ( oldSweepStep > 0 ) // Only push if not first point (two pixel wide img)
|
||||
img.pushSprite ( X_ORIGIN+oldSweepStep-1, Y_ORIGIN );
|
||||
img.pushSprite ( xOrigin+oldSweepStep-1, yOrigin );
|
||||
|
||||
myFreq[oldSweepStep] = oldSweepFreq; // Store the frequency for XML file creation
|
||||
|
||||
@ -609,13 +636,15 @@ static uint16_t chunkIndex;
|
||||
if ( sweepCount < 2 )
|
||||
sweepCount++; // Used to disable wifi at start
|
||||
|
||||
oldPeakLevel = peakLevel; //Save value of peak level for use by the "SetPowerLevel" function
|
||||
// Serial.printf("MaxRSSI = %i, freq = %i\n", maxRSSI, maxFreq);
|
||||
|
||||
if ( myActual[DISPLAY_POINTS-1] == 0 ) // Ensure a value in last data point
|
||||
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[DISPLAY_POINTS-1] = rxRSSI; // Yes, save it
|
||||
myGain[DISPLAY_POINTS-1] = gainReading;
|
||||
myFreq[DISPLAY_POINTS-1] = oldSweepFreq;
|
||||
myActual[displayPoints-1] = rxRSSI; // Yes, save it
|
||||
myGain[displayPoints-1] = gainReading;
|
||||
myFreq[displayPoints-1] = oldSweepFreq;
|
||||
}
|
||||
|
||||
if ( showRSSI == 1 ) // Only show it once?
|
||||
|
398
cmd.cpp
398
cmd.cpp
@ -17,9 +17,9 @@
|
||||
* here in place of much redundant code in those modules.
|
||||
*/
|
||||
|
||||
#include "Cmd.h" // Our associated header
|
||||
#include "cmd.h" // Our associated header
|
||||
#include "preferences.h" // For "SAVE" & "RECALL"
|
||||
#include "Marker.h" // Marker class definition
|
||||
#include "marker.h" // Marker class definition
|
||||
/*
|
||||
* These are the objects for the PE4302 and Si4432 modules. They are created in the
|
||||
* main program file:
|
||||
@ -47,11 +47,29 @@ extern int changedSetting; // Something in "setting" changed
|
||||
|
||||
extern uint16_t tinySA_mode;
|
||||
|
||||
extern uint8_t myData[DISPLAY_POINTS+1];
|
||||
extern uint8_t myStorage[DISPLAY_POINTS+1];
|
||||
/*
|
||||
* Variables to determine size of grid and waterfall
|
||||
* In Bandscope mode the grid is reduced. In future it may be possible to add
|
||||
* a waterfall to the main sweep, but not yet
|
||||
*/
|
||||
extern uint16_t gridHeight;
|
||||
extern uint16_t gridWidth;
|
||||
extern uint16_t yGrid; // no of grid divisions
|
||||
extern uint16_t yDelta; // no of points/division
|
||||
extern uint16_t xGrid;
|
||||
extern uint16_t xOrigin;
|
||||
extern uint16_t yOrigin;
|
||||
extern uint16_t displayPoints;
|
||||
extern uint16_t xDelta;
|
||||
extern uint16_t waterfallHeight;
|
||||
|
||||
|
||||
extern uint8_t myData[SCREEN_WIDTH+1];
|
||||
extern uint8_t myStorage[SCREEN_WIDTH+1];
|
||||
|
||||
extern float bandwidth; // The current bandwidth (not * 10)
|
||||
extern unsigned long delaytime; // In microseconds
|
||||
extern unsigned long offsetDelayTime; // In microseconds
|
||||
|
||||
extern unsigned long wiFiTargetTime;
|
||||
extern uint16_t wiFiPoints;
|
||||
@ -76,10 +94,15 @@ extern uint32_t startFreq_IF; // Last value of the IF sweep start frequency
|
||||
extern uint32_t stopFreq_IF; // Last value of the IF sweep end frequency
|
||||
extern uint32_t sigFreq_IF; // Last value of the IF sweep end frequency
|
||||
|
||||
extern uint32_t startFreq_RX; // Last value of the IF sweep start frequency
|
||||
extern uint32_t stopFreq_RX; // Last value of the IF sweep end frequency
|
||||
extern uint32_t sigFreq_RX; // Last value of the IF sweep end frequency
|
||||
|
||||
extern uint8_t showRSSI; // When true, RSSI readings are displayed
|
||||
extern int initSweep; // Set by the "RSSI" command to restart the sweep
|
||||
extern bool paused;
|
||||
|
||||
extern uint32_t colourTest;
|
||||
|
||||
extern Marker marker[MARKER_COUNT]; // Array of marker objects
|
||||
|
||||
@ -97,6 +120,9 @@ extern void initSweepLow ();
|
||||
extern void initSigLow ();
|
||||
extern void initIF_Sweep ();
|
||||
extern void setMode (uint16_t newMode);
|
||||
extern uint8_t dBmToRSSI ( double dBm );
|
||||
|
||||
|
||||
/*
|
||||
* The "msgTable" provides a way of translating the ASCII message to the internal
|
||||
* number. Needs to be re-ordered based on expected usage.
|
||||
@ -143,14 +169,20 @@ extern void setMode (uint16_t newMode);
|
||||
{ "SPUR", MSG_SPUR }, // Set Spur reduction on/off
|
||||
{ "WIFITIME", MSG_WIFI_UPDATE }, // Set WiFi Update target time
|
||||
{ "WIFIPTS", MSG_WIFI_POINTS }, // Set WiFi points
|
||||
{ "SKTINT", MSG_WEBSKT_INTERVAL }, // Set WebSocket interval
|
||||
{ "SKTINT", MSG_WEBSKT_INTERVAL }, // Set WebSocket interval
|
||||
{ "SGRXDRIVE", MSG_SG_RX_DRIVE }, // Set Signal Generator RX Drive level
|
||||
{ "SGLODRIVE", MSG_SG_LO_DRIVE }, // Set Signal Generator LO Drive level
|
||||
{ "TGIFDRIVE", MSG_TG_IF_DRIVE }, // Set Track Generator IF Drive level
|
||||
{ "TGLODRIVE", MSG_TG_LO_DRIVE }, // Set Track Generator LO Drive level
|
||||
{ "IFSIGNAL", MSG_IFSIGNAL }, // IF sweep signal frequency
|
||||
{ "TGOFFSET", MSG_TGOFFSET }, // Offset TG IF from SA IF to reduce pass through
|
||||
{ "", MSG_NONE } // Unrecognized command
|
||||
{ "IFSIGNAL", MSG_IFSIGNAL }, // IF sweep signal frequency
|
||||
{ "TGOFFSET", MSG_TGOFFSET }, // Offset TG IF from SA IF to reduce pass through
|
||||
{ "CTEST", MSG_COLOURTEST}, // Work out how colours work!
|
||||
{ "OFFDEL", MSG_OFFDELAY }, // Offset tuning delay
|
||||
{ "WFMIN", MSG_WFMIN }, // Min level for waterfall colours
|
||||
{ "WFGAIN", MSG_WFGAIN }, // Gain for waterfall colours
|
||||
{ "RXSWEEP", MSG_RX_SWEEP }, // Set RX Sweep Mode
|
||||
{ "RXSIGNAL", MSG_RXSIGNAL }, // IF sweep signal frequency
|
||||
{ "", MSG_NONE } // Unrecognized command
|
||||
};
|
||||
|
||||
int msgCount = ELEMENTS ( msgTable);
|
||||
@ -197,6 +229,7 @@ void ShowMenu ()
|
||||
Serial.println ( " SALO..........Set to analyse mode low frequency range" );
|
||||
Serial.println ( " SGLO..........Set to signal generator mode low frequency range" );
|
||||
Serial.println ( " IFSWEEP.......Set to IF Sweep mode to analyse the TinySA SAW filters" );
|
||||
Serial.println ( " RXSWEEP.......Set to RX Sweep mode to analyse the TinySA FIR filters" );
|
||||
Serial.println ( " BANDSCOPE.....Set to BANDSCOPE mode" );
|
||||
|
||||
Serial.println ( " TRACES........Turn display traces on or off ['GAIN' or 'dB']" );
|
||||
@ -208,6 +241,9 @@ void ShowMenu ()
|
||||
|
||||
Serial.printf ( " SCALE.........Set the dB/horizontal line value; currently: %ddB\n", setting.PowerGrid );
|
||||
|
||||
Serial.printf ( " WFMIN.........Set the minimum RSSI level for waterfall colouring: %i\n", setting.WaterfallMin );
|
||||
Serial.printf ( " WFGAIN........Set the gain for waterfall colouring: %d\n", setting.WaterfallGain );
|
||||
|
||||
Serial.println ( "\nOther Commands:\n" );
|
||||
|
||||
Serial.print ( " DRIVE.........Local oscillator drive level [0 to 7]; currently: " );
|
||||
@ -240,6 +276,8 @@ void ShowMenu ()
|
||||
|
||||
Serial.printf ( " DELAY.........Timestep in uS, currently: %uuS\n", delaytime );
|
||||
|
||||
Serial.printf ( " OFFDEL........Timestep in uS for Bandscope, currently: %uuS\n", offsetDelayTime );
|
||||
|
||||
Serial.print ( " VFO...........Set or get active VFO [R, ( L or T ), I(tg If), G(tG LO)]; currently: " );
|
||||
|
||||
if ( VFO == RX_4432 )
|
||||
@ -442,6 +480,7 @@ int16_t addr; // Si4432 register address
|
||||
|
||||
int16_t tempValue; // Temporary value of something
|
||||
int32_t tempFreq; // Temporary frequency
|
||||
float tempFloat;
|
||||
|
||||
uint32_t freq1; // Several other temporary frequencies
|
||||
uint32_t freq2; // used in computing the center
|
||||
@ -641,7 +680,7 @@ uint8_t reg69; // Ditto
|
||||
* Unlike the touch-screen equivalent command, here you can set any value you like as opposed
|
||||
* to chosing from a list of standard settings.
|
||||
*
|
||||
* If no number is entered, we report the current setting.
|
||||
* If no number is entered, we report the current setting.
|
||||
*/
|
||||
|
||||
case MSG_SCALE:
|
||||
@ -926,6 +965,20 @@ uint8_t reg69; // Ditto
|
||||
Serial.printf ( "Time per scan step = %uuS\n", delaytime );
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The "OFFDEL" command sets the timestep in uS for tuning using offsets.
|
||||
*/
|
||||
|
||||
case MSG_OFFDELAY: // Set the timestep in uS, currently 2000
|
||||
if ( dataLen != 0 ) // Anything entered?
|
||||
{
|
||||
offsetDelayTime = atol ( dataBuff ); // Yes, set new delay time
|
||||
DisplayInfo ();
|
||||
}
|
||||
|
||||
Serial.printf ( "Offset delay time per bandscope step = %uuS\n", offsetDelayTime );
|
||||
return true;
|
||||
|
||||
|
||||
/*
|
||||
* The "VFO" command sets the active VFO
|
||||
@ -1270,6 +1323,9 @@ uint8_t reg69; // Ditto
|
||||
* The "TUNE" comand allows the use to specify the crystal load capacitance for the
|
||||
* selected VFO. This teaks the frequency. See A440 and the TinySA documentation for
|
||||
* info on how it really works.
|
||||
*
|
||||
* We need to force the SI4432 to recalibrate the PLL after each tune by putting it into READY mode
|
||||
*
|
||||
*/
|
||||
|
||||
case MSG_TUNE:
|
||||
@ -1453,7 +1509,7 @@ uint8_t reg69; // Ditto
|
||||
{
|
||||
tempValue = atoi ( dataBuff ); // Yes, get new value
|
||||
// check valid
|
||||
if ( (tempValue > 10) && (tempValue < DISPLAY_POINTS * OVERLAP) )
|
||||
if ( (tempValue > 10) && (tempValue < displayPoints * OVERLAP) )
|
||||
{
|
||||
wiFiPoints = tempValue;
|
||||
Serial.printf ( "Chunk size set to: %u\n", tempValue );
|
||||
@ -1461,7 +1517,7 @@ uint8_t reg69; // Ditto
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Invalid - must be between 10 and %u\n", DISPLAY_POINTS * OVERLAP);
|
||||
Serial.printf("Invalid - must be between 10 and %u\n", displayPoints * OVERLAP);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1505,6 +1561,10 @@ uint8_t reg69; // Ditto
|
||||
setMode(IF_SWEEP);
|
||||
return true;
|
||||
|
||||
case MSG_RX_SWEEP:
|
||||
setMode(RX_SWEEP);
|
||||
return true;
|
||||
|
||||
case MSG_TGOFFSET:
|
||||
if ( dataLen != 0 ) // Frequency specified?
|
||||
{
|
||||
@ -1526,7 +1586,7 @@ uint8_t reg69; // Ditto
|
||||
freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency
|
||||
SetIFsweepSigFreq (freq1);
|
||||
}
|
||||
Serial.printf ( "If Signal frequency: %s\n", FormatFrequency ( GetIFsweepSigFreq() ));
|
||||
Serial.printf ( "IF Sweep Signal frequency: %s\n", FormatFrequency ( GetIFsweepSigFreq() ));
|
||||
return true;
|
||||
|
||||
|
||||
@ -1557,6 +1617,70 @@ uint8_t reg69; // Ditto
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
case MSG_COLOURTEST:
|
||||
if ( dataLen != 0 ) // Anything entered?
|
||||
{
|
||||
tempValue = atoi ( dataBuff ); // Yes, get new value
|
||||
if ( ( tempValue >= 0 ) && (tempValue <= 65535) )
|
||||
{
|
||||
colourTest = tempValue;
|
||||
return true;
|
||||
}
|
||||
else // Nothing specified
|
||||
{
|
||||
Serial.println ( "Invalid Colour" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "WFMIN" command sets the min RSSI level for waterfall colouring.
|
||||
* The value is entered in dBm so the value can be judged from the waterfall
|
||||
*
|
||||
* If no number is entered, we report the current setting.
|
||||
*/
|
||||
case MSG_WFMIN:
|
||||
if ( dataLen != 0 ) // Value specified?
|
||||
{
|
||||
tempValue = atoi ( dataBuff ); // Yes, get grid reference value
|
||||
SetWFMin ( tempValue ); // Set it
|
||||
DisplayInfo (); // Re display the scan
|
||||
}
|
||||
|
||||
Serial.printf ( "Waterfall Minimum RSSI value: %i\n", setting.WaterfallMin );
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The "WFGAIN" command sets the min RSSI level for waterfall colouring.
|
||||
*
|
||||
* If no number is entered, we report the current setting.
|
||||
*/
|
||||
case MSG_WFGAIN:
|
||||
if ( dataLen != 0 ) // Value specified?
|
||||
{
|
||||
tempFloat = atof ( dataBuff ); // Yes, get grid reference value
|
||||
SetWFGain ( tempFloat ); // Set it
|
||||
Serial.printf("tempFloat = %4.2f\n", tempFloat);
|
||||
DisplayInfo (); // Re display the scan
|
||||
}
|
||||
|
||||
Serial.printf ( "Waterfall colour gain: %4.2f\n", setting.WaterfallGain );
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Set signal frequency fro RX Sweep
|
||||
*/
|
||||
case MSG_RXSIGNAL:
|
||||
if ( dataLen != 0 ) // Frequency specified?
|
||||
{
|
||||
freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency
|
||||
SetRXsweepSigFreq (freq1);
|
||||
}
|
||||
Serial.printf ( "RX Sweep Signal frequency: %s\n", FormatFrequency ( GetRXsweepSigFreq() ));
|
||||
return true;
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
} // End of "switch"
|
||||
@ -1953,7 +2077,7 @@ int oldMin = setting.MinGrid;
|
||||
int oldMax = setting.MaxGrid;
|
||||
|
||||
setting.MaxGrid = ref;
|
||||
setting.MinGrid = ref - Y_GRID * setting.PowerGrid;
|
||||
setting.MinGrid = ref - yGrid * setting.PowerGrid;
|
||||
|
||||
if (( oldMin != setting.MinGrid ) || ( oldMax != setting.MaxGrid ))
|
||||
{
|
||||
@ -2014,7 +2138,7 @@ void SetPowerGrid ( int g )
|
||||
int oldGrid = setting.PowerGrid;
|
||||
|
||||
setting.PowerGrid = g;
|
||||
setting.MinGrid = setting.MaxGrid - Y_GRID * g;
|
||||
setting.MinGrid = setting.MaxGrid - yGrid * g;
|
||||
|
||||
if ( oldGrid != setting.PowerGrid )
|
||||
{
|
||||
@ -2083,7 +2207,7 @@ int oldAtten = setting.Attenuate;
|
||||
|
||||
void SetStorage ( void )
|
||||
{
|
||||
for ( int i = 0; i < DISPLAY_POINTS; i++ )
|
||||
for ( int i = 0; i < displayPoints; i++ )
|
||||
myStorage[i] = myData[i];
|
||||
|
||||
setting.ShowStorage = true;
|
||||
@ -2179,6 +2303,7 @@ int16_t tempBw;
|
||||
if ( setting.Bandwidth10 != oldRBW )
|
||||
{
|
||||
changedSetting = true;
|
||||
SetRXsweepSpan (setting.Bandwidth10 * 1000); // 10 * bandwidth
|
||||
WriteSettings ();
|
||||
}
|
||||
}
|
||||
@ -2622,6 +2747,189 @@ uint32_t GetIFsweepSigFreq ( void )
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Specific span setting for RX Sweep mode
|
||||
*
|
||||
*
|
||||
* "SetSweepSpan" will maintain the previous center frequency and attempt to simply
|
||||
* change the range of the scan. If the new limits cause the start frequency to go
|
||||
* or the stop frequency to exceed "STOP_MAX", the range will be adjusted to maintain
|
||||
* an equal range on both sides of the center frequency.
|
||||
*/
|
||||
|
||||
void SetRXsweepSpan ( uint32_t spanRange )
|
||||
{
|
||||
uint32_t startFreq; // These are used in computing the
|
||||
uint32_t stopFreq; // Scan limits
|
||||
uint32_t centerFreq; // Current center frequency
|
||||
uint32_t halfSpan; // Half of the frequency span
|
||||
|
||||
uint32_t lastStart; // Old ssweep start frequency
|
||||
uint32_t lastStop; // and old stop frequency
|
||||
|
||||
// Serial.print ( "Requested span = " ); Serial.println ( FormatFrequency ( spanRange ));
|
||||
|
||||
lastStart = startFreq_RX; // Save the current start frequency
|
||||
lastStop = stopFreq_RX; // and the current stop frequency
|
||||
|
||||
halfSpan = spanRange / 2; // Half the requested span
|
||||
centerFreq = setting.IF_Freq; // Always the IF Freq for this mode
|
||||
|
||||
startFreq = centerFreq - halfSpan; // New computed start frequency
|
||||
stopFreq = centerFreq + halfSpan; // New computed stop frequency
|
||||
|
||||
|
||||
/*
|
||||
* Now we have to range check the computed start and stop frequencies and if either
|
||||
* of those is out of bounds, we will adjust the span accordingly. We'll maintain
|
||||
* the previous center frequency though.
|
||||
*/
|
||||
|
||||
if ( stopFreq > RX_STOP_MAX ) // Range check the stop frequency
|
||||
{
|
||||
stopFreq = RX_STOP_MAX; // Set the stop frequency at the upper limit
|
||||
halfSpan = stopFreq - centerFreq; // Re-compute half span
|
||||
startFreq = centerFreq - halfSpan; // and recompute start frequency
|
||||
}
|
||||
|
||||
if ( startFreq < RX_START_MIN ) // Range check the start frequency
|
||||
{
|
||||
startFreq = RX_START_MIN; // Set start at the limit
|
||||
halfSpan = centerFreq - startFreq; // Re-compute half span
|
||||
stopFreq = centerFreq + halfSpan; // and re-compute stop frequency
|
||||
}
|
||||
|
||||
startFreq = centerFreq - halfSpan; // Re-compute start and
|
||||
stopFreq = centerFreq + halfSpan; // stop frequencies
|
||||
|
||||
// Serial.print ( "Computed start = " ); Serial.println ( FormatFrequency ( startFreq ));
|
||||
// Serial.print ( "Computed stop = " ); Serial.println ( FormatFrequency ( stopFreq ));
|
||||
// Serial.print ( "Half span = " ); Serial.println ( FormatFrequency ( halfSpan ));
|
||||
|
||||
startFreq_RX = startFreq; // Set new start frequency
|
||||
stopFreq_RX = stopFreq; // Set new stop frequency
|
||||
|
||||
if (( startFreq_RX != lastStart )
|
||||
|| ( stopFreq_RX != lastStop )) // Did it change
|
||||
{
|
||||
changedSetting = true; // Yes it did
|
||||
RedrawHisto (); // Redraw labels and restart sweep with new settings
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetRXsweepSpan ()
|
||||
{
|
||||
return stopFreq_RX - startFreq_RX;
|
||||
}
|
||||
|
||||
|
||||
void SetRXsweepStart ( uint32_t startFreq )
|
||||
{
|
||||
uint32_t lastStart; // Old sweep start frequency
|
||||
uint32_t lastStop; // and old stop frequency
|
||||
|
||||
// Serial.print ( "Requested start = " ); Serial.println ( FormatFrequency ( startFreq ));
|
||||
|
||||
lastStart = startFreq_RX; // Save the current start frequency
|
||||
lastStop = stopFreq_RX; // and the current stop frequency
|
||||
|
||||
if ( startFreq < RX_START_MIN ) // Range check
|
||||
startFreq = RX_START_MIN;
|
||||
|
||||
if ( startFreq > RX_STOP_MAX ) // Range check
|
||||
startFreq = RX_STOP_MAX;
|
||||
|
||||
if ( startFreq > stopFreq_RX ) // Start can't be more than current stop
|
||||
stopFreq_RX = RX_STOP_MAX; // So set stop at maximum
|
||||
|
||||
startFreq_RX = startFreq; // Set new start frequency
|
||||
|
||||
if (( startFreq_RX != lastStart )
|
||||
|| ( stopFreq_RX != lastStop )) // Did it change?
|
||||
{
|
||||
changedSetting = true; // Yes it did
|
||||
RedrawHisto (); // Redraw labels and restart sweep with new settings
|
||||
// WriteSettings (); // and save the setting structure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetRXsweepStart ( void )
|
||||
{
|
||||
return startFreq_RX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SetRXsweepStop ( uint32_t stopFreq )
|
||||
{
|
||||
uint32_t lastStart; // Old sweep start frequency
|
||||
uint32_t lastStop; // and old stop frequency
|
||||
|
||||
// Serial.print ( "Requested stop = " ); Serial.println ( FormatFrequency ( stopFreq ));
|
||||
|
||||
lastStart = startFreq_RX; // Save the current start frequency
|
||||
lastStop = stopFreq_RX; // and the current stop frequency
|
||||
|
||||
if ( stopFreq < RX_START_MIN ) // Range check
|
||||
stopFreq = RX_START_MIN;
|
||||
|
||||
if ( stopFreq > RX_STOP_MAX ) // Range check
|
||||
stopFreq = RX_STOP_MAX;
|
||||
|
||||
if ( stopFreq < startFreq_RX ) // Stop can't be less than current start
|
||||
startFreq_RX = RX_START_MIN; // so set start to minimum frequency
|
||||
|
||||
stopFreq_RX = stopFreq; // Set new stop frequency
|
||||
|
||||
if (( startFreq_RX != lastStart )
|
||||
|| ( stopFreq_RX != lastStop )) // Did it change?
|
||||
{
|
||||
changedSetting = true; // Yes it did
|
||||
RedrawHisto (); // Redraw labels and restart sweep with new settings
|
||||
// WriteSettings (); // and save the setting structure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetRXsweepStop ( void )
|
||||
{
|
||||
return stopFreq_RX;
|
||||
}
|
||||
|
||||
|
||||
void SetRXsweepSigFreq ( uint32_t sigFreq )
|
||||
{
|
||||
uint32_t lastSigFreq;
|
||||
|
||||
// Serial.print ( "Requested RX sweep signal = " ); Serial.println ( FormatFrequency ( sigFreq_RX ));
|
||||
|
||||
lastSigFreq = sigFreq_RX;
|
||||
|
||||
// check in a sensible range
|
||||
if ( ( sigFreq < 1000000 ) || (sigFreq > 100000000 ) )
|
||||
Serial.println(" Out of range - must be between 1,000,000 and 100,000,000Hz");
|
||||
else
|
||||
{
|
||||
sigFreq_RX = sigFreq;
|
||||
if ( sigFreq_RX != lastSigFreq )
|
||||
changedSetting = true;
|
||||
}
|
||||
|
||||
RedrawHisto (); // Redraw labels and restart sweep with new settings
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetRXsweepSigFreq ( void )
|
||||
{
|
||||
return sigFreq_RX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Specific start/stop frequency setting for Bandscope mode
|
||||
*/
|
||||
@ -2646,8 +2954,29 @@ uint32_t lastStart; // Old sweep start frequency
|
||||
{
|
||||
changedSetting = true; // Yes it did
|
||||
initSweep = true;
|
||||
// RedrawHisto (); // Redraw labels and restart sweep with new settings
|
||||
// WriteSettings (); // and save the setting structure
|
||||
WriteSettings (); // and save the setting structure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "SetRBW" - Sets the resolution bandwidth in the "setting" structure. We don't
|
||||
* bother to actually set it in the receiver Si4432 as that is done at the start
|
||||
* of each scan cycle.
|
||||
*/
|
||||
void SetBandscopeRBW ( int bw )
|
||||
{
|
||||
int16_t oldRBW = setting.BandscopeRBW10;
|
||||
int16_t tempBw = bw;
|
||||
|
||||
setting.BandscopeRBW10 = bw;
|
||||
|
||||
tempBw = rcvr.SetRBW ( bw, &delaytime );
|
||||
|
||||
if ( tempBw != oldRBW )
|
||||
{
|
||||
changedSetting = true;
|
||||
WriteSettings ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2662,7 +2991,6 @@ uint32_t GetBandscopeStart ( void )
|
||||
/*
|
||||
* Specific start/stop frequency setting for Bandscope mode
|
||||
*/
|
||||
|
||||
void SetBandscopeSpan ( uint32_t spanFreq )
|
||||
{
|
||||
uint32_t lastSpan; // Old sweep span
|
||||
@ -2695,6 +3023,25 @@ uint32_t GetBandscopeSpan ( void )
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "SetBandscopeLevel" - Sets the decibel level for the top line of the graph in Bandscope mode.
|
||||
*/
|
||||
|
||||
void SetBandscopeLevel ( int ref )
|
||||
{
|
||||
int oldMin = setting.BandscopeMinGrid;
|
||||
int oldMax = setting.BandscopeMaxGrid;
|
||||
|
||||
setting.BandscopeMaxGrid = ref;
|
||||
setting.BandscopeMinGrid = ref - yGrid * setting.PowerGrid;
|
||||
|
||||
if (( oldMin != setting.BandscopeMinGrid ) || ( oldMax != setting.BandscopeMaxGrid ))
|
||||
{
|
||||
changedSetting = true;
|
||||
WriteSettings ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -2884,3 +3231,18 @@ void SetFreq ( int vfo, uint32_t freq )
|
||||
if ( vfo == TX_4432 ) // Transmitter?
|
||||
xmit.SetFrequency ( freq );
|
||||
}
|
||||
|
||||
void SetWFMin (int16_t level)
|
||||
{
|
||||
if ( (level >=-130) && (level < -50) )
|
||||
setting.WaterfallMin = dBmToRSSI( (double)level );
|
||||
Serial.printf("Watterfall min set to %i \n", setting.WaterfallMin );
|
||||
WriteSettings();
|
||||
}
|
||||
|
||||
void SetWFGain (float gain)
|
||||
{
|
||||
if ((gain > 0.1) && (gain < 3.0))
|
||||
setting.WaterfallGain = gain;
|
||||
WriteSettings();
|
||||
}
|
||||
|
43
cmd.h
43
cmd.h
@ -13,8 +13,8 @@
|
||||
#define _CMD_H_ // Prevent double inclusion
|
||||
|
||||
#include "simpleSA.h" // General program definitions
|
||||
#include "PE4302.h" // Class definition for thePE4302 attenuator
|
||||
#include "Si4432.h" // Class definition for the Si4432 transceiver
|
||||
#include "pE4302.h" // Class definition for thePE4302 attenuator
|
||||
#include "si4432.h" // Class definition for the Si4432 transceiver
|
||||
#include "preferences.h" // For saving the "setting" structure
|
||||
#include <SPI.h>
|
||||
|
||||
@ -72,6 +72,13 @@
|
||||
#define MSG_TGOFFSET 43 // Offset TG IF frequency from SA IF
|
||||
#define MSG_BANDSCOPE 44 // Set Bandscope Mode
|
||||
#define MSG_IFSWEEP 45 // Set IF Sweep Mode
|
||||
#define MSG_OFFDELAY 46 // Adjust offset tuning delay time before taking reading
|
||||
#define MSG_WFMIN 47 // set the min level for the waterfall colours
|
||||
#define MSG_WFGAIN 48 // set the gain for waterfall colouring
|
||||
#define MSG_RX_SWEEP 49 // Set the RX Sweep Mode
|
||||
#define MSG_RXSIGNAL 50 // Set frequency of injected signal for IF Sweep
|
||||
|
||||
#define MSG_COLOURTEST 99 // test of waterfall colours - remove this when done!
|
||||
|
||||
|
||||
typedef struct // Keeps everything together
|
||||
@ -161,24 +168,40 @@ uint8_t GetPreampGain ( bool* agc, uint8_t* reg );
|
||||
void SetSweepStart ( uint32_t freq ); // Added in Version 2.3
|
||||
uint32_t GetSweepStart ( void );
|
||||
|
||||
void SetSweepStop ( uint32_t freq ); // Added in Version 2.3
|
||||
void SetSweepStop ( uint32_t freq ); // Added in Version 2.3
|
||||
uint32_t GetSweepStop ( void );
|
||||
|
||||
void SetIFsweepStart ( uint32_t freq ); // Added in Version 3.0c
|
||||
uint32_t GetIFsweepStart ( void );
|
||||
|
||||
void SetBandscopeStart ( uint32_t freq ); // Added in Version 3.0f
|
||||
uint32_t GetBandscopeStart ( void );
|
||||
|
||||
void SetBandscopeSpan ( uint32_t freq ); // Added in Version 3.0f
|
||||
void SetBandscopeSpan ( uint32_t freq ); // Added in Version 3.0f
|
||||
uint32_t GetBandscopeSpan ( void );
|
||||
|
||||
void SetIFsweepStop ( uint32_t freq ); // Added in Version 3.0c
|
||||
void SetBandscopeRBW ( int v ); // Sets the resolution bandwidth
|
||||
|
||||
void SetBandscopeLevel ( int ref ); // Sets the decibel level for the top line of the graph
|
||||
|
||||
void SetIFsweepStart ( uint32_t freq ); // Added in Version 3.0c
|
||||
uint32_t GetIFsweepStart ( void );
|
||||
|
||||
void SetIFsweepStop ( uint32_t freq ); // Added in Version 3.0c
|
||||
uint32_t GetIFsweepStop ( void );
|
||||
|
||||
void SetIFsweepSigFreq ( uint32_t freq ); // Added in Version 3.0c
|
||||
uint32_t GetIFsweepSigFreq ( void );
|
||||
|
||||
void SetRXsweepStart ( uint32_t freq );
|
||||
uint32_t GetRXsweepStart ( void );
|
||||
|
||||
void SetRXsweepStop ( uint32_t freq );
|
||||
uint32_t GetRXsweepStop ( void );
|
||||
|
||||
void SetRXsweepSpan ( uint32_t freq );
|
||||
uint32_t GetRXsweepSpan ( void );
|
||||
|
||||
void SetRXsweepSigFreq ( uint32_t freq );
|
||||
uint32_t GetRXsweepSigFreq ( void );
|
||||
|
||||
void SetSweepCenter ( uint32_t freq, uint8_t span );
|
||||
uint32_t GetSweepCenter ( void );
|
||||
|
||||
@ -189,4 +212,8 @@ void SetFreq ( int vfo, uint32_t freq );
|
||||
|
||||
bool UpdateMarker ( uint8_t mkr, char action );
|
||||
|
||||
void SetWFMin (int16_t level);
|
||||
void SetWFGain (float gain);
|
||||
|
||||
|
||||
#endif // End of "Cmd.h"
|
||||
|
@ -2,7 +2,7 @@
|
||||
* "Marker.cpp" Contains the code for the "Marker" class functions
|
||||
*/
|
||||
|
||||
#include "Marker.h" // Class definition
|
||||
#include "marker.h" // Class definition
|
||||
|
||||
/*
|
||||
* There are two constructors; the first simply creates an uninitialized
|
||||
|
2
menu.cpp
2
menu.cpp
@ -2,7 +2,7 @@
|
||||
* "Menu.cpp" implements the "Menuitem" class.
|
||||
*/
|
||||
|
||||
#include "Menu.h" // Class definition
|
||||
#include "menu.h" // Class definition
|
||||
|
||||
Menuitem::Menuitem () {} // Placeholder constructor
|
||||
|
||||
|
16
my_SA.h
16
my_SA.h
@ -92,6 +92,18 @@
|
||||
#define IF_STOP_MAX 500000000 // 500MHz
|
||||
#define IF_START_MIN 400000000 // 400MHz
|
||||
|
||||
|
||||
/*
|
||||
* Some definitions for RX-Sweep to test the internal FIR filters
|
||||
*/
|
||||
|
||||
#define RX_SWEEP_START 432000000
|
||||
#define RX_SWEEP_STOP 436000000
|
||||
|
||||
// Limits for keypad entry of IF sweep frequency start/stop
|
||||
#define RX_STOP_MAX 440000000 // 500MHz
|
||||
#define RX_START_MIN 430000000 // 400MHz
|
||||
|
||||
|
||||
/*
|
||||
* Spur reduction shifts the IF down from its normal setting every other scan
|
||||
@ -200,8 +212,8 @@
|
||||
* The values here were Erik's original values
|
||||
*/
|
||||
|
||||
#define TX_CAPACITANCE 0x64 // Transmitter (LO) crystal load capacitance
|
||||
#define RX_CAPACITANCE 0x64 // Receiver crystal load capacitance
|
||||
#define TX_CAPACITANCE 0x65 // Transmitter (LO) crystal load capacitance
|
||||
#define RX_CAPACITANCE 0x59 // Receiver crystal load capacitance
|
||||
|
||||
#define TG_LO_CAPACITANCE 0x64 // Tracking generator LO crystal load capacitance
|
||||
#define TG_IF_CAPACITANCE 0x62 // Tracking generator IF crystal load capacitance
|
||||
|
@ -8,7 +8,7 @@
|
||||
* I2C GPIO expander to drive a parallel version of the PE4302 module.
|
||||
*/
|
||||
|
||||
#include "PE4302.h"
|
||||
#include "pE4302.h"
|
||||
|
||||
|
||||
/*
|
||||
|
316
si4432.cpp
316
si4432.cpp
@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include <SPI.h> // Serial Peripheral Interface library
|
||||
#include "Si4432.h" // Our header file
|
||||
#include "si4432.h" // Our header file
|
||||
#include <esp32-hal-spi.h>
|
||||
|
||||
/*
|
||||
@ -25,21 +25,35 @@
|
||||
bandpassFilter_t Si4432::_bandpassFilters[]
|
||||
{
|
||||
// bw*10, settle, dwn3, ndec, filset
|
||||
{ 26, 7500, 0, 5, 1 }, // 0 "AUTO" selection possibility
|
||||
{ 31, 7000, 0, 5, 3 }, // 1 If user selects 3KHz -> 3.1KHz actual
|
||||
{ 59, 3700, 0, 4, 3 }, // 2 "AUTO" selection possibility
|
||||
{ 106, 2500, 0, 3, 2 }, // 3 If user selects 10KHz -> 10.6KHz actual
|
||||
{ 322, 1000, 0, 2, 6 }, // 4 If user selects 30KHz -> 32.2KHz actual
|
||||
{ 377, 1000, 0, 1, 1 }, // 5 "AUTO" selection possibility
|
||||
{ 562, 700, 0, 1, 5 }, // 6 "AUTO" selection possibility
|
||||
{ 832, 600, 0, 0, 2 }, // 7 "AUTO" selection possibility
|
||||
{ 1121, 500, 0, 0, 5 }, // 8 If user selects 100KHz -> 112.1KHz actual
|
||||
{ 1811, 500, 1, 1, 9 }, // 9 "AUTO" selection possibility
|
||||
{ 2488, 450, 1, 0, 2 }, // 10 "AUTO" selection possibility
|
||||
{ 3355, 400, 1, 0, 8 }, // 11 If user selects 300KHz -> 335.5KHz actual
|
||||
{ 3618, 300, 1, 0, 9 }, // 12 "AUTO" selection possibility
|
||||
{ 4685, 300, 1, 0, 11 }, // 13 "AUTO" selection possibility
|
||||
{ 6207, 300, 1, 0, 14 } // 14 "AUTO" selection possibility
|
||||
{ 26, 6800, 0, 5, 1 }, // 0 "AUTO" selection possibility
|
||||
{ 28, 6600, 0, 5, 2 }, // 1 "AUTO" selection possibility
|
||||
{ 31, 6600, 0, 5, 3 }, // 2 If user selects 3KHz -> 3.1KHz actual
|
||||
{ 32, 6600, 0, 5, 4 }, // 3 "AUTO" selection possibility
|
||||
{ 37, 6600, 0, 5, 5 }, // 4 "AUTO" selection possibility
|
||||
{ 42, 6600, 0, 5, 6 }, // 5 "AUTO" selection possibility
|
||||
{ 45, 5500, 0, 5, 7 }, // 6 "AUTO" selection possibility
|
||||
{ 49, 5000, 0, 4, 1 }, // 7 "AUTO" selection possibility
|
||||
{ 54, 4200, 0, 4, 2 }, // 8 "AUTO" selection possibility
|
||||
{ 59, 3700, 0, 4, 3 }, // 9 "AUTO" selection possibility
|
||||
{ 72, 3300, 0, 4, 5 }, // 10 "AUTO" selection possibility
|
||||
{ 106, 2500, 0, 3, 2 }, // 11 If user selects 10KHz -> 10.6KHz actual
|
||||
{ 162, 2000, 0, 3, 6 }, // 12 "AUTO" selection possibility
|
||||
{ 210, 1600, 0, 2, 2 }, // 13 "AUTO" selection possibility
|
||||
{ 227, 1500, 0, 2, 3 }, // 14 "AUTO" selection possibility
|
||||
{ 240, 1400, 0, 2, 4 }, // 15 "AUTO" selection possibility
|
||||
{ 282, 1000, 0, 2, 5 }, // 16 "AUTO" selection possibility
|
||||
{ 322, 1000, 0, 2, 6 }, // 17 If user selects 30KHz -> 32.2KHz actual
|
||||
{ 377, 1000, 0, 1, 1 }, // 18 "AUTO" selection possibility
|
||||
{ 562, 700, 0, 1, 5 }, // 19 "AUTO" selection possibility
|
||||
{ 832, 600, 0, 0, 2 }, // 20 "AUTO" selection possibility
|
||||
{ 1121, 500, 0, 0, 5 }, // 21 If user selects 100KHz -> 112.1KHz actual
|
||||
{ 1811, 500, 1, 1, 9 }, // 22 "AUTO" selection possibility
|
||||
{ 2251, 1400, 1, 0, 1 }, // 23 "AUTO" selection possibility
|
||||
{ 2488, 450, 1, 0, 2 }, // 24 "AUTO" selection possibility
|
||||
{ 3355, 400, 1, 0, 8 }, // 25 If user selects 300KHz -> 335.5KHz actual
|
||||
{ 3618, 300, 1, 0, 9 }, // 26 "AUTO" selection possibility
|
||||
{ 4685, 300, 1, 0, 11 }, // 27 "AUTO" selection possibility
|
||||
{ 6207, 300, 1, 0, 14 } // 28 "AUTO" selection possibility
|
||||
};
|
||||
|
||||
|
||||
@ -97,82 +111,6 @@ bool Si4432::Init ( uint8_t cap )
|
||||
|
||||
if ( !Reset () ) // Reset the module
|
||||
return false; // If that failed
|
||||
SubInit (); // Things common to both modules
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* We turn on receive mode ("RXON"), the PLL ("PLLON") and ready mode
|
||||
* ("XTON"). The Si4432 module does not have the 32.768 kHz crystal for
|
||||
* the microcontroller, so we do not turn on the "X32KSEL" bit.
|
||||
*
|
||||
* The initial frequency is set to 433.92 MHz which is a typical IF
|
||||
* Finally the GPIO-2 pin is set to ground.
|
||||
*
|
||||
* 03/24 - Logic verified against A440 register edscription document
|
||||
*/
|
||||
|
||||
WriteByte ( REG_OFC1, ( RXON | PLLON | XTON )); // Receiver, PLL and "Ready Mode" all on
|
||||
Tune ( cap ); // Set the crystal capacitance to fine tune frequency
|
||||
|
||||
SetFrequency ( 443920000 ); // 443.92MHz
|
||||
delayMicroseconds ( 300 ); // Time to allow the SI4432 state machine to do its stuff
|
||||
Serial.printf ( "End of Init - _cs = %i\n", _cs );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//bool Si4432::TX_Init ( uint8_t cap, uint8_t power )
|
||||
//{
|
||||
// _type = TX_4432; // We're a transmitter
|
||||
//
|
||||
// if ( !Reset () ) // Reset the module
|
||||
// return false; // If that failed
|
||||
// _pwr = power; // Set the transmitter power level
|
||||
// SubInit (); // Things common to both modules
|
||||
//
|
||||
//
|
||||
///*
|
||||
// * Settings specific to the transmitter module.
|
||||
// *
|
||||
// * This is almost identical to how we set up the receiver except we turn
|
||||
// * on the "TXON" bit (0x08) instead of the "RXON" bit. We also set the
|
||||
// * transmitter power based on the mixer module being used. ("CalcPower"
|
||||
// * function sets the value).
|
||||
// *
|
||||
// * GPIO-2 is handled differently; here, we set GPIO-2 to output the
|
||||
// * microcontroller clock at maximum drive level (0xC0). We also set the
|
||||
// * microcontroller clock speed to 10MHz.
|
||||
// *
|
||||
// * 03/24 - Logic verified against A440
|
||||
// */
|
||||
//
|
||||
// Tune ( cap ); // Set the crystal capacitance
|
||||
// WriteByte ( REG_TXPWR, _pwr ); // Power based on mixer in use
|
||||
//
|
||||
// WriteByte ( REG_GPIO2, 0xC0 ); // Maximum drive and microcontroller clock output
|
||||
// WriteByte ( REG_MCOC, 0x02 ); // Set 10MHz clock output
|
||||
//
|
||||
// SetFrequency ( 443920000 ); // 433.92MHz (setting.IF_Freq???)
|
||||
//
|
||||
// delayMicroseconds ( 300 ); // Doesn't work without this!
|
||||
//
|
||||
// WriteByte ( REG_OFC1, ( TXON | PLLON | XTON )); // Transmitter, PLL and "Ready Mode" all on
|
||||
//
|
||||
//// Serial.println ( "End of TX_Init" );
|
||||
//
|
||||
// return true;
|
||||
//}
|
||||
|
||||
|
||||
/*
|
||||
* "SubInit" is used by the "Init" function to set up
|
||||
* all the registers.
|
||||
*/
|
||||
|
||||
void Si4432::SubInit ()
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -257,10 +195,32 @@ void Si4432::SubInit ()
|
||||
WriteByte ( REG_GPIO1, 0x15 ); // GPIO-1 RX State (output)
|
||||
|
||||
WriteByte ( REG_GPIO2, 0x1F ); // Set GPIO-2 output to ground until needed
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* We turn on receive mode ("RXON"), the PLL ("PLLON") and ready mode
|
||||
* ("XTON"). The Si4432 module does not have the 32.768 kHz crystal for
|
||||
* the microcontroller, so we do not turn on the "X32KSEL" bit.
|
||||
*
|
||||
* The initial frequency is set to 433.92 MHz which is a typical IF
|
||||
* Finally the GPIO-2 pin is set to ground.
|
||||
*
|
||||
* 03/24 - Logic verified against A440 register edscription document
|
||||
*/
|
||||
|
||||
Tune ( cap ); // Set the crystal capacitance to fine tune frequency
|
||||
|
||||
WriteByte ( REG_OFC1, ( RXON | PLLON | XTON )); // Receiver, PLL and "Ready Mode" all on
|
||||
|
||||
SetFrequency ( 443920000 ); // 443.92MHz
|
||||
delayMicroseconds ( 300 ); // Time to allow the SI4432 state machine to do its stuff
|
||||
Serial.printf ( "End of Init - _cs = %i\n", _cs );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "Reset" - Initializes the Si4432.
|
||||
*
|
||||
@ -369,7 +329,7 @@ uint8_t Si4432::ReadByte ( uint8_t reg )
|
||||
|
||||
void Si4432::SetFrequency ( uint32_t freq )
|
||||
{
|
||||
int hbsel; // High/low band select bit
|
||||
int hbsel; // high band select, but shifted to the correct location in the byte
|
||||
int sbsel; // Sideband select bit
|
||||
uint16_t carrier; // Carrier frequency
|
||||
uint32_t reqFreq = freq; // Copy of requested frequency
|
||||
@ -392,7 +352,7 @@ uint8_t registerBuf[4]; // Used to send frequency data in burst mode
|
||||
|
||||
/*
|
||||
* add half the frequency resolution to required frequency so the actual value is rounded to nearest, not lowest
|
||||
* Frequency resoluion is 156.25 in low band, 312.5 in high band but freq is already divided above
|
||||
* Frequency resoluion is 156.25Hz in low band, 312.5Hz in high band but freq is already divided above
|
||||
*/
|
||||
freq = freq + 78;
|
||||
/*
|
||||
@ -440,56 +400,31 @@ uint8_t registerBuf[4]; // Used to send frequency data in burst mode
|
||||
|
||||
/*
|
||||
* M0WID mod - Update the frequency in "burst" mode as opposed to separate
|
||||
* writes for each register, but only update what is needed
|
||||
* writes for each register
|
||||
*/
|
||||
uint8_t ncf1 = ( carrier >> 8 ) & 0xFF;
|
||||
|
||||
// if (fbs != _fbs) // write all three registers
|
||||
// {
|
||||
registerBuf[0] = REG_FBS|0x80; // First register in write mode (bit 7 set)
|
||||
registerBuf[1] = fbs; // FBS register value
|
||||
registerBuf[2] = ncf1 ; // NCF1 value
|
||||
registerBuf[3] = carrier & 0xFF; // NCF0 value
|
||||
|
||||
//_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE ));
|
||||
// spiSimpleTransaction(_spi->bus());
|
||||
digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
_spi->transfer ( registerBuf, 4 ); // Send the data
|
||||
digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
//_spi->endTransaction();
|
||||
_ncf1 = ncf1;
|
||||
_fbs = fbs;
|
||||
// }
|
||||
// else if (ncf1 != _ncf1) // Only write both bytes of the carrier data
|
||||
// {
|
||||
// registerBuf[0] = REG_NCF1|0x80; // First register in write mode (bit 7 set)
|
||||
// registerBuf[1] = ncf1 ; // NCF1 value
|
||||
// registerBuf[2] = carrier & 0xFF; // NCF0 value
|
||||
// digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
// _spi->transfer ( registerBuf, 3 ); // Send the data
|
||||
// digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
// _ncf1 = ncf1;
|
||||
// }
|
||||
// else // Only write the least significant byte of the carrier register
|
||||
// {
|
||||
// registerBuf[0] = REG_NCF0|0x80; // First register in write mode (bit 7 set)
|
||||
// registerBuf[1] = carrier & 0xFF; // NCF0 value
|
||||
// digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
// _spi->transfer ( registerBuf, 2 ); // Send the data
|
||||
// digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
//
|
||||
// }
|
||||
registerBuf[0] = REG_FBS|0x80; // First register in write mode (bit 7 set)
|
||||
registerBuf[1] = fbs; // FBS register value
|
||||
registerBuf[2] = ncf1 ; // NCF1 value
|
||||
registerBuf[3] = carrier & 0xFF; // NCF0 value
|
||||
|
||||
//_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE ));
|
||||
// spiSimpleTransaction(_spi->bus());
|
||||
digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
_spi->transfer ( registerBuf, 4 ); // Send the data
|
||||
digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
//_spi->endTransaction();
|
||||
_ncf1 = ncf1;
|
||||
_fbs = fbs;
|
||||
|
||||
uint32_t fb = ( fbs & F_BAND ) ;
|
||||
hbsel = hbsel>>5; // should be 1 or 0
|
||||
_hbsel = hbsel>>5; // should be 1 or 0
|
||||
|
||||
// _freq will contain the actual frequency, not necessarily what was requested
|
||||
_freq = (double)(10000000 * (hbsel + 1 )) * ( (double)fb + (double)24 + (double)carrier / (double)64000) ;
|
||||
_freq = (double)(10000000 * (_hbsel + 1 )) * ( (double)fb + (double)24 + (double)carrier / (double)64000) ;
|
||||
// Serial.printf("set Freq :%i, actual:%i, fb:%i, fc:%i, hbsel:%i\n", reqFreq, _freq, fb, carrier, hbsel);
|
||||
|
||||
// _spi->endTransaction(); // Release the bus
|
||||
// delayMicroseconds ( WRITE_DELAY ); // Delay needed when writing frequency
|
||||
|
||||
// Serial.print ( ", N = " );
|
||||
// Serial.print ( N );
|
||||
|
||||
@ -518,7 +453,87 @@ uint8_t registerBuf[4]; // Used to send frequency data in burst mode
|
||||
* handled by the calling program.
|
||||
*/
|
||||
|
||||
// delayMicroseconds ( _dt ); // M0WID - Delay depends on RBW
|
||||
// delayMicroseconds ( _dt );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "SetOffsetFreq" adjusts the frequency from the nominal value set in SetFrequency.
|
||||
* It is intended for use by the SI4432 AFC algorithm to enable more accurate
|
||||
* frequency matching of different radios, but we can turn off the AFC and use it
|
||||
* to adjust the frequency without having the Si4432 go through its TX-RX-TX state machine
|
||||
* and enable reduced edlay times from setting a frequency to getting valid readings
|
||||
* The offset can vary +- 80kHz in low bands (f<480MHz) and +-160kHz in high bands (480-960MHz)
|
||||
* negative numbers are twos complement of the positive offset
|
||||
*/
|
||||
void Si4432::SetOffsetFreq ( int32_t freq )
|
||||
{
|
||||
uint8_t registerBuf[3]; // Used to send data in burst mode
|
||||
|
||||
uint32_t posFreq;
|
||||
if (freq < 0)
|
||||
posFreq = -freq;
|
||||
else
|
||||
posFreq = freq;
|
||||
|
||||
uint16_t fo = (double)posFreq/(156.25 * (double)(_hbsel + 1));
|
||||
|
||||
if (freq < 0)
|
||||
// do twos complement - invert the bits (0-9) (use XOR) and add one
|
||||
fo = (fo ^ 0x3FF) + 1;
|
||||
|
||||
//Serial.printf(" offset frequency %i fo=%3x \n", freq, fo);
|
||||
|
||||
// write to the Si4432
|
||||
registerBuf[0] = REG_FOFF1|0x80; // First register in write mode (bit 7 set)
|
||||
registerBuf[1] = fo & 0xFF; // first 8 bits
|
||||
registerBuf[2] = (fo >> 8 ) & 0x03; // last 2 bits
|
||||
|
||||
//_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE ));
|
||||
// spiSimpleTransaction(_spi->bus());
|
||||
digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
_spi->transfer ( registerBuf, 3 ); // Send the data
|
||||
digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
//_spi->endTransaction();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "SetOffset" sets the frequency offset registers to correspond to the number of offset steps
|
||||
*/
|
||||
void Si4432::SetOffset ( int32_t offset )
|
||||
{
|
||||
uint8_t registerBuf[3]; // Used to send data in burst mode
|
||||
|
||||
uint16_t posOffset;
|
||||
if (offset < 0)
|
||||
posOffset = -offset;
|
||||
else
|
||||
posOffset = offset;
|
||||
|
||||
uint16_t fo = posOffset;
|
||||
|
||||
if (offset < 0)
|
||||
// do twos complement - invert the bits (0-9) (use XOR) and add one
|
||||
fo = (fo ^ 0x3FF) + 1;
|
||||
|
||||
//Serial.printf(" posoffset %3x, offset %i fo=%3x \n", posOffset, offset, fo);
|
||||
|
||||
// write to the Si4432
|
||||
registerBuf[0] = REG_FOFF1|0x80; // First register in write mode (bit 7 set)
|
||||
registerBuf[1] = fo & 0xFF; // first 8 bits
|
||||
registerBuf[2] = (fo >> 8 ) & 0x03; // last 2 bits
|
||||
|
||||
//_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE ));
|
||||
// spiSimpleTransaction(_spi->bus());
|
||||
digitalWrite ( _cs, LOW ); // Select the correct device
|
||||
_spi->transfer ( registerBuf, 3 ); // Send the data
|
||||
digitalWrite ( _cs, HIGH ); // Deselect the device
|
||||
//_spi->endTransaction();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -541,8 +556,11 @@ float Si4432::SetRBW ( float reqBandwidth10, unsigned long* delaytime_p ) // "re
|
||||
*/
|
||||
|
||||
if ( reqBandwidth10 <= _bandpassFilters[0].bandwidth10 )
|
||||
{
|
||||
filter = 0;
|
||||
|
||||
Serial.print ("Minimum RBW");
|
||||
}
|
||||
|
||||
/*
|
||||
* If the requested bandwidth is greater or equal to the value in the first entry,
|
||||
* find the setting that is nearest (and above) the requested setting.
|
||||
@ -551,7 +569,7 @@ float Si4432::SetRBW ( float reqBandwidth10, unsigned long* delaytime_p ) // "re
|
||||
while (( _bandpassFilters[filter-1].bandwidth10 > reqBandwidth10 - 0.01 ) && ( filter > 0 ))
|
||||
filter--;
|
||||
|
||||
// Serial.print ( "filter = " ); Serial.println ( filter );
|
||||
Serial.printf ( "Required = %f, filter = %i\n", reqBandwidth10, filter); Serial.println ( filter );
|
||||
|
||||
|
||||
/*
|
||||
@ -748,15 +766,35 @@ void Si4432::RxMode () // Put module in RX mode
|
||||
WriteByte ( REG_OFC1, ( RXON | PLLON | XTON )); // Receiver, PLL and "Ready Mode" all on
|
||||
}
|
||||
|
||||
void Si4432::ReadyMode () // Put module into ready mode, rx and tx off
|
||||
{
|
||||
WriteByte ( REG_OFC1, XTON ); // "Ready Mode" on
|
||||
}
|
||||
|
||||
void Si4432::SetMode (uint8_t newMode)
|
||||
{
|
||||
WriteByte ( REG_OFC1, newMode ); // "Ready Mode" on
|
||||
}
|
||||
|
||||
uint8_t Si4432::GetMode ()
|
||||
{
|
||||
return ReadByte ( REG_OFC1 );
|
||||
}
|
||||
|
||||
/*
|
||||
* "Tune" sets the crystal tuning capacitance.
|
||||
*
|
||||
* We need to cycle the PLL to force a recalibration after the tune
|
||||
*/
|
||||
|
||||
void Si4432::Tune ( uint8_t cap ) // Set the crystal tuning capacitance
|
||||
{
|
||||
_capacitance = cap; // Save in local data
|
||||
WriteByte ( REG_COLC, _capacitance ); // Send to the Si4432
|
||||
uint8_t currentMode = ReadByte ( REG_OFC1 );
|
||||
ReadyMode ();
|
||||
delayMicroseconds(300);
|
||||
SetMode ( currentMode );
|
||||
}
|
||||
|
||||
/*
|
||||
|
14
si4432.h
14
si4432.h
@ -142,6 +142,9 @@
|
||||
|
||||
#define REG_TXPWR 0x6D // Transmitter Power
|
||||
|
||||
#define REG_FOFF1 0x73 // Frequency Offset registers
|
||||
#define REG_FOFF2 0x74
|
||||
|
||||
#define REG_FBS 0x75 // Frequency Band Select
|
||||
#define SBSEL 0x40
|
||||
#define HBSEL 0x20
|
||||
@ -175,9 +178,11 @@ void SetFrequency ( uint32_t Freq ); // Set module's frequency
|
||||
uint32_t GetFrequency (); // Get the module's frequency
|
||||
uint32_t ReadFrequency (); // Read frequency from SI4432
|
||||
|
||||
void SetOffsetFreq ( int32_t freq ); // Set a frequency offset from the nominal frequency
|
||||
void SetOffset ( int32_t offset ); // Offset based on number of offset increments
|
||||
|
||||
void SetPowerReference ( int freq ); // Set the GPIO output for the LO
|
||||
void SetDrive ( uint8_t level ); // Sets the drive level
|
||||
void TxMode ( uint8_t level ); // Put module in TX mode
|
||||
|
||||
float SetRBW ( float reqBandwidth10, unsigned long* delaytime_p ); // "reqBandwidth" in kHz * 10
|
||||
|
||||
@ -188,7 +193,13 @@ bool PreAmpAGC(); // Reads the register and return true if agc set to a
|
||||
bool GetPreAmpAGC (); // Return true if agc set to auto
|
||||
|
||||
uint8_t GetRSSI (); // Get Receiver Signal Strength
|
||||
|
||||
void RxMode (); // Put module in RX mode
|
||||
void TxMode ( uint8_t level ); // Put module in TX mode
|
||||
void ReadyMode (); // Put module in READY mode, crystal on, PLL off
|
||||
uint8_t GetMode ();
|
||||
void SetMode (uint8_t newMode);
|
||||
|
||||
void Tune ( uint8_t cap ); // Set the crystal tuning capacitance
|
||||
|
||||
void WriteByte ( byte reg, byte setting ); // Write a byte of data to the specified register
|
||||
@ -221,6 +232,7 @@ uint8_t _pwr; // Current power output (TX only?)
|
||||
uint8_t _type; // Transmitter or receiver
|
||||
uint8_t _capacitance; // Crystal load capacitance
|
||||
SPIClass* _spi; // Pointer to the SPI object
|
||||
int _hbsel; // High band (1) or low band (0)
|
||||
uint8_t _fbs; // Current value of frequency band select register
|
||||
uint8_t _ncf1; // Current value for most significant byte of carrier
|
||||
uint32_t _freq; // Current actual frequency
|
||||
|
28
simpleSA.h
28
simpleSA.h
@ -26,13 +26,13 @@
|
||||
#ifndef TINYSA_H_
|
||||
#define TINYSA_H_ // Prevent double inclusion
|
||||
|
||||
#include "My_SA.h" // User settable parameters
|
||||
#include "my_SA.h" // User settable parameters
|
||||
#include <Arduino.h> // General Arduino definitions
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
|
||||
#define PROGRAM_NAME "TinySA" // These are for the WiFi interface
|
||||
#define PROGRAM_VERSION "3.0" // Current version is 3.0
|
||||
#define PROGRAM_NAME "simpleSA" // These are for the WiFi interface
|
||||
#define PROGRAM_VERSION "0.01" // Current version is 0.01 - beta!
|
||||
|
||||
|
||||
/*
|
||||
@ -41,7 +41,7 @@
|
||||
* it out, it will stay set at '1'.
|
||||
*/
|
||||
|
||||
#define TRACE_COUNT 1 // Number fo different traces available
|
||||
#define TRACE_COUNT 1 // Number of different traces available
|
||||
|
||||
|
||||
/*
|
||||
@ -49,6 +49,7 @@
|
||||
*/
|
||||
|
||||
#define DISPLAY_POINTS 290 // Number of scan points in a sweep
|
||||
#define BANDSCOPE_POINTS 80 // Number of scan points in a bandscope sweep
|
||||
#define CHAR_HEIGHT 8 // Height of a character
|
||||
#define HALF_CHAR_H 4 // Half a character height
|
||||
#define CHAR_WIDTH 6 // Width of a character
|
||||
@ -63,6 +64,9 @@
|
||||
|
||||
#define GRID_HEIGHT ( Y_GRID * DELTA_Y ) // Height of checkerboard
|
||||
|
||||
#define WATERFALL_HEIGHT 100 // Height of waterfall in Bandscope mode
|
||||
|
||||
|
||||
/*
|
||||
* Definitions used in signal generator mode
|
||||
*/
|
||||
@ -175,7 +179,7 @@
|
||||
*/
|
||||
|
||||
enum { SA_LOW_RANGE, SA_HIGH_RANGE, SIG_GEN_LOW_RANGE, SIG_GEN_HIGH_RANGE,
|
||||
IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR, BANDSCOPE };
|
||||
IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR, BANDSCOPE, RX_SWEEP };
|
||||
|
||||
|
||||
/*
|
||||
@ -229,7 +233,7 @@ typedef struct {
|
||||
int8_t Attenuate = 0; // Attenuator setting (***)
|
||||
int8_t Generate = 0; // Signal generator mode if not zero (***)
|
||||
int16_t Bandwidth10 = 0; // Resolution Bandwidth setting*10; 0 = auto
|
||||
int16_t LevelOffset = 0; // Related to power reading; not sure what though!
|
||||
int16_t LevelOffset = 0; // Calibration value (move to config?)
|
||||
int8_t ReferenceOut = 1; // Transmitter GPIO2 set to 15MHz
|
||||
int16_t PowerGrid = 10; // dB/vertical divison on the grid
|
||||
bool Spur = 0; // Spur reduction on or off
|
||||
@ -239,7 +243,7 @@ typedef struct {
|
||||
bool SubtractStorage = 0; // Subtract stored scan (on or off)
|
||||
bool ShowGain = 1; // Display gain trace (on or off)
|
||||
bool ShowSweep = 1; // Display dB trace (on or off)
|
||||
uint8_t Drive = 6; // LO Drive power (***)
|
||||
uint8_t Drive = 6; // LO Drive power (***) (move to config?)
|
||||
uint8_t SigGenDrive = 5; // Signal generator drive (for RX SI4432)
|
||||
uint8_t spareUint8t_1 = 5; // spare
|
||||
uint8_t spareUint8t_2 = 5; // spare
|
||||
@ -247,10 +251,14 @@ typedef struct {
|
||||
uint16_t Mode = SA_LOW_RANGE; // Default to low freq range Spectrum analyser mode
|
||||
uint16_t Timebase = 100; // Timebase for Zero IF modes (milliSeconds)
|
||||
int16_t TriggerLevel = -40; // Trigger level for ZeroIF mode (dBm)
|
||||
uint32_t BandscopeStart = 7000000; // Start frequency for bandscope sweep
|
||||
uint32_t BandscopeStart = 14000000; // Start frequency for bandscope sweep
|
||||
uint32_t BandscopeSpan = 200000; // Span for the bandscope sweep
|
||||
uint16_t BandscopePoints = 80; // No of points in the sweep. 80/160/320
|
||||
|
||||
uint16_t BandscopePoints = BANDSCOPE_POINTS; // No of points in the sweep. 80/160/320
|
||||
int16_t BandscopeMaxGrid= -30;
|
||||
int16_t BandscopeMinGrid= -130;
|
||||
int16_t BandscopeRBW10 = 28; // Resolution Bandwidth setting*10;
|
||||
int16_t WaterfallMin = 17; // RSSI values below this are treated as zero
|
||||
double WaterfallGain = 1.5; // Multiply RSSI value to get colour intensity
|
||||
|
||||
/*
|
||||
* The following line should read:
|
||||
|
323
simpleSA.ino
323
simpleSA.ino
@ -2,6 +2,7 @@
|
||||
* "simpleSA.ino"
|
||||
*
|
||||
* This is the main program file for the "TinySA for ESP32" (spectrum analyzer)
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2020 David Wilde (M0WID), John Price (WA2FZW)
|
||||
*
|
||||
@ -22,17 +23,21 @@
|
||||
* The starting point for this version is the "tinySA_touch05" software developed
|
||||
* by David (M0WID).
|
||||
* That software was based on the original version for STM "Blue Pill" by Erik Kaashoek PD0EK.
|
||||
* For more information on that version visit https://groups.io/g/HBTE/topics
|
||||
*
|
||||
* Glen VK3PE has designed a set of PCB - see http://www.carnut.info/tinySA/tinySA.html
|
||||
*
|
||||
* Erik has since gone on to produce a commecial version, google tinySA, and this software
|
||||
* has been renamed simpleSA to avoid confusion.
|
||||
*
|
||||
* Modified by John Price (WA2FZW):
|
||||
*
|
||||
* Version 1.0:
|
||||
*
|
||||
* Just add comments, try to figure out how it all works and move some stuff
|
||||
* around for clarity!
|
||||
*
|
||||
*
|
||||
* Version 1.1:
|
||||
*
|
||||
* Added the file "Si4432.h" which contains symbols for all the Si4432
|
||||
* registers and some other things related to it's operation.
|
||||
*
|
||||
@ -54,12 +59,10 @@
|
||||
*
|
||||
*
|
||||
* Version 1.6:
|
||||
*
|
||||
* Added the file "Si4432.cpp" and moved all of the functions to handle the
|
||||
* interface to the hardware out of here. *
|
||||
*
|
||||
* Version 1.7:
|
||||
*
|
||||
* Moved all the global variables to the top of the file and moved the "setup"
|
||||
* and "loop" functions to the top where they are customarily found.
|
||||
*
|
||||
@ -69,18 +72,15 @@
|
||||
*
|
||||
*
|
||||
* Version 1.8:
|
||||
*
|
||||
* Replaced the original code to handle the Si4432 modules with a class/object
|
||||
* implementation using real SPI protocol.
|
||||
*
|
||||
*
|
||||
* Version 2.0:
|
||||
*
|
||||
* Overhauled the serial command handler and help menu.
|
||||
*
|
||||
*
|
||||
* Version 2.1:
|
||||
*
|
||||
* A major overhaul of the entire architecture! I moved all the functions that
|
||||
* handle reading and processing commands from the serial input into "Cmd.cpp".
|
||||
* This is the first step into being able to use common command processing for
|
||||
@ -88,14 +88,12 @@
|
||||
*
|
||||
*
|
||||
* Version 2.7:
|
||||
*
|
||||
* More restructuring. Added markers . Added more
|
||||
* commands to the serial command handler. Re-organized the touch screen menus
|
||||
* in a more logical hierarchy and added some new capabilities there.
|
||||
*
|
||||
*
|
||||
* Version 2.8 Changes by M0WID:
|
||||
*
|
||||
* Data now pushed to the web clients
|
||||
* Grid y changed to have 10 divisions
|
||||
* Various bug fixes
|
||||
@ -128,10 +126,12 @@
|
||||
* SPI now runs at 16MHz (was at 1MHz - oops!)
|
||||
* Additional functions in ui.cmd to allow signed frequency entry.
|
||||
*
|
||||
* Moved to github for trial
|
||||
* Added initial changes for bandscope mode
|
||||
* Added indication of tracking generator on/off
|
||||
* Renamed to simpleSA
|
||||
* Version 3.0f Changes by M0WID
|
||||
* renamed simpleSA. Doesn't seem that simple to me!
|
||||
* First go at bandscope mode
|
||||
* VSPI reduced to 10Mhz as some boards will not run at 16MHz
|
||||
* Put onto github - lets see how it works!
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@ -139,10 +139,10 @@
|
||||
#include <Arduino.h> // Basic Arduino definitions
|
||||
#include <SPI.h> // Serial Peripheral Interface library
|
||||
#include <Wire.h> // I2C library
|
||||
#include "Si4432.h" // Si4432 tranceiver class definitions and prototypes
|
||||
#include "PE4302.h" // PE4302 attenuator class
|
||||
#include "Cmd.h" // Command processing functions
|
||||
#include "Marker.h" // Marker class
|
||||
#include "si4432.h" // Si4432 tranceiver class definitions and prototypes
|
||||
#include "pE4302.h" // PE4302 attenuator class
|
||||
#include "cmd.h" // Command processing functions
|
||||
#include "marker.h" // Marker class
|
||||
|
||||
|
||||
#if USE_WIFI // M0WID - We need the following if using WiFi
|
||||
@ -163,7 +163,7 @@
|
||||
|
||||
/*
|
||||
* Note the actual definitions for display and touch screen pins used are defined
|
||||
* in the file "M0WID_Setup_ILI9341_simpleSA.h" in the "User_Setups" directory of
|
||||
* in the file "M0WID_Setup_ILI9341_TinySA.h" in the "User_Setups" directory of
|
||||
* the "TFT_eSPI" library.
|
||||
*
|
||||
* These are based on using HSPI (spi2) for display and VSPI (spi3) for the SI4432s
|
||||
@ -356,22 +356,53 @@ size_t capacity = JSON_ARRAY_SIZE ( MAX_WIFI_POINTS + 1 )
|
||||
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // Buffer for json data to be pushed to the web clients
|
||||
static JsonArray Points = jsonDocument.createNestedArray ( "Points" ); // add Points array
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Variables to determine size of grid and waterfall
|
||||
* In Bandscope mode the grid is reduced. In future it may be possible to add
|
||||
* a waterfall to the main sweep, but not yet
|
||||
*/
|
||||
uint16_t gridHeight = GRID_HEIGHT;
|
||||
uint16_t gridWidth = DISPLAY_POINTS;
|
||||
uint16_t yGrid = Y_GRID; // no of grid divisions
|
||||
uint16_t yDelta = gridHeight / yGrid; // no of points/division
|
||||
uint16_t xGrid = X_GRID;
|
||||
uint16_t xOrigin = X_ORIGIN;
|
||||
uint16_t yOrigin = Y_ORIGIN;
|
||||
uint16_t displayPoints = DISPLAY_POINTS;
|
||||
uint16_t xDelta = displayPoints / xGrid;
|
||||
uint16_t waterfallHeight = WATERFALL_HEIGHT;
|
||||
int16_t maxGrid;
|
||||
int16_t minGrid;
|
||||
|
||||
/*
|
||||
* Some varibales for the various operating modes
|
||||
*/
|
||||
uint16_t tinySA_mode = SA_LOW_RANGE; // Low frequency range
|
||||
const char *modeText[] = { "SALo", "SAHi", "SGLo", "SGHi", "IFSw", "0SpL", "0SpH", "TrGn" }; // For mode display
|
||||
const char *modeText[] = { "SALo", "SAHi", "SGLo", "SGHi", "IFSw", "0SpL", "0SpH", "TrGn", "BScp", "RXSw" }; // For mode display
|
||||
|
||||
|
||||
float bandwidth; // The current bandwidth (not * 10)
|
||||
unsigned long delaytime = 2000; // M0WID - changed to microseconds and moved here
|
||||
unsigned long delaytime = 2000; // delay time to allow SI4432 filters to settle
|
||||
|
||||
uint32_t steps = DISPLAY_POINTS; // Number of frequency steps in the sweep
|
||||
uint32_t steps = displayPoints; // Number of frequency steps in the sweep
|
||||
uint32_t sweepPoints; // Number of points in the sweep. Can be more than DISPLAY_POINTS if RBW is set less than video resolution
|
||||
uint32_t startFreq = 0; // Default start frequency is 0MHz
|
||||
uint32_t stopFreq = 100000000; // Default stop frequency is 100MHz
|
||||
uint32_t tempIF; // IF used for this sweep. Changes if Spur reduction is on
|
||||
|
||||
/*
|
||||
* Variables for offset frequency tuning
|
||||
*/
|
||||
int32_t offsetFreq; // Frequency offset from nominal setting
|
||||
int16_t offsetStep; // increments by one at each reading
|
||||
int16_t offsetValue; // Offset value to be written to Si4432
|
||||
int16_t offsetIncrement; // Increment of offsetValue per reading
|
||||
int32_t offsetFreqIncrement; // Increment offsetFreq per reading
|
||||
unsigned long offsetDelayTime = 5000; // Delay time when using frequency offset to change frequency
|
||||
|
||||
|
||||
int VFO = RX_4432; // Set current VFO for command parser to the receiver Si4432
|
||||
|
||||
int gainReading; // Current preamp gain (will vary during a scan if AGC enabled)
|
||||
@ -389,6 +420,7 @@ extern void StartSigGenMenu ( void ); // Function to launch sig gen menu
|
||||
extern void StartSigGenFreq ( void ); // Function to set frequency
|
||||
extern void ResetSAMenuStack ( void ); // Reinitialise stack for SA mode
|
||||
extern void ResetIFsweepMenuStack ( void ); // Reinitialise stack for IF Sweep mode
|
||||
extern void ResetRXsweepMenuStack ( void ); // Reinitialise stack for IF Sweep mode
|
||||
extern void ResetBandscopeMenuStack ( void ); // Reinitialise stack for Bandscope mode
|
||||
|
||||
extern void ShowSplash ( void ); // Displays the splash screen
|
||||
@ -403,8 +435,14 @@ extern void pushBandscopeSettings ();
|
||||
*/
|
||||
uint32_t startFreq_IF = IF_SWEEP_START;
|
||||
uint32_t stopFreq_IF = IF_SWEEP_STOP;
|
||||
uint32_t sigFreq_IF = 20000000; // 30 Mhz reference
|
||||
uint32_t sigFreq_IF = 15000000; // 15 Mhz reference
|
||||
|
||||
/*
|
||||
* Variables for RXSweep Mode
|
||||
*/
|
||||
uint32_t startFreq_RX = RX_SWEEP_START;
|
||||
uint32_t stopFreq_RX = RX_SWEEP_STOP;
|
||||
uint32_t sigFreq_RX = 15000000; // 15 Mhz reference
|
||||
|
||||
/*
|
||||
* Variables for timing websocket event checks:
|
||||
@ -430,33 +468,33 @@ uint32_t sweepCount; // Used to inhibit handling Wifi until
|
||||
|
||||
/*
|
||||
* These arrays contain the data for the various scan points; they are used in
|
||||
* here and in the "simpleSA_wifi" modules:
|
||||
* here and in the "TinySA_wifi" modules:
|
||||
*/
|
||||
|
||||
uint8_t myData[DISPLAY_POINTS+1];
|
||||
uint8_t myStorage[DISPLAY_POINTS+1];
|
||||
uint8_t myActual[DISPLAY_POINTS+1];
|
||||
uint8_t myGain[DISPLAY_POINTS+1]; // Preamp gain
|
||||
uint32_t myFreq[DISPLAY_POINTS+1]; // Frequency for XML file
|
||||
uint8_t myData[SCREEN_WIDTH+1];
|
||||
uint8_t myStorage[SCREEN_WIDTH+1];
|
||||
uint8_t myActual[SCREEN_WIDTH+1];
|
||||
uint8_t myGain[SCREEN_WIDTH+1]; // Preamp gain
|
||||
uint32_t myFreq[SCREEN_WIDTH+1]; // Frequency for XML file
|
||||
|
||||
uint16_t peakLevel; // Current maximum signal level
|
||||
uint16_t oldPeakLevel; // Old maximum signal level
|
||||
uint16_t peakIndex;
|
||||
uint16_t peakGain; // Actual gain at the peak (ie minimum gain)
|
||||
|
||||
static int old_settingAttenuate = -1000;
|
||||
static int old_settingPowerGrid = -1000;
|
||||
static int old_settingMax = -1;
|
||||
static int old_settingMin = -1;
|
||||
static long old_startFreq = -1;
|
||||
static long old_stopFreq = -1;
|
||||
static int ownrbw = 0;
|
||||
static int old_ownrbw = -1;
|
||||
static int vbw = 0;
|
||||
static int old_vbw = -1;
|
||||
static int old_settingAverage = -1;
|
||||
static int old_settingSpur = -100;
|
||||
static int old_bandwidth = 0;
|
||||
static int old_settingAttenuate = -1000;
|
||||
static int old_settingPowerGrid = -1000;
|
||||
static int old_settingMax = -1;
|
||||
static int old_settingMin = -1;
|
||||
static double old_startFreq = -1;
|
||||
static double old_stopFreq = -1;
|
||||
static int ownrbw = 0;
|
||||
static int old_ownrbw = -1;
|
||||
static int vbw = 0;
|
||||
static int old_vbw = -1;
|
||||
static int old_settingAverage = -1;
|
||||
static int old_settingSpur = -100;
|
||||
static int old_bandwidth = 0;
|
||||
|
||||
int16_t standalone = true;
|
||||
uint16_t spacing = 10000;
|
||||
@ -721,7 +759,7 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
startAP (); // Start it up
|
||||
|
||||
#else // Connect to the router using SSID
|
||||
// and password defined in simpleSA.h
|
||||
// and password defined in TinySA.h
|
||||
|
||||
Serial.println ( "Connecting..." ); // Indicate trying to connect
|
||||
|
||||
@ -769,7 +807,7 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
|
||||
// tft.println("Setup Complete");
|
||||
|
||||
Serial.printf ( "\nsimpleSA Version %s Initialization Complete\n", PROGRAM_VERSION );
|
||||
Serial.printf ( "\nTinySA Version %s Initialization Complete\n", PROGRAM_VERSION );
|
||||
|
||||
ShowMenu (); // Display the menu of commands on serial monitor
|
||||
|
||||
@ -860,6 +898,10 @@ loopStartMicros = micros();
|
||||
doIF_Sweep(); // IF Sweep
|
||||
break;
|
||||
|
||||
case RX_SWEEP:
|
||||
doRX_Sweep(); // RX Sweep
|
||||
break;
|
||||
|
||||
case BANDSCOPE:
|
||||
doBandscope(); // Bandscope Sweep
|
||||
break;
|
||||
@ -899,14 +941,19 @@ void setMode ( uint16_t newMode )
|
||||
// initSigHigh();
|
||||
// break;
|
||||
|
||||
case BANDSCOPE:
|
||||
initBandscope();
|
||||
break;
|
||||
|
||||
case IF_SWEEP:
|
||||
initIF_Sweep();
|
||||
break;
|
||||
|
||||
case BANDSCOPE:
|
||||
initBandscope();
|
||||
case RX_SWEEP:
|
||||
initRX_Sweep();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
DisplayError ( ERR_WARN,
|
||||
"Invalid Mode!",
|
||||
@ -952,6 +999,13 @@ void menuExit()
|
||||
initIF_Sweep();
|
||||
break;
|
||||
|
||||
case RX_SWEEP:
|
||||
if ( setting.Mode == RX_SWEEP )
|
||||
RedrawHisto();
|
||||
else
|
||||
initRX_Sweep();
|
||||
break;
|
||||
|
||||
case BANDSCOPE:
|
||||
if ( setting.Mode == BANDSCOPE )
|
||||
RedrawHisto();
|
||||
@ -968,7 +1022,7 @@ void menuExit()
|
||||
|
||||
|
||||
/*
|
||||
* Initialise common to low, high and IF_Sweeps
|
||||
* Initialise common to low, high, RX and IF_Sweeps
|
||||
*/
|
||||
void init_sweep()
|
||||
{
|
||||
@ -990,7 +1044,7 @@ void init_sweep()
|
||||
img.setTextSize ( 1 );
|
||||
img.setColorDepth ( 16 );
|
||||
img.setAttribute ( PSRAM_ENABLE, false ); // Don't use the PSRAM on the WROVERs
|
||||
img.createSprite ( 2, GRID_HEIGHT + 1 ); // Only 2 columns wide
|
||||
img.createSprite ( 2, gridHeight + 1 ); // Only 2 columns wide
|
||||
|
||||
|
||||
/*
|
||||
@ -1033,21 +1087,22 @@ void init_sweep()
|
||||
old_settingSpur = -100;
|
||||
old_bandwidth = 0;
|
||||
|
||||
SetRX ( 0 ); // LO to transmit, RX to receive
|
||||
SetRX ( 0 ); // LO to transmit, RX to receive
|
||||
xmit.SetOffset ( 0 ); // make sure frequency offset registers are zero
|
||||
|
||||
xmit.SetDrive ( setting.Drive ); // Set transmitter power level
|
||||
rcvr.SetPreampGain ( setting.PreampGain );
|
||||
|
||||
#ifdef SI_TG_IF_CS
|
||||
if (tgIF_OK) {
|
||||
tg_if.TxMode ( trackGenSetting.IF_Drive ); // turn on the IF oscillator in tracking generator
|
||||
tg_if.TxMode ( trackGenSetting.IF_Drive ); // turn on the IF oscillator in tracking generator
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
if (tgLO_OK) {
|
||||
tg_lo.TxMode ( trackGenSetting.LO_Drive ); // turn on the Local Oscillator in tracking generator
|
||||
tg_lo.TxMode ( trackGenSetting.LO_Drive ); // turn on the Local Oscillator in tracking generator
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1331,7 +1386,17 @@ void RedrawHisto ()
|
||||
old_settingAverage = -1;
|
||||
old_settingSpur = -100;
|
||||
ClearDisplay();
|
||||
DisplayInfo();
|
||||
switch (tinySA_mode)
|
||||
{
|
||||
case BANDSCOPE:
|
||||
DisplayBandscopeInfo();
|
||||
break;
|
||||
|
||||
default:
|
||||
DisplayInfo();
|
||||
break;
|
||||
|
||||
}
|
||||
DrawFullCheckerBoard();
|
||||
}
|
||||
|
||||
@ -1350,7 +1415,7 @@ double fStart;
|
||||
double fCenter;
|
||||
double fStop;
|
||||
|
||||
// enum { SA_LOW_RANGE, SA_HIGH_RANGE, SIG_GEN_LOW_RANGE, SIG_GEN_HIGH_RANGE, IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR };
|
||||
// enum { SA_LOW_RANGE, SA_HIGH_RANGE, SIG_GEN_LOW_RANGE, SIG_GEN_HIGH_RANGE, IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, TRACKING_GENERATOR, RX_SWEEP };
|
||||
|
||||
tSprite.fillSprite ( BLACK );
|
||||
tSprite.setTextColor ( WHITE );
|
||||
@ -1376,10 +1441,10 @@ double fStop;
|
||||
|
||||
sSprite.setCursor ( 0, CHAR_HEIGHT * 2 );
|
||||
sSprite.setTextColor ( DB_COLOR );
|
||||
sSprite.printf ( "%4i", setting.MaxGrid );
|
||||
sSprite.printf ( "%4i", maxGrid );
|
||||
|
||||
sSprite.setCursor ( 0, GRID_HEIGHT + Y_ORIGIN );
|
||||
sSprite.printf ( "%4i", setting.MinGrid );
|
||||
sSprite.setCursor ( 0, gridHeight + yOrigin );
|
||||
sSprite.printf ( "%4i", minGrid );
|
||||
|
||||
sSprite.setTextColor ( WHITE );
|
||||
sSprite.setCursor ( 0, HALF_CHAR_H * 8 );
|
||||
@ -1493,6 +1558,11 @@ double fStop;
|
||||
fCenter = (double) ((( startFreq_IF + stopFreq_IF ) / 2.0 ) / 1000000.0 );
|
||||
fStop = stopFreq_IF/1000000.0;
|
||||
}
|
||||
else if (tinySA_mode == RX_SWEEP) {
|
||||
fStart = startFreq_RX/1000000.0;
|
||||
fCenter = (double) ((( startFreq_RX + stopFreq_RX ) / 2.0 ) / 1000000.0 );
|
||||
fStop = stopFreq_RX/1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fStart = (( (double)setting.ScanStart )/ 1000000.0); // Start freq
|
||||
@ -1503,16 +1573,16 @@ double fStop;
|
||||
|
||||
if ( old_startFreq != fStart || old_stopFreq != fStop )
|
||||
{
|
||||
tft.fillRect ( X_ORIGIN, SCREEN_HEIGHT -
|
||||
CHAR_HEIGHT, SCREEN_WIDTH - X_ORIGIN - 1, SCREEN_HEIGHT - 1, BLACK );
|
||||
tft.fillRect ( xOrigin, SCREEN_HEIGHT -
|
||||
CHAR_HEIGHT, SCREEN_WIDTH - xOrigin - 1, SCREEN_HEIGHT - 1, BLACK );
|
||||
|
||||
// Show operating mode
|
||||
tft.setCursor ( X_ORIGIN + 50, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setCursor ( xOrigin + 50, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setTextColor ( DB_COLOR );
|
||||
tft.printf ( "Mode:%s", modeText[setting.Mode] );
|
||||
tft.setTextColor ( WHITE );
|
||||
|
||||
tft.setCursor ( X_ORIGIN + 2, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setCursor ( xOrigin + 2, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
|
||||
tft.print ( fStart );
|
||||
// tft.print( "MHz" );
|
||||
@ -1525,7 +1595,7 @@ double fStop;
|
||||
/*
|
||||
* Show the center frequency:
|
||||
*/
|
||||
tft.setCursor ( SCREEN_WIDTH / 2 - 40 + X_ORIGIN, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.setCursor ( SCREEN_WIDTH / 2 - 40 + xOrigin, SCREEN_HEIGHT - CHAR_HEIGHT );
|
||||
tft.print ( fCenter );
|
||||
tft.print ( "(MHz)" );
|
||||
|
||||
@ -1583,7 +1653,7 @@ double fStop;
|
||||
int x = tSprite.width () - 45;
|
||||
tSprite.setTextColor ( WHITE );
|
||||
|
||||
tSprite.pushSprite ( X_ORIGIN, 0 ); // Write sprite to the display
|
||||
tSprite.pushSprite ( xOrigin, 0 ); // Write sprite to the display
|
||||
|
||||
updateSidebar = false;
|
||||
} // End of "DisplayInfo"
|
||||
@ -1596,12 +1666,12 @@ double fStop;
|
||||
|
||||
void DrawFullCheckerBoard()
|
||||
{
|
||||
for ( int p=0; p<DISPLAY_POINTS; p++ )
|
||||
for ( int p=0; p<displayPoints; p++ )
|
||||
{
|
||||
DrawCheckerBoard ( p );
|
||||
|
||||
if ( p > 0 )
|
||||
img.pushSprite( X_ORIGIN+p-1, Y_ORIGIN );
|
||||
img.pushSprite( xOrigin+p-1, yOrigin );
|
||||
}
|
||||
|
||||
// Serial.println ( "DrawFullCheckerBoard" );
|
||||
@ -1612,7 +1682,7 @@ void DrawFullCheckerBoard()
|
||||
* "DrawCheckerBoard" - Paints the grid. It now uses a sprite so no need to
|
||||
* erase the old grid, just draw a new one.
|
||||
*
|
||||
* The sprite is two pixels wide, and the image from the previous data point
|
||||
* The img sprite is two pixels wide, and the image from the previous data point
|
||||
* is scrolled and then new data point drawn. The data from last is scrolled
|
||||
* so any line from before is retained.
|
||||
*/
|
||||
@ -1625,24 +1695,24 @@ void DrawCheckerBoard ( int x )
|
||||
if ( x == 1 )
|
||||
{
|
||||
img.fillSprite ( BLACK ); // Clear the sprite
|
||||
img.drawFastVLine ( 0, 0, GRID_HEIGHT, DARKGREY ); // Draw vertical line at edge
|
||||
img.drawFastVLine ( 0, 0, gridHeight, DARKGREY ); // Draw vertical line at edge
|
||||
|
||||
for ( int y=0; y <= Y_GRID; y++ )
|
||||
img.drawPixel ( 1, y*DELTA_Y, DARKGREY ); // Draw the horizontal grid lines
|
||||
for ( int y=0; y <= yGrid; y++ )
|
||||
img.drawPixel ( 1, y*yDelta, DARKGREY ); // Draw the horizontal grid lines
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
img.setScrollRect ( 0, 0, 2,GRID_HEIGHT, BLACK ); // Scroll the whole sprite
|
||||
img.setScrollRect ( 0, 0, 2,gridHeight, BLACK ); // Scroll the whole sprite
|
||||
img.scroll ( -1, 0 );
|
||||
int lastStep = x - 1;
|
||||
|
||||
if (( x % DELTA_X ) == 0 ) // Need a vertical line here
|
||||
img.drawFastVLine ( 1, 0, GRID_HEIGHT, DARKGREY );
|
||||
if (( x % xDelta ) == 0 ) // Need a vertical line here
|
||||
img.drawFastVLine ( 1, 0, gridHeight, DARKGREY );
|
||||
|
||||
else
|
||||
for ( int y = 0; y <= Y_GRID; y++ )
|
||||
img.drawPixel ( 1, y * DELTA_Y, DARKGREY ); // Draw the horizontal grid lines
|
||||
for ( int y = 0; y <= yGrid; y++ )
|
||||
img.drawPixel ( 1, y * yDelta, DARKGREY ); // Draw the horizontal grid lines
|
||||
}
|
||||
}
|
||||
|
||||
@ -1654,18 +1724,18 @@ void DrawCheckerBoard ( int x )
|
||||
|
||||
uint16_t rssiToImgY ( uint8_t rSSI )
|
||||
{
|
||||
int delta = setting.MaxGrid - setting.MinGrid;
|
||||
int delta = maxGrid - minGrid;
|
||||
double y = rssiTodBm ( rSSI );
|
||||
|
||||
y = ( y - setting.MinGrid ) * GRID_HEIGHT / delta;
|
||||
y = ( y - minGrid ) * gridHeight / delta;
|
||||
|
||||
if ( y >= GRID_HEIGHT )
|
||||
y = GRID_HEIGHT-1;
|
||||
if ( y >= gridHeight )
|
||||
y = gridHeight-1;
|
||||
|
||||
if ( y < 0 )
|
||||
y = 0;
|
||||
|
||||
return GRID_HEIGHT - 1 - (int) y;
|
||||
return gridHeight - 1 - (int) y;
|
||||
}
|
||||
|
||||
|
||||
@ -1679,6 +1749,16 @@ double rssiTodBm ( uint8_t rSSI )
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function to convert rSSi to dBm
|
||||
*/
|
||||
|
||||
uint8_t dBmToRSSI ( double dBm )
|
||||
{
|
||||
return ( 2 * ( dBm - setting.Attenuate + 120.0 - setting.LevelOffset ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "DisplayPoint" - Display a point on the chart.
|
||||
*
|
||||
@ -1693,28 +1773,28 @@ void DisplayPoint ( uint8_t* data, int i, int color )
|
||||
return;
|
||||
|
||||
int lastPoint = i - 1;
|
||||
int delta = setting.MaxGrid - setting.MinGrid;
|
||||
int delta = maxGrid - minGrid;
|
||||
double f0 = (( data[i] / 2.0 + setting.Attenuate ) - 120.0 ) + setting.LevelOffset; // Current point
|
||||
f0 = ( f0 - setting.MinGrid ) * GRID_HEIGHT / delta;
|
||||
f0 = ( f0 - minGrid ) * gridHeight / delta;
|
||||
|
||||
if ( f0 >= GRID_HEIGHT )
|
||||
f0 = GRID_HEIGHT-1;
|
||||
if ( f0 >= gridHeight )
|
||||
f0 = gridHeight-1;
|
||||
|
||||
if ( f0 < 0 )
|
||||
f0 = 0;
|
||||
|
||||
double f1 = (( data[lastPoint] / 2.0 + setting.Attenuate ) - 120.0) + setting.LevelOffset; // Previous point
|
||||
|
||||
f1 = ( f1 - setting.MinGrid ) * GRID_HEIGHT / delta;
|
||||
f1 = ( f1 - minGrid ) * gridHeight / delta;
|
||||
|
||||
if ( f1 >= GRID_HEIGHT )
|
||||
f1 = GRID_HEIGHT-1;
|
||||
if ( f1 >= gridHeight )
|
||||
f1 = gridHeight-1;
|
||||
|
||||
if ( f1 < 0 )
|
||||
f1 = 0;
|
||||
|
||||
int Y0 = GRID_HEIGHT - 1 - (int) f0;
|
||||
int Y1 = GRID_HEIGHT - 1 - (int) f1;
|
||||
int Y0 = gridHeight - 1 - (int) f0;
|
||||
int Y1 = gridHeight - 1 - (int) f1;
|
||||
|
||||
img.drawLine ( 0, Y1, 1, Y0, color );
|
||||
}
|
||||
@ -1735,26 +1815,26 @@ void displayGainPoint ( unsigned char *data, int i, int color )
|
||||
|
||||
// Serial.printf ( "gain %f \n", f );
|
||||
|
||||
f0 = ( f0 ) * GRID_HEIGHT / delta;
|
||||
f0 = ( f0 ) * gridHeight / delta;
|
||||
|
||||
if ( f0 >= GRID_HEIGHT )
|
||||
f0 = GRID_HEIGHT - 1;
|
||||
if ( f0 >= gridHeight )
|
||||
f0 = gridHeight - 1;
|
||||
|
||||
if ( f0 < 0 )
|
||||
f0 = 0;
|
||||
|
||||
double f1 = ( data[lastPoint] );
|
||||
|
||||
f1 = ( f1 ) * GRID_HEIGHT / delta;
|
||||
f1 = ( f1 ) * gridHeight / delta;
|
||||
|
||||
if ( f1 >= GRID_HEIGHT )
|
||||
f1 = GRID_HEIGHT - 1;
|
||||
if ( f1 >= gridHeight )
|
||||
f1 = gridHeight - 1;
|
||||
|
||||
if ( f1 < 0 )
|
||||
f1 = 0;
|
||||
|
||||
int Y0 = GRID_HEIGHT - 1 - (int) f0;
|
||||
int Y1 = GRID_HEIGHT - 1 - (int) f1;
|
||||
int Y0 = gridHeight - 1 - (int) f0;
|
||||
int Y1 = gridHeight - 1 - (int) f1;
|
||||
|
||||
img.drawLine ( 0, Y1, 1, Y0, color );
|
||||
}
|
||||
@ -1773,7 +1853,7 @@ void CreateGainScale ()
|
||||
gainScaleSprite.deleteSprite();
|
||||
gainScaleSprite.setAttribute ( PSRAM_ENABLE, false );
|
||||
gainScaleSprite.setColorDepth ( 16 ); // Using 16 bit (RGB565) colors
|
||||
gainScaleSprite.createSprite(CHAR_WIDTH * 2, GRID_HEIGHT);
|
||||
gainScaleSprite.createSprite(CHAR_WIDTH * 2, gridHeight);
|
||||
gainScaleSprite.fillSprite(BLACK);
|
||||
gainScaleSprite.setPivot( 0, 0 );
|
||||
gainScaleSprite.setTextSize ( 1 );
|
||||
@ -1790,11 +1870,60 @@ void CreateGainScale ()
|
||||
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
gainScaleSprite.setCursor ( 0, 2 + ( DELTA_Y * i * 2 ));
|
||||
gainScaleSprite.setCursor ( 0, 2 + ( yDelta * i * 2 ));
|
||||
gainScaleSprite.print ( 50 - ( i * 10 ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "CreateGridScale" puts the decibel values for the main trace into a sprite for
|
||||
* display at the left side of the Bandscope grid.
|
||||
* The gainScaleSprite is reused as there in no need for a gain trace on the bandscope
|
||||
*
|
||||
* NOTE Due to temporary error in TFT_eSPI library the inverted colour is used
|
||||
* so TFT_BLUE actually results in TFT_GREEN!
|
||||
*/
|
||||
|
||||
void CreateGridScale ()
|
||||
{
|
||||
gainScaleSprite.deleteSprite();
|
||||
gainScaleSprite.setAttribute ( PSRAM_ENABLE, false );
|
||||
gainScaleSprite.setColorDepth ( 16 ); // Using 16 bit (RGB565) colors
|
||||
gainScaleSprite.createSprite(CHAR_WIDTH * 4, gridHeight);
|
||||
gainScaleSprite.fillSprite(BLACK);
|
||||
gainScaleSprite.setPivot( 0, 0 );
|
||||
gainScaleSprite.setTextSize ( 1 );
|
||||
gainScaleSprite.setTextColor ( TFT_WHITE );
|
||||
int w = gainScaleSprite.width();
|
||||
|
||||
// Serial.printf("Create gain scale - get sprite width %i \n", w);
|
||||
|
||||
if ( w != CHAR_WIDTH * 4 )
|
||||
{
|
||||
Serial.println ( "Error - no gain scale sprite" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Markers at every other line, there are 10 lines
|
||||
int16_t valueInterval = (setting.BandscopeMaxGrid - setting.BandscopeMinGrid) / yGrid * 2 ;
|
||||
int16_t v = setting.BandscopeMaxGrid;
|
||||
int16_t yoffset;
|
||||
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
if (i > 0)
|
||||
yoffset = -3;
|
||||
else
|
||||
yoffset = 0;
|
||||
gainScaleSprite.setCursor ( 0, yoffset + ( yDelta * i * 2 ));
|
||||
gainScaleSprite.printf ( "%4i", v );
|
||||
v = v - valueInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "ledcAnalogWrite" - Arduino like analogWrite used for PWM control of backlight.
|
||||
*
|
||||
|
@ -16,8 +16,23 @@
|
||||
|
||||
|
||||
#include "simpleSA_wifi.h" // WiFi definitions
|
||||
#include "Si4432.h" // Si4432 definitions
|
||||
#include "Cmd.h" // Command processing functions
|
||||
#include "si4432.h" // Si4432 definitions
|
||||
#include "cmd.h" // Command processing functions
|
||||
|
||||
/*
|
||||
* Variables to determine size of grid and waterfall
|
||||
* In Bandscope mode the grid is reduced. In future it may be possible to add
|
||||
* a waterfall to the main sweep, but not yet
|
||||
*/
|
||||
extern uint16_t gridHeight;
|
||||
extern uint16_t gridWidth;
|
||||
extern uint16_t yGrid; // no of grid divisions
|
||||
extern uint16_t yDelta; // no of points/division
|
||||
extern uint16_t xGrid;
|
||||
extern uint16_t displayPoints;
|
||||
extern uint16_t xDelta;
|
||||
extern uint16_t waterfallHeight;
|
||||
|
||||
|
||||
extern int bpfCount; // Number of elements in the bandpassFilters array
|
||||
extern int updateSidebar; // Flag to indicate no of clients has changed
|
||||
@ -376,7 +391,7 @@ void onGetScan ( AsyncWebServerRequest *request )
|
||||
response->print ( "<?xml version=\"1.0\" encoding=\"utf-16\"?>" );
|
||||
response->println ( "<Points>" );
|
||||
|
||||
for( int i = 0; i < DISPLAY_POINTS-1; i++ ) // For each data point
|
||||
for( int i = 0; i < displayPoints-1; i++ ) // For each data point
|
||||
{
|
||||
// Serial.printf ( "<Point F=\"%i\" RSSI=\"%i\"/> %i\n",myFreq[i], myData[i], i );
|
||||
response->printf ( "<P F=\"%i\" R=\"%i\"/>\n", myFreq[i], myData[i] );
|
||||
@ -394,8 +409,8 @@ void onGetScan ( AsyncWebServerRequest *request )
|
||||
|
||||
void onGetGainSweep ( AsyncWebServerRequest *request )
|
||||
{
|
||||
size_t bufferSize = JSON_ARRAY_SIZE ( DISPLAY_POINTS )
|
||||
+ JSON_OBJECT_SIZE ( 1 ) + DISPLAY_POINTS * JSON_OBJECT_SIZE ( 2 );
|
||||
size_t bufferSize = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ JSON_OBJECT_SIZE ( 1 ) + SCREEN_WIDTH * JSON_OBJECT_SIZE ( 2 );
|
||||
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse ( false, bufferSize );
|
||||
// response->addHeader ( "Server","ESP Async Web Server" );
|
||||
@ -407,7 +422,7 @@ void onGetGainSweep ( AsyncWebServerRequest *request )
|
||||
* Add the objects to the array
|
||||
*/
|
||||
|
||||
for ( int i = 0; i < DISPLAY_POINTS; i++ ) // For each data point
|
||||
for ( int i = 0; i < displayPoints; i++ ) // For each data point
|
||||
{
|
||||
JsonObject dataPoint = gainPoints.createNestedObject(); // Add an object to the array
|
||||
dataPoint["x"] = myFreq[i]/1000000.0; // set the x(frequency) value
|
||||
@ -426,14 +441,14 @@ void onGetGainSweep ( AsyncWebServerRequest *request )
|
||||
|
||||
void onGetSweep ( AsyncWebServerRequest *request )
|
||||
{
|
||||
size_t bufferSize = JSON_ARRAY_SIZE ( DISPLAY_POINTS )
|
||||
+ JSON_OBJECT_SIZE ( 14 ) + DISPLAY_POINTS * JSON_OBJECT_SIZE ( 2 );
|
||||
size_t bufferSize = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ JSON_OBJECT_SIZE ( 14 ) + SCREEN_WIDTH * JSON_OBJECT_SIZE ( 2 );
|
||||
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse ( false, bufferSize );
|
||||
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["dispPoints"] = DISPLAY_POINTS;
|
||||
root["dispPoints"] = displayPoints;
|
||||
root["start"] = setting.ScanStart / 1000.0;
|
||||
root["stop"] = setting.ScanStop / 1000.0;
|
||||
root["IF"] = setting.IF_Freq / 1000000.0;
|
||||
@ -454,7 +469,7 @@ void onGetSweep ( AsyncWebServerRequest *request )
|
||||
JsonArray Points = root.createNestedArray ( "Points" ); // Add Points array
|
||||
|
||||
|
||||
for ( int i = 0; i < DISPLAY_POINTS; i++ ) //For each data point
|
||||
for ( int i = 0; i < displayPoints; i++ ) //For each data point
|
||||
{
|
||||
JsonObject dataPoint = Points.createNestedObject(); // add an object to the array
|
||||
dataPoint["x"] = myFreq[i]/1000000.0; // set the x(frequency) value
|
||||
@ -477,7 +492,7 @@ void onGetSettings (AsyncWebServerRequest *request)
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["mType"] = "Settings";
|
||||
root["dispPoints"] = DISPLAY_POINTS;
|
||||
root["dispPoints"] = displayPoints;
|
||||
root["start"] = setting.ScanStart / 1000.0;
|
||||
root["stop"] = setting.ScanStop / 1000.0;
|
||||
root["IF"] = setting.IF_Freq / 1000000.0;
|
||||
@ -507,12 +522,12 @@ void onGetSettings (AsyncWebServerRequest *request)
|
||||
*/
|
||||
void pushSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( DISPLAY_POINTS )
|
||||
+ DISPLAY_POINTS*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["dispPoints"] = DISPLAY_POINTS;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = setting.ScanStart / 1000.0;
|
||||
jsonDocument["stop"] = setting.ScanStop / 1000.0;
|
||||
jsonDocument["IF"] = setting.IF_Freq / 1000000.0;
|
||||
@ -551,12 +566,12 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
*/
|
||||
void pushIFSweepSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( DISPLAY_POINTS )
|
||||
+ DISPLAY_POINTS*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["dispPoints"] = DISPLAY_POINTS;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = startFreq_IF / 1000.0;
|
||||
jsonDocument["stop"] = stopFreq_IF / 1000.0;
|
||||
jsonDocument["IF"] = sigFreq_IF / 1000000.0;
|
||||
@ -594,8 +609,8 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
*/
|
||||
void pushBandscopeSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( DISPLAY_POINTS )
|
||||
+ DISPLAY_POINTS*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "Arduino.h" // Basic Arduino definitions
|
||||
#include "simpleSA.h" // Program definitions
|
||||
#include "Si4432.h" // RF module definitions
|
||||
#include "si4432.h" // RF module definitions
|
||||
|
||||
#include <WiFi.h> // WiFi library
|
||||
#include <AsyncTCP.h>
|
||||
@ -71,11 +71,11 @@
|
||||
|
||||
extern settings_t setting;
|
||||
|
||||
extern uint8_t myData[DISPLAY_POINTS+1];
|
||||
extern uint8_t myStorage[DISPLAY_POINTS+1];
|
||||
extern uint8_t myActual[DISPLAY_POINTS+1];
|
||||
extern uint8_t myGain[DISPLAY_POINTS+1]; // M0WID addition to record preamp gain
|
||||
extern uint32_t myFreq[DISPLAY_POINTS+1]; // M0WID addition to store frequency for XML file
|
||||
extern uint8_t myData[SCREEN_WIDTH+1];
|
||||
extern uint8_t myStorage[SCREEN_WIDTH+1];
|
||||
extern uint8_t myActual[SCREEN_WIDTH+1];
|
||||
extern uint8_t myGain[SCREEN_WIDTH+1]; // M0WID addition to record preamp gain
|
||||
extern uint32_t myFreq[SCREEN_WIDTH+1]; // M0WID addition to store frequency for XML file
|
||||
|
||||
|
||||
extern WebSocketsServer webSocket; // Initiated in TinySA.ino
|
||||
|
360
ui.cpp
360
ui.cpp
@ -30,12 +30,12 @@
|
||||
#include <SPI.h> // SPI Bus handling library
|
||||
#include "simpleSA.h"
|
||||
#include "ui.h" // User interface definitions and prototypes
|
||||
#include "Cmd.h" // Command processing functions
|
||||
#include "cmd.h" // Command processing functions
|
||||
#include "preferences.h" // Save/recall functions
|
||||
#include <TFT_eSPI.h> // Display/Touch Screen header file
|
||||
#include "Menu.h" // "Menuitem" class definition
|
||||
#include "Marker.h" // Marker class definition
|
||||
#include "Si4432.h" // Si4432 class definition
|
||||
#include "menu.h" // "Menuitem" class definition
|
||||
#include "marker.h" // Marker class definition
|
||||
#include "si4432.h" // Si4432 class definition
|
||||
|
||||
|
||||
extern Marker marker[MARKER_COUNT]; // Array of markers
|
||||
@ -94,8 +94,8 @@ typedef struct {
|
||||
// to '6' below!
|
||||
int8_t digit_mode;
|
||||
int8_t current_trace; // 0 to 3 ???
|
||||
int32_t value; // For editing at numeric input area
|
||||
int32_t previous_value;
|
||||
double value; // For editing at numeric input area
|
||||
double previous_value;
|
||||
} uistat_t;
|
||||
|
||||
|
||||
@ -107,8 +107,8 @@ uistat_t uistat = {
|
||||
6, // digit - See note above
|
||||
0, // digit_mode
|
||||
0, // current_trace
|
||||
0, // value
|
||||
0 // previous_value
|
||||
0.0, // value
|
||||
0.0 // previous_value
|
||||
};
|
||||
|
||||
|
||||
@ -197,7 +197,8 @@ uint8_t operation_requested = OP_NONE; // No operations so far
|
||||
enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_FOCUS,
|
||||
KM_REFPOS, KM_ATTENUATION, KM_ACTUALPOWER, KM_IFFREQ, KM_PREAMP,
|
||||
KM_TUNE, KM_SGFREQ, KM_SGLEVEL, KM_SGLEVCAL, KM_IFSTART, KM_IFSTOP,
|
||||
KM_IFSIG, KM_TGOFFSET, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART, KM_BANDSCOPESPAN };
|
||||
KM_IFSIG, KM_TGOFFSET, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART,
|
||||
KM_WFMIN, KM_WFGAIN, KM_BANDSCOPELEVEL, KM_RXSPAN, KM_RXSIG, KM_RBW };
|
||||
|
||||
|
||||
/*
|
||||
@ -214,7 +215,8 @@ static const char * const keypad_mode_label[] =
|
||||
"START", "STOP", "CENTER", "SPAN", "FOCUS",
|
||||
"REFPOS", "ATTEN", "POWER", "IF FREQ", "PREAMP",
|
||||
"XTAL CAL", "SG FREQ", "dBm", "Max dBm", "IF START", "IF STOP",
|
||||
"IF Sig Freq", "TG OFFSET", "TG LO Drive", "TG IF Drive", "START", "SPAN"
|
||||
"IF Sig Freq", "TG OFFSET", "TG LO Drive", "TG IF Drive", "START",
|
||||
"WF MIN", "WF GAIN", "REF LEVEL", "RX SPAN", "RX Sig Freq", "RBW"
|
||||
};
|
||||
|
||||
|
||||
@ -272,10 +274,18 @@ static void menu_format_cb ( int item );
|
||||
static void menu_scale_cb ( int item );
|
||||
static void menu_sweep_cb ( int item );
|
||||
static void menu_IF_sweep_cb ( int item ); // M0WID added 3.0c
|
||||
static void menu_RX_sweep_cb ( int item );
|
||||
static void menu_recall_cb ( int item );
|
||||
static void menu_version_cb (int item );
|
||||
static void menu_generate_cb(int item); // WA2FZW - Added in M0WID's Version 05
|
||||
static void menu_Bandscope_cb ( int item ); // M0WID added 3.0f
|
||||
|
||||
// forward declarations for bandscope menu items
|
||||
static void menu_BandscopeStart_cb ( int item );
|
||||
static void menu_BandscopeRbw_cb ( int item );
|
||||
static void menu_BandscopeSpan_cb ( int item );
|
||||
static void menu_BandscopeLevel_cb ( int item );
|
||||
static void menu_WaterfallMin_cb ( int item );
|
||||
static void menu_WaterfallGain_cb ( int item );
|
||||
|
||||
static void menu_tracking_cb(int item); // M0WID - added in 3.0e
|
||||
static void menu_tg_offset_cb(int item); // M0WID - added in 3.0e
|
||||
@ -433,8 +443,9 @@ static Menuitem menu_mode[] = // Select mode menu
|
||||
{
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0LOW", menu_mode_cb ),
|
||||
Menuitem ( MT_FUNC, "\2SIG\0GEN", menu_mode_cb ),
|
||||
Menuitem ( MT_FUNC, "\2IF\0SWEEP", menu_mode_cb ),
|
||||
Menuitem ( MT_FUNC, "\2BAND\0SCOPE",menu_mode_cb ),
|
||||
Menuitem ( MT_FUNC, "\2IF\0SWEEP", menu_mode_cb ),
|
||||
Menuitem ( MT_FUNC, "\2RX\0SWEEP", menu_mode_cb ),
|
||||
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
@ -730,15 +741,51 @@ static Menuitem menu_IFsweep_top[] = // This is the main "IF_SWEEP" menu
|
||||
};
|
||||
|
||||
|
||||
static Menuitem menu_Bandscope_top[] = // This is the main "IF_SWEEP" menu
|
||||
static Menuitem menu_RXsweep_top[] = // This is the main "IF_SWEEP" menu
|
||||
{
|
||||
Menuitem ( MT_MENU, "MODE", menu_mode ),
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0START", menu_Bandscope_cb ),
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0SPAN", menu_Bandscope_cb ),
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0SPAN", menu_RX_sweep_cb ),
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0SIG", menu_RX_sweep_cb ),
|
||||
Menuitem ( MT_FUNC, "RBW", menu_RX_sweep_cb ),
|
||||
Menuitem ( MT_MENU, "REFERENCE", menu_refer ), // Select GPIO2 reference frequency
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
|
||||
|
||||
static Menuitem menu_BandscopeSpan[] = // Badscope Span settings
|
||||
{
|
||||
Menuitem ( MT_FUNC, "200kHz", menu_BandscopeSpan_cb ),
|
||||
Menuitem ( MT_FUNC, "400kHz", menu_BandscopeSpan_cb ),
|
||||
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
|
||||
|
||||
static Menuitem menu_BandscopeRBW[] = // Resolution bandwidth settings
|
||||
{
|
||||
Menuitem ( MT_FUNC, "2.6kHz", menu_BandscopeRbw_cb ), // In auto mode, there are many
|
||||
Menuitem ( MT_FUNC, "2.8kHz", menu_BandscopeRbw_cb ), // more available settings that
|
||||
Menuitem ( MT_FUNC, "3.1kHz", menu_BandscopeRbw_cb ), // are roughly the sweep range
|
||||
Menuitem ( MT_FUNC, "3.7kHz", menu_BandscopeRbw_cb ), // divided by 300.
|
||||
Menuitem ( MT_FUNC, "4.2kHz", menu_BandscopeRbw_cb ),
|
||||
Menuitem ( MT_FUNC, "5.4kHz", menu_BandscopeRbw_cb ),
|
||||
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
|
||||
|
||||
static Menuitem menu_Bandscope_top[] = // This is the main "IF_SWEEP" menu
|
||||
{
|
||||
Menuitem ( MT_MENU, "MODE", menu_mode ),
|
||||
Menuitem ( MT_FUNC, "\2SWEEP\0START", menu_BandscopeStart_cb ),
|
||||
Menuitem ( MT_MENU, "\2SWEEP\0SPAN", menu_BandscopeSpan ),
|
||||
Menuitem ( MT_MENU, "RBW", menu_BandscopeRBW ),
|
||||
Menuitem ( MT_FUNC, "\2REF\0LEVEL", menu_BandscopeLevel_cb ), // Set top line of the grid
|
||||
Menuitem ( MT_FUNC, "\2W'FALL\0MIN", menu_WaterfallMin_cb ),
|
||||
Menuitem ( MT_FUNC, "\2W'FALL\0GAIN", menu_WaterfallGain_cb ),
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* And last but not least the main menu!
|
||||
@ -1111,13 +1158,13 @@ void ShowSplash ( void )
|
||||
tft.setTextColor ( MAGENTA );
|
||||
|
||||
tft.setFreeFont ( &FreeSerifBoldItalic18pt7b ); // Select Free Serif 9 point font
|
||||
tft.drawString ( "TinySA for ESP32", 160, 20 );
|
||||
tft.drawString ( "simpleSA for ESP32", 160, 20 );
|
||||
tft.setTextColor ( WHITE );
|
||||
tft.setFreeFont ( &FreeSansBold9pt7b ); // Select Free Serif 9 point font
|
||||
tft.drawString ( "By WA2FZW, M0WID,", 160, 60 );
|
||||
tft.drawString ( "VK3PE and G3ZQC", 160, 80 );
|
||||
tft.drawString ( "Version 3.0", 160, 100 );
|
||||
tft.drawString ( "Original by Erik (PD0EK)", 160, 120 );
|
||||
tft.drawString ( "Version 0.01", 160, 100 );
|
||||
tft.drawString ( "Original tinySA by Erik (PD0EK)", 160, 120 );
|
||||
|
||||
tft.setTextDatum ( TL_DATUM ); // Back to default top left
|
||||
|
||||
@ -1161,15 +1208,22 @@ void menu_mode_cb ( int item )
|
||||
break;
|
||||
|
||||
case 2: // Set IF Sweep mode
|
||||
setMode(IF_SWEEP);
|
||||
setMode(BANDSCOPE);
|
||||
ui_mode_normal (); // No menu displayed
|
||||
break;
|
||||
|
||||
case 3: // Set IF Sweep mode
|
||||
setMode(BANDSCOPE);
|
||||
setMode(IF_SWEEP);
|
||||
ui_mode_normal (); // No menu displayed
|
||||
break;
|
||||
|
||||
case 4: // Set RX Sweep mode
|
||||
setMode(RX_SWEEP);
|
||||
ui_mode_normal (); // No menu displayed
|
||||
break;
|
||||
|
||||
}
|
||||
changedSetting = true;
|
||||
|
||||
}
|
||||
|
||||
@ -1395,7 +1449,7 @@ static void menu_tracking_cb (int item )
|
||||
}
|
||||
|
||||
/*
|
||||
* "menu_autosettings_cb" seems to set all the defaults then clears the menu
|
||||
* "menu_autosettings_cb" sets defaults then clears the menu
|
||||
* from the display.
|
||||
*
|
||||
* Modified in Version 2.5 by WA2FZW:
|
||||
@ -1432,13 +1486,13 @@ static void menu_touch_cb ( int item )
|
||||
{
|
||||
switch ( item )
|
||||
{
|
||||
case 0: // All these need symbols!
|
||||
case 0: // Touch calibrate
|
||||
touch_cal_exec ();
|
||||
request_to_redraw_grid ();
|
||||
draw_menu ();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 1: // Touch Draw test
|
||||
touch_draw_test ();
|
||||
request_to_redraw_grid ();
|
||||
draw_menu ();
|
||||
@ -1739,12 +1793,100 @@ static void menu_IF_sweep_cb ( int item )
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
static void menu_Bandscope_cb ( int item )
|
||||
|
||||
static void menu_RX_sweep_cb ( int item )
|
||||
{
|
||||
ui_mode_keypad ( item + KM_BANDSCOPESTART - 1 ); // item = 1 -> KM_BANDSCOPESTART, 2 -> KM_BANDSCOPESPAN
|
||||
ui_mode_keypad ( item + KM_RXSPAN - 1 ); // item = 1 -> KM_RXSPAN, 2 -> KM_RXSIG
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* *********************************************
|
||||
* BANDSCOPE MENU ITEMS
|
||||
* *********************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Handles the Bandscope RBW menu item.
|
||||
*
|
||||
*/
|
||||
static void menu_BandscopeRbw_cb ( int item )
|
||||
{
|
||||
const int rbwsel[] = { 0, 26, 28, 31, 37 , 42, 54 }; // Resolution bandwidth choices (in KHz * 10)
|
||||
|
||||
SetBandscopeRBW ( rbwsel[item] );
|
||||
menu_move_back ();
|
||||
ui_mode_normal ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the span for the bandscope
|
||||
*/
|
||||
static void menu_BandscopeSpan_cb ( int item )
|
||||
{
|
||||
switch ( item )
|
||||
{
|
||||
case 0: // 200kHz
|
||||
setting.BandscopeSpan = 200000;
|
||||
break;
|
||||
|
||||
case 1: // 400kHz
|
||||
setting.BandscopeSpan = 400000;
|
||||
break;
|
||||
}
|
||||
|
||||
WriteSettings ();
|
||||
menu_move_back ();
|
||||
ui_mode_normal ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the level of the top of the bandscope scale
|
||||
*/
|
||||
static void menu_BandscopeLevel_cb ( int item )
|
||||
{
|
||||
ui_mode_keypad ( KM_BANDSCOPELEVEL );
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the min for the bandscope waterfall colours
|
||||
*/
|
||||
static void menu_WaterfallMin_cb ( int item )
|
||||
{
|
||||
ui_mode_keypad ( KM_WFMIN );
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the gain for the bandscope waterfall colours
|
||||
*/
|
||||
static void menu_WaterfallGain_cb ( int item )
|
||||
{
|
||||
ui_mode_keypad ( KM_WFGAIN );
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set the start frequency of the bandscope sweep
|
||||
*/
|
||||
static void menu_BandscopeStart_cb ( int item )
|
||||
{
|
||||
ui_mode_keypad ( KM_BANDSCOPESTART );
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "ensure_selection" - Validates that a menu selection is valid
|
||||
*/
|
||||
@ -1982,7 +2124,13 @@ static const keypads_t * const keypads_mode_tbl[] =
|
||||
keypads_level, // KM_TGLO_DRIVE.....Tracking generator LO drive
|
||||
keypads_level, // KM_TGIF_DRIVE.....Tracking generator IF drive
|
||||
keypads_freq, // KM_BANDSCOPESTART.IF Sweep start frequency
|
||||
keypads_freq // KM_BANDSCOPESPAN..IF Sweep stop frequency
|
||||
keypads_integer, // KM_WFMIN..........Waterfall min level (RSSI)
|
||||
keypads_level, // KM_WFGAIN.........Waterfall Gain
|
||||
keypads_level, // KM_BANDSCOPELEVEL.Grid reference level
|
||||
keypads_freq, // KM_RXSPAN.........RX Sweep span frequency
|
||||
keypads_freq, // KM_RXSIG..........RX Sweep signal frequency
|
||||
keypads_freq // KM_RBW............RX Sweep RBW
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -2373,10 +2521,30 @@ static void fetch_numeric_target ( void )
|
||||
uistat.value = setting.BandscopeStart;
|
||||
break;
|
||||
|
||||
case KM_BANDSCOPESPAN:
|
||||
uistat.value = setting.BandscopeSpan;
|
||||
case KM_WFMIN:
|
||||
uistat.value = setting.WaterfallMin;
|
||||
break;
|
||||
|
||||
case KM_WFGAIN:
|
||||
uistat.value = setting.WaterfallGain;
|
||||
break;
|
||||
|
||||
case KM_BANDSCOPELEVEL:
|
||||
uistat.value = setting.BandscopeMaxGrid;
|
||||
break;
|
||||
|
||||
case KM_RXSPAN:
|
||||
uistat.value = GetRXsweepSpan();
|
||||
break;
|
||||
|
||||
case KM_RXSIG:
|
||||
uistat.value = GetRXsweepSigFreq();
|
||||
break;
|
||||
|
||||
case KM_RBW:
|
||||
uistat.value = (double)setting.Bandwidth10 / 10.0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
uint32_t x = uistat.value;
|
||||
@ -2388,7 +2556,7 @@ static void fetch_numeric_target ( void )
|
||||
uistat.digit = n;
|
||||
|
||||
uistat.previous_value = uistat.value;
|
||||
Serial.printf("uistat previous value %f\n", uistat.previous_value );
|
||||
// Serial.printf("uistat previous value %f\n", uistat.previous_value );
|
||||
}
|
||||
|
||||
|
||||
@ -2792,11 +2960,51 @@ static int keypad_click ( int key )
|
||||
break;
|
||||
|
||||
|
||||
case KM_BANDSCOPESPAN: // Bandscope span entered?
|
||||
SetBandscopeSpan (( int32_t ) value );
|
||||
case KM_WFMIN: // Bandscope span entered?
|
||||
if ( (value >= 0) && (value <= 200 ) )
|
||||
setting.WaterfallMin = ( int16_t )value ;
|
||||
else
|
||||
{
|
||||
DisplayError ( ERR_WARN,
|
||||
"Invalid minimum level!",
|
||||
"(0 - 200)",
|
||||
NULL,
|
||||
NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case KM_WFGAIN: // Bandscope span entered?
|
||||
if ( (value >= 0.1) && (value <= 4.0 ) )
|
||||
setting.WaterfallGain = value ;
|
||||
else
|
||||
{
|
||||
DisplayError ( ERR_WARN,
|
||||
"Invalid gain!",
|
||||
"(0.1 - 4)",
|
||||
NULL,
|
||||
NULL );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case KM_BANDSCOPELEVEL: // Bandscope level entered?
|
||||
SetBandscopeLevel (( int32_t ) value );
|
||||
break;
|
||||
|
||||
case KM_RXSPAN: // RX Span frequency entered?
|
||||
Serial.printf( "Value = %f\n", value );
|
||||
SetRXsweepSpan (( int32_t ) value );
|
||||
break;
|
||||
|
||||
case KM_RXSIG: // RX Signal frequency entered?
|
||||
SetRXsweepSigFreq (( int32_t ) value );
|
||||
break;
|
||||
|
||||
case KM_RBW: // RBW
|
||||
SetRBW (( int32_t ) (value * 10) );
|
||||
break;
|
||||
|
||||
} // End of "switch"
|
||||
|
||||
return KP_DONE; // Indicate finished with the keypad
|
||||
@ -2990,41 +3198,46 @@ void UiProcessTouch ( void )
|
||||
Serial.printf("x:%i y:%i\n", touch_x, touch_y);
|
||||
touch_wait_release ();
|
||||
|
||||
|
||||
// test to see if the touch is in the marker area
|
||||
if ( (touch_y < 10) && (touch_x < 160) )
|
||||
{
|
||||
marker[0].Toggle(); // marker 1
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 10) && (touch_x > 160) )
|
||||
{
|
||||
marker[2].Toggle(); // marker 3
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x < 160) )
|
||||
{
|
||||
marker[1].Toggle(); // marker 2
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x > 160) )
|
||||
{
|
||||
marker[3].Toggle(); // marker 4
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 40) && (touch_x > 30) )
|
||||
StartMarkerMenu();
|
||||
else if ( (touch_y > 210) && ( setting.Mode == SA_LOW_RANGE ) )
|
||||
StartSweepMenu();
|
||||
else if ( (touch_x < 30) && (touch_y < 60) && ( setting.Mode == SA_LOW_RANGE ) )
|
||||
StartRBWMenu();
|
||||
else if ( (touch_x < 30) && (touch_y > CHAR_HEIGHT * 20 ) && ( touch_y < CHAR_HEIGHT * 22 ) && ( setting.Mode == SA_LOW_RANGE ) )
|
||||
{
|
||||
SetSpur (!setting.Spur);
|
||||
return;
|
||||
}
|
||||
else if ( (touch_x < 30) && ( setting.Mode == SA_LOW_RANGE ) )
|
||||
StartDisplayMenu();
|
||||
/*
|
||||
* Some touchscreen areas have fast access to the submenu levels, depends on the mode
|
||||
*/
|
||||
if ( setting.Mode == SA_LOW_RANGE )
|
||||
{
|
||||
// test to see if the touch is in the marker area
|
||||
if ( (touch_y < 10) && (touch_x < 160) )
|
||||
{
|
||||
marker[0].Toggle(); // marker 1
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 10) && (touch_x > 160) )
|
||||
{
|
||||
marker[2].Toggle(); // marker 3
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x < 160) )
|
||||
{
|
||||
marker[1].Toggle(); // marker 2
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x > 160) )
|
||||
{
|
||||
marker[3].Toggle(); // marker 4
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 40) && (touch_x > 30) )
|
||||
StartMarkerMenu();
|
||||
else if ( touch_y > 210 )
|
||||
StartSweepMenu();
|
||||
else if ( (touch_x < 30) && (touch_y < 60) )
|
||||
StartRBWMenu();
|
||||
else if ( (touch_x < 30) && (touch_y > CHAR_HEIGHT * 20 ) && ( touch_y < CHAR_HEIGHT * 22 ) )
|
||||
{
|
||||
SetSpur (!setting.Spur);
|
||||
return;
|
||||
}
|
||||
else if ( (touch_x < 30) )
|
||||
StartDisplayMenu();
|
||||
}
|
||||
|
||||
selection = -1; // Switch menu mode
|
||||
bg = BLACK; // black background
|
||||
@ -3160,6 +3373,21 @@ void ResetIFsweepMenuStack (void)
|
||||
ui_mode_normal ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Resets the menu stack to root level for RX_SWEEP mode
|
||||
*/
|
||||
void ResetRXsweepMenuStack (void)
|
||||
{
|
||||
tft.unloadFont();
|
||||
selection = -1; // Switch menu mode
|
||||
menu_current_level = 0;
|
||||
menu_stack[0] = menu_RXsweep_top;
|
||||
menu_stack[1] = NULL;
|
||||
menu_stack[2] = NULL;
|
||||
menu_stack[3] = NULL;
|
||||
if (ui_mode != UI_NORMAL)
|
||||
ui_mode_normal ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user