commit
f36f478363
@ -237,14 +237,8 @@ static uint16_t chunkIndex;
|
||||
|
||||
if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan
|
||||
{
|
||||
jsonDocument.clear ();
|
||||
chunkIndex = 0;
|
||||
|
||||
jsonDocument["PreAmp"] = setting.PreampGain;
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = 0;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
initChunkSweepDoc (autoSweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
@ -395,12 +389,8 @@ static uint16_t chunkIndex;
|
||||
if ( ( chunkIndex >= wiFiPoints ) || !jsonDocInitialised ) // Start new jSon document
|
||||
{
|
||||
chunkIndex = 0;
|
||||
jsonDocument.clear();
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = autoSweepStep;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
Points = jsonDocument.createNestedArray ("Points" ); // Add Points array
|
||||
initChunkSweepDoc (autoSweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
}
|
||||
|
19
IFsweep.ino
19
IFsweep.ino
@ -120,6 +120,7 @@ static uint16_t chunkIndex;
|
||||
} // initSweep || changedSetting
|
||||
|
||||
autoSweepStep = 0; // Set the step counter to zero
|
||||
sweepStep = 0;
|
||||
autoSweepFreq = startFreq_IF; // Set the start frequency.
|
||||
|
||||
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
|
||||
@ -142,24 +143,16 @@ static uint16_t chunkIndex;
|
||||
|
||||
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);
|
||||
initChunkSweepDoc (sweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
|
||||
else
|
||||
jsonDocInitialised = false;
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
sweepStep = 0;
|
||||
startFreq = startFreq_IF + sigFreq_IF; // Start freq for the LO
|
||||
stopFreq = stopFreq_IF + sigFreq_IF; // Stop freq for the LO
|
||||
|
||||
@ -315,12 +308,8 @@ static uint16_t chunkIndex;
|
||||
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
|
||||
initChunkSweepDoc (sweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
}
|
||||
|
19
RXsweep.ino
19
RXsweep.ino
@ -126,6 +126,7 @@ static uint16_t chunkIndex;
|
||||
} // initSweep || changedSetting
|
||||
|
||||
autoSweepStep = 0; // Set the step counter to zero
|
||||
sweepStep = 0;
|
||||
autoSweepFreq = startFreq_RX; // Set the start frequency.
|
||||
|
||||
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
|
||||
@ -148,24 +149,16 @@ static uint16_t chunkIndex;
|
||||
|
||||
if ( numberOfWebsocketClients > 0 ) // Start off the json document for the scan
|
||||
{
|
||||
jsonDocument.clear ();
|
||||
chunkIndex = 0;
|
||||
|
||||
jsonDocument["PreAmp"] = setting.PreampGain;
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = 0;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
initChunkSweepDoc (sweepStep);
|
||||
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
|
||||
|
||||
@ -322,12 +315,8 @@ static uint16_t chunkIndex;
|
||||
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
|
||||
initChunkSweepDoc (sweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
}
|
||||
|
90
SigLo.ino
90
SigLo.ino
@ -107,6 +107,11 @@ void initSigLow()
|
||||
|
||||
oldFreq = 0; // Force write of frequency on first loop
|
||||
|
||||
#ifdef USE_WIFI
|
||||
if ( numberOfWebsocketClients > 0 )
|
||||
pushSigGenSettings ();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -119,6 +124,10 @@ void initSigLow()
|
||||
void doSigGenLow ()
|
||||
{
|
||||
static uint32_t oldIF; // to store the current IF
|
||||
static uint16_t oldSigGenOutputOn;
|
||||
float p; // temporary variable for slider percent
|
||||
static uint16_t sliderRange = ATTENUATOR_RANGE + RX_SI4432_MAX_DRIVE * 3;
|
||||
|
||||
|
||||
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
|
||||
|
||||
@ -127,6 +136,29 @@ void doSigGenLow ()
|
||||
showUpDownButtons = 1;
|
||||
#endif
|
||||
|
||||
if (changedSetting) {
|
||||
// calculate required drive and attenuator settings
|
||||
// keep drive as high as possible so nasties are attenuated
|
||||
uint16_t sgRXDrive = RX_SI4432_MAX_DRIVE;
|
||||
uint16_t attenuation = sigGenSetting.Calibration - sigGenSetting.Power;
|
||||
if (attenuation > ATTENUATOR_RANGE )
|
||||
{
|
||||
int16_t diff = attenuation - ATTENUATOR_RANGE;
|
||||
sgRXDrive = RX_SI4432_MAX_DRIVE - (int16_t)( (diff-1)/3 ) - 1 ;
|
||||
attenuation = ATTENUATOR_RANGE - 2 + (diff-1)%3;
|
||||
}
|
||||
SetSGRxDrive(sgRXDrive);
|
||||
att.SetAtten(attenuation);
|
||||
Serial.printf("sigGenLow - rxDrive set to %i, attenuation set to %i, cal is %i\n", sgRXDrive, attenuation, sigGenSetting.Calibration);
|
||||
|
||||
#ifdef USE_WIFI
|
||||
if ( numberOfWebsocketClients > 0 )
|
||||
pushSigGenSettings ();
|
||||
#endif
|
||||
|
||||
changedSetting = false;
|
||||
}
|
||||
|
||||
|
||||
// Get current touch state and coordinates
|
||||
boolean pressed = tft.getTouch(&t_x, &t_y); // Just uses standard TFT_eSPI function as not bothered about speed
|
||||
@ -154,6 +186,7 @@ void doSigGenLow ()
|
||||
case 5:
|
||||
case 6:
|
||||
incrementFreq( pow(10, 8-b) );
|
||||
changedSetting=true;
|
||||
break;
|
||||
|
||||
case 7: // Decrement buttons
|
||||
@ -164,6 +197,7 @@ void doSigGenLow ()
|
||||
case 12:
|
||||
case 13:
|
||||
decrementFreq( pow(10, 15-b) );
|
||||
changedSetting=true;
|
||||
break;
|
||||
|
||||
case 14: // Return to SAlo mode
|
||||
@ -172,21 +206,6 @@ void doSigGenLow ()
|
||||
|
||||
case 15: // toggle the output on/off
|
||||
sigGenOutputOn = !sigGenOutputOn;
|
||||
if (sigGenOutputOn) {
|
||||
SetRX(3); // both LO and RX in transmit. Output levels have been set in the init function
|
||||
key[b].drawButton(true, sig_keys[b].activeText);
|
||||
tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y);
|
||||
tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR);
|
||||
tft.setTextColor(TFT_GREEN, SIG_BACKGROUND_COLOR );
|
||||
tft.print(" ON");
|
||||
} else {
|
||||
SetRX(1); // Both in receive
|
||||
key[b].drawButton(false, sig_keys[b].text);
|
||||
tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y);
|
||||
tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR);
|
||||
tft.setTextColor(TFT_WHITE, SIG_BACKGROUND_COLOR );
|
||||
tft.print("OFF");
|
||||
}
|
||||
break;
|
||||
|
||||
case 16: // launch menu
|
||||
@ -224,6 +243,33 @@ void doSigGenLow ()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if state changed - can change from command or from wifi
|
||||
switch (b) {
|
||||
case 15: // On/Off button
|
||||
if (oldSigGenOutputOn != sigGenOutputOn)
|
||||
{
|
||||
if (sigGenOutputOn) {
|
||||
SetRX(3); // both LO and RX in transmit. Output levels have been set in the init function
|
||||
key[b].drawButton(true, sig_keys[b].activeText);
|
||||
tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y);
|
||||
tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR);
|
||||
tft.setTextColor(TFT_GREEN, SIG_BACKGROUND_COLOR );
|
||||
tft.print(" ON");
|
||||
} else {
|
||||
SetRX(1); // Both in receive
|
||||
key[b].drawButton(false, sig_keys[b].text);
|
||||
tft.setCursor(sig_keys[b].x + 30, sig_keys[b].y);
|
||||
tft.fillRect(sig_keys[b].x + 30, sig_keys[b].y, sig_keys[b].x + 60, sig_keys[b].y + 10, SIG_BACKGROUND_COLOR);
|
||||
tft.setTextColor(TFT_WHITE, SIG_BACKGROUND_COLOR );
|
||||
tft.print("OFF");
|
||||
}
|
||||
changedSetting = true;
|
||||
}
|
||||
break;
|
||||
|
||||
} // on of state change switch
|
||||
|
||||
|
||||
} // end of keys loop
|
||||
|
||||
@ -232,12 +278,15 @@ void doSigGenLow ()
|
||||
// Check if slider touched
|
||||
if ( sliderPressed( pressed, t_x, t_y) )
|
||||
{
|
||||
float p = sliderPercent( t_x ); // position of slider in %
|
||||
float pwr = p * (ATTENUATOR_RANGE)/100.0 + sigGenSetting.Calibration - ATTENUATOR_RANGE;
|
||||
p = sliderPercent( t_x ); // position of slider in %
|
||||
float pwr = p * (sliderRange)/100.0 + sigGenSetting.Calibration - sliderRange;
|
||||
|
||||
drawSlider ( SLIDER_X, SLIDER_Y, p, pwr, "dBm" );
|
||||
att.SetAtten ( ( 100.0 - p ) / 100.0 * ATTENUATOR_RANGE ); // set attenuator to give required output
|
||||
sigGenSetting.Power = pwr;
|
||||
changedSetting = true;
|
||||
} else {
|
||||
p = ( sigGenSetting.Power - (sigGenSetting.Calibration - sliderRange) ) * 100.0 / sliderRange;
|
||||
drawSlider ( SLIDER_X, SLIDER_Y, p, sigGenSetting.Power, "dBm" );
|
||||
}
|
||||
|
||||
|
||||
@ -266,12 +315,15 @@ void doSigGenLow ()
|
||||
if (sigGenOutputOn)
|
||||
{
|
||||
delayMicroseconds(300);
|
||||
SetRX(3);
|
||||
SetRX(3); // both LO and RX in tx mode
|
||||
}
|
||||
changedSetting = true;
|
||||
}
|
||||
|
||||
oldFreq = sigGenSetting.Frequency;
|
||||
oldIF = setting.IF_Freq;
|
||||
oldSigGenOutputOn = sigGenOutputOn;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
46
SweepLo.ino
46
SweepLo.ino
@ -73,6 +73,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
|
||||
static uint32_t tgIF; // Track gen IF - SA IF plus any offset if both SI4432 defined
|
||||
|
||||
|
||||
|
||||
@ -181,10 +182,20 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
tg_lo.RxMode();
|
||||
#endif
|
||||
|
||||
#if defined(SI_TG_IF_CS) && defined(SI_TG_LO_CS)
|
||||
if (tgLO_OK && tgIF_OK && (trackGenSetting.Mode == 2) ) // tracking gen as signal generator
|
||||
{
|
||||
tg_if.SetFrequency ( setting.IF_Freq + trackGenSetting.Offset );
|
||||
tg_lo.SetFrequency ( setting.IF_Freq + trackGenSetting.Offset + trackGenSetting.Frequency );
|
||||
tg_lo.TxMode ( trackGenSetting.LO_Drive ); // Set tracking generator LO on
|
||||
tg_if.TxMode ( trackGenSetting.IF_Drive ); // Set tracking generator IF on
|
||||
}
|
||||
#endif
|
||||
|
||||
} // initSweep || changedSetting
|
||||
|
||||
autoSweepStep = 0; // Set the step counter to zero
|
||||
sweepStep = 0;
|
||||
autoSweepFreq = setting.ScanStart; // Set the start frequency.
|
||||
|
||||
nextPointFreq = autoSweepFreq + autoSweepFreqStep;
|
||||
@ -207,6 +218,12 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
tempIF = offsetIF;
|
||||
}
|
||||
|
||||
// track gen IF follows LO if only one SI4432, otherwise its offset by an amount to reduce blow by
|
||||
if (tgLO_OK)
|
||||
tgIF = tempIF + trackGenSetting.Offset;
|
||||
else
|
||||
tgIF = tempIF;
|
||||
|
||||
|
||||
|
||||
spurToggle = !spurToggle;
|
||||
@ -225,7 +242,7 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
|
||||
#ifdef SI_TG_IF_CS
|
||||
if (tgIF_OK && (trackGenSetting.Mode == 1) )
|
||||
tg_if.SetFrequency ( tempIF + trackGenSetting.Offset ); // Set tracking generator IF for the sweep
|
||||
tg_if.SetFrequency ( tgIF ); // Set tracking generator IF for the sweep
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -233,13 +250,11 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
if (tgLO_OK && (trackGenSetting.Mode == 1) )
|
||||
tg_lo.SetFrequency ( tempIF + autoSweepFreq + trackGenSetting.Offset ); // Set tracking generator LO
|
||||
tg_lo.SetFrequency ( tgIF + autoSweepFreq ); // Set tracking generator LO
|
||||
#endif
|
||||
|
||||
setFreqMicros = micros(); // Store the time the frequency was changed
|
||||
|
||||
// if (trackGenSetting.Mode == 1) // debug
|
||||
// Serial.printf("tglo start %i at %i\n", tg_lo.GetFrequency(), setFreqMicros);
|
||||
|
||||
/*
|
||||
* Actual frequency in the SI4432 is rounded and is limited by the possible resolution
|
||||
@ -253,22 +268,15 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
{
|
||||
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);
|
||||
initChunkSweepDoc (sweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
|
||||
else
|
||||
jsonDocInitialised = false;
|
||||
|
||||
#endif // #ifdef USE_WIFI
|
||||
|
||||
sweepStep = 0;
|
||||
startFreq = setting.ScanStart + tempIF; // Start freq for the LO
|
||||
stopFreq = setting.ScanStop + tempIF; // Stop freq for the LO
|
||||
|
||||
@ -438,7 +446,11 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
{
|
||||
Serial.println("webSocketTimeout");
|
||||
Serial.println(wsBuffer);
|
||||
numberOfWebsocketClients = 0;
|
||||
websocketFailCount++;
|
||||
if (websocketFailCount > 2)
|
||||
numberOfWebsocketClients = 0;
|
||||
} else {
|
||||
websocketFailCount = 0; // reset if OK
|
||||
}
|
||||
// Serial.print("j");
|
||||
}
|
||||
@ -450,12 +462,8 @@ static uint32_t offsetIF; // IF frequency offset by half the bandwidth to pos
|
||||
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
|
||||
initChunkSweepDoc (sweepStep);
|
||||
Points = jsonDocument.createNestedArray ( "Points" ); // Add Points array
|
||||
jsonDocInitialised = true;
|
||||
}
|
||||
}
|
||||
|
177
cmd.cpp
177
cmd.cpp
@ -106,6 +106,7 @@ extern uint32_t colourTest;
|
||||
|
||||
extern Marker marker[MARKER_COUNT]; // Array of marker objects
|
||||
|
||||
extern uint16_t sigGenOutputOn; // signal generator state - 0 = off, 1 = on
|
||||
|
||||
/*
|
||||
* Functions still in the main program file. Maybe some need to move here?
|
||||
@ -183,6 +184,13 @@ extern uint8_t dBmToRSSI ( double dBm );
|
||||
{ "RXSWEEP", MSG_RX_SWEEP }, // Set RX Sweep Mode
|
||||
{ "RXSIGNAL", MSG_RXSIGNAL }, // IF sweep signal frequency
|
||||
{ "EXTGAIN", MSG_EXTGAIN }, // External gain or attenuation
|
||||
{ "SGON", MSG_SGON }, // turn on signal generator output
|
||||
{ "SGOFF", MSG_SGOFF }, // turn off signal generator output
|
||||
{ "SGFREQ", MSG_SGFREQ }, // Set Signal Generator Frequency
|
||||
{ "TRACKON", MSG_TGON }, // turn on tracking generator output
|
||||
{ "TRACKOFF", MSG_TGOFF }, // turn off tracking generator output
|
||||
{ "TRACKSIG", MSG_TGSIG }, // turn off tracking generator output
|
||||
{ "TGFREQ", MSG_TGFREQ }, // Set Track gen freq for sig gen mode
|
||||
{ "", MSG_NONE } // Unrecognized command
|
||||
};
|
||||
|
||||
@ -196,7 +204,7 @@ int msgCount = ELEMENTS ( msgTable);
|
||||
|
||||
void ShowMenu ()
|
||||
{
|
||||
Serial.printf ( "\nTiny Spectrum Analyzer Version %s - User Commands:\n\n", PROGRAM_VERSION );
|
||||
Serial.printf ( "\nsimpleSA Spectrum Analyzer %s - User Commands:\n\n", PROGRAM_VERSION );
|
||||
Serial.println ( "Sweep Settings:\n" );
|
||||
|
||||
Serial.print ( " START.........Sweep start frequency, currently: " );
|
||||
@ -248,25 +256,53 @@ void ShowMenu ()
|
||||
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: " );
|
||||
Serial.println ( setting.Drive );
|
||||
Serial.println ( "\nSignal Generator Commands:\n" );
|
||||
|
||||
Serial.println ( " SGON..........Turn on signal generator output" );
|
||||
Serial.print ( " SGOFF.........Turn off signal generator output; currently " );
|
||||
Serial.println ( sigGenOutputOn );
|
||||
|
||||
Serial.print ( " SGFREQ........Signal Generator frequency, currently: " );
|
||||
Serial.println ( FormatFrequency ( sigGenSetting.Frequency ));
|
||||
|
||||
Serial.print ( " SGLODRIVE.....Local oscillator drive level in signal generator mode [0 to 7]; currently: " );
|
||||
Serial.println ( sigGenSetting.LO_Drive );
|
||||
|
||||
Serial.print ( " SGRXDRIVE.....Local oscillator drive level in signal generator mode [0 to 7]; currently: " );
|
||||
Serial.print ( " SGRXDRIVE.....RX SI4432 oscillator drive level in signal generator mode [0 to ");
|
||||
Serial.print ( RX_SI4432_MAX_DRIVE );
|
||||
Serial.print ( "]; currently: " );
|
||||
Serial.println ( sigGenSetting.RX_Drive );
|
||||
|
||||
#ifdef SI_TG_IF_CS
|
||||
Serial.println ( "\nTracking Generator Commands:\n" );
|
||||
|
||||
Serial.println ( " TRACKON.......Turn on tracking generator output" );
|
||||
#ifdef SI_TG_LO_CS
|
||||
Serial.println ( " TRACKSIG......Turn on tracking generator signal generator output" );
|
||||
#endif
|
||||
Serial.print ( " TRACKOFF......Turn off tracking generator output; currently " );
|
||||
Serial.println ( trackGenSetting.Mode );
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
Serial.print ( " TGLODRIVE.....Local oscillator drive level in tracking generator mode [0 to 7]; currently: " );
|
||||
Serial.println ( trackGenSetting.LO_Drive );
|
||||
|
||||
#endif
|
||||
Serial.print ( " TGIFDRIVE.....Local oscillator drive level in tracking generator mode [0 to 7]; currently: " );
|
||||
Serial.println ( trackGenSetting.IF_Drive );
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
Serial.print ( " TGOFFSET......Tracking generator offset from SA IF; currently: " );
|
||||
Serial.println ( trackGenSetting.Offset );
|
||||
Serial.print ( " TGFREQ........Tracking generator signal generator frequency; currently: " );
|
||||
Serial.println ( trackGenSetting.Frequency );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
Serial.println ( "\nOther Commands:\n" );
|
||||
|
||||
Serial.print ( " DRIVE.........Local oscillator drive level [0 to 7]; currently: " );
|
||||
Serial.println ( setting.Drive );
|
||||
|
||||
Serial.println ( " SAVE .........Save the current scan configuration [0 to 4]" );
|
||||
|
||||
@ -759,6 +795,29 @@ uint8_t reg69; // Ditto
|
||||
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Signal Generator On/Off commands
|
||||
*
|
||||
*/
|
||||
case MSG_SGON:
|
||||
SetSGState(1);
|
||||
return true;
|
||||
|
||||
case MSG_SGOFF:
|
||||
SetSGState(0);
|
||||
return true;
|
||||
|
||||
case MSG_SGFREQ:
|
||||
if ( dataLen != 0 ) // Frequency specified?
|
||||
{
|
||||
freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency
|
||||
SetSGFreq (freq1);
|
||||
}
|
||||
Serial.printf ( "Signal Generator frequency: %i\n", FormatFrequency ( freq1 ));
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The "SGLODRIVE" command sets the local oscillator "drive" level in signal generator mode.
|
||||
@ -769,7 +828,7 @@ uint8_t reg69; // Ditto
|
||||
tempValue = atoi ( dataBuff ); // Yes, convert to a number
|
||||
|
||||
if (( tempValue < MIN_DRIVE ) || ( tempValue > MAX_DRIVE ))
|
||||
Serial.printf ( "Invalid drive specification: %d\n", tempValue );
|
||||
Serial.printf ( "Invalid LO drive: %d\n", tempValue );
|
||||
else // Set the transmitter drive level
|
||||
SetSGLoDrive ( tempValue ); // "SetSGLoDrive" saves the settings
|
||||
}
|
||||
@ -781,17 +840,17 @@ uint8_t reg69; // Ditto
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The "SGLODRIVE" command sets the receiver (IF) oscillator "drive" level in signal generator mode.
|
||||
* The "SGRXDRIVE" command sets the receiver (IF) oscillator "drive" level in signal generator mode.
|
||||
*/
|
||||
case MSG_SG_RX_DRIVE:
|
||||
if ( dataLen != 0 ) // Drive level specified?
|
||||
{
|
||||
tempValue = atoi ( dataBuff ); // Yes, convert to a number
|
||||
|
||||
if (( tempValue < MIN_DRIVE ) || ( tempValue > MAX_DRIVE ))
|
||||
Serial.printf ( "Invalid drive specification: %d\n", tempValue );
|
||||
if (( tempValue < MIN_DRIVE ) || ( tempValue > RX_SI4432_MAX_DRIVE ))
|
||||
Serial.printf ( "Invalid RX drive: %d - (%d-%d)\n", tempValue, MIN_DRIVE, RX_SI4432_MAX_DRIVE );
|
||||
else // Set the transmitter drive level
|
||||
SetSGRxDrive ( tempValue ); // "SetTGRxDrive" saves the settings
|
||||
SetSGRxDrive ( tempValue ); // "SetSGRxDrive" saves the settings
|
||||
}
|
||||
|
||||
Serial.printf ( "SigGen RX Drive: %d (+%udBm)\n", sigGenSetting.RX_Drive, driveLevel[sigGenSetting.RX_Drive] );
|
||||
@ -800,8 +859,26 @@ uint8_t reg69; // Ditto
|
||||
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Tracking Generator On/Off commands
|
||||
*
|
||||
*/
|
||||
case MSG_TGON:
|
||||
SetTracking(1);
|
||||
return true;
|
||||
|
||||
case MSG_TGOFF:
|
||||
SetTracking(0);
|
||||
return true;
|
||||
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
|
||||
case MSG_TGSIG:
|
||||
SetTracking(2);
|
||||
return true;
|
||||
|
||||
|
||||
/*
|
||||
* The "TGLODRIVE" command sets the local oscillator "drive" level in tracking generator mode.
|
||||
* (only valid if two SI4432 used for the tracking generator)
|
||||
@ -1578,6 +1655,14 @@ uint8_t reg69; // Ditto
|
||||
Serial.printf ( "Tracking Generator IF offset: %i\n", trackGenSetting.Offset ); // sort out signed version of format frequency!!!!!!!!!!!!!!!!!!!
|
||||
return true;
|
||||
|
||||
case MSG_TGFREQ:
|
||||
if ( dataLen != 0 ) // Frequency specified?
|
||||
{
|
||||
freq1 = ParseFrequency ( dataBuff ); // Yes, get new frequency
|
||||
SetTGFreq (freq1);
|
||||
}
|
||||
Serial.printf ( "Tracking Signal Generator frequency: %i\n", FormatFrequency ( trackGenSetting.Frequency ));
|
||||
return true;
|
||||
|
||||
|
||||
/*
|
||||
@ -2295,6 +2380,7 @@ void RequestSetPowerLevel ( float o )
|
||||
|
||||
/*
|
||||
* "SetPowerLevel"
|
||||
* Adjusts displayed power to match the actual input signal power - calibration function
|
||||
*/
|
||||
|
||||
void SetPowerLevel ( double o )
|
||||
@ -2433,6 +2519,32 @@ int oldLevel = setting.Drive;
|
||||
}
|
||||
|
||||
|
||||
/* Set SGFreq sets the signal generator Frequency
|
||||
* Signal generator frequency may change frequently, so don't save the setting
|
||||
* Settings are saved when leaving the mode
|
||||
* parameter is in Hz
|
||||
*/
|
||||
bool SetSGFreq (uint32_t f)
|
||||
{
|
||||
if ( ( f >= MIN_SIGLO_FREQ ) && ( f <= MAX_SIGLO_FREQ ) )
|
||||
{
|
||||
sigGenSetting.Frequency = f;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sig gen state is not saved - always want to start in off state
|
||||
*/
|
||||
|
||||
void SetSGState (uint16_t s)
|
||||
{
|
||||
sigGenOutputOn = s;
|
||||
}
|
||||
|
||||
/*
|
||||
* "SetSGLoDrive" sets the transmitter max output level in signal generator mode.
|
||||
*
|
||||
@ -2479,13 +2591,16 @@ int oldLevel = sigGenSetting.LO_Drive;
|
||||
* 1 => +2dBm 5 => +14dBm
|
||||
* 2 => +5dBm 6 => +17dBm
|
||||
* 3 => +8dBm 7 => +20dBm
|
||||
* Note the power limits of the B3555 SAW filter is 10dBm
|
||||
* RX_SI4432_MAX_DRIVE is set in my_SA.h to suit the attenuator pad and losses
|
||||
* in your build.
|
||||
*/
|
||||
|
||||
void SetSGRxDrive ( uint8_t level )
|
||||
{
|
||||
int oldLevel = sigGenSetting.RX_Drive;
|
||||
|
||||
if (( level < 0 ) || ( level > 7 ))
|
||||
if (( level < 0 ) || ( level > RX_SI4432_MAX_DRIVE ))
|
||||
return;
|
||||
|
||||
else
|
||||
@ -2503,6 +2618,20 @@ int oldLevel = sigGenSetting.RX_Drive;
|
||||
}
|
||||
|
||||
|
||||
void SetSGPower ( int16_t dBm )
|
||||
{
|
||||
// Add algorithm to set attenuator and IF drive level
|
||||
// initially limit to just set attenuator
|
||||
|
||||
if ( dBm > sigGenSetting.Calibration )
|
||||
dBm = sigGenSetting.Calibration;
|
||||
if ( dBm < (sigGenSetting.Calibration - ATTENUATOR_RANGE - RX_SI4432_MAX_DRIVE * 3) )
|
||||
dBm = sigGenSetting.Calibration - ATTENUATOR_RANGE;
|
||||
|
||||
sigGenSetting.Power = dBm;
|
||||
changedSetting = true;
|
||||
}
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
/*
|
||||
* "SetTGLoDrive" sets the transmitter max output level for the tracking generator.
|
||||
@ -2618,6 +2747,28 @@ int32_t GetTGOffset ( )
|
||||
return trackGenSetting.Offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the Track Gen frequency - M0WID addition
|
||||
*/
|
||||
|
||||
bool SetTGFreq ( int32_t freq )
|
||||
{
|
||||
int32_t oldFreq = trackGenSetting.Frequency;
|
||||
|
||||
if (( freq < MIN_SIGLO_FREQ ) || ( freq > MAX_SIGLO_FREQ )) // If out of limits
|
||||
return false; // Don't change it
|
||||
|
||||
trackGenSetting.Frequency = freq;
|
||||
|
||||
if ( oldFreq != trackGenSetting.Frequency )
|
||||
{
|
||||
changedSetting = true;
|
||||
WriteTrackGenSettings ();
|
||||
}
|
||||
|
||||
return true; // Frequency was good
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* "SetSweepStart" and "GetSweepStart" were added in Version 2.3. They used to be in
|
||||
|
11
cmd.h
11
cmd.h
@ -78,6 +78,13 @@
|
||||
#define MSG_RX_SWEEP 49 // Set the RX Sweep Mode
|
||||
#define MSG_RXSIGNAL 50 // Set frequency of injected signal for IF Sweep
|
||||
#define MSG_EXTGAIN 51 // Set external gain or attenuation
|
||||
#define MSG_SGON 52 // Turn Signal Generator output on
|
||||
#define MSG_SGOFF 53 // Turn Signal Generator output off
|
||||
#define MSG_SGFREQ 54 // Set Signal Generator Frequency
|
||||
#define MSG_TGON 55 // Turn Tracking Generator output on
|
||||
#define MSG_TGOFF 56 // Turn Tracking Generator output off
|
||||
#define MSG_TGFREQ 57 // Set Track Gen frequency for sig gen mode
|
||||
#define MSG_TGSIG 58 // Set Track Gen sig gen mode
|
||||
|
||||
#define MSG_COLOURTEST 99 // test of waterfall colours - remove this when done!
|
||||
|
||||
@ -139,13 +146,17 @@ void SetGenerate ( int8_t g ); // Puts the unit into or out of signal generat
|
||||
bool SetIFFrequency ( int32_t f ); // Sets the IF frequency
|
||||
|
||||
void SetLoDrive ( uint8_t level ); // Sets LO Si4432 output level
|
||||
void SetSGState (uint16_t s);
|
||||
bool SetSGFreq ( uint32_t freq); // set signal generator frequency - returns false if invalid
|
||||
void SetSGLoDrive ( uint8_t level );
|
||||
void SetSGRxDrive ( uint8_t level );
|
||||
void SetSGPower ( int16_t dBm ); // Set signal generator attenuator and drive levels
|
||||
|
||||
void SetTracking ( int8_t m ); // set tracking generator mode
|
||||
void SetTGLoDrive ( uint8_t level ); // set tracking generator drive
|
||||
void SetTGIfDrive ( uint8_t level );
|
||||
bool SetTGOffset ( int32_t offset); // set tracking generator offset - returns false if invalid
|
||||
bool SetTGFreq ( int32_t freq); // set tracking generator freq for sig gen mode - returns false if invalid
|
||||
int32_t GetTGOffset (void );
|
||||
void SetTGPower ( int16_t dBm ); // Set TG attenuator and drive levels
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>[TinySA]</title>
|
||||
<title>[simpleSA]</title>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" media="all" />
|
||||
|
||||
<meta charset="UTF-8">
|
||||
@ -46,18 +46,18 @@
|
||||
<h1>About</h1>
|
||||
|
||||
<p style="max-width:700px;">
|
||||
The TinySA has been developed by Erik PD0EK.
|
||||
This version has been adapted to run on the ESP32 DevKit module by Dave M0WID and John WA2FZW.
|
||||
This simpleSA running on an ESP32 has been adapted by Dave M0WID and John WA2FZW.<br />
|
||||
It was based on an early prototype design of the TinySA by Erik PD0EK.<br />
|
||||
Information can be found at <a href = "https://groups.io/g/HBTE">https://groups.io/g/HBTE</a>
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
<form method="get" action="/doReboot">
|
||||
To reboot click <button style="background-color: red; color: white;"
|
||||
onclick="return confirm('Are you sure?')" type="submit">here</button>
|
||||
</form>
|
||||
<form method="get" action="/doReboot">
|
||||
To reboot click <button style="background-color: red; color: white;"
|
||||
onclick="return confirm('Are you sure?')" type="submit">here</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id=footer>Copyright © <span id="programCopyright"></span></div>
|
||||
<div id=footer>Copyright © <span id="programCopyright">M0WID and WA2FZW</span></div>
|
||||
</body>
|
||||
</html>
|
||||
|
549
data/index.html
549
data/index.html
@ -32,7 +32,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>TinySA-ESP</title>
|
||||
<title>simpleSA</title>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
||||
<!-- get file below from http://canvasjs.com/ -->
|
||||
<script type="text/javascript" src="canvasjs.min.js"></script>
|
||||
@ -41,7 +41,7 @@
|
||||
</head>
|
||||
|
||||
<body style="min-width:100vw">
|
||||
<div class='norm'>
|
||||
<div class='norm' id="top">
|
||||
|
||||
<button id="homeButton" onclick="window.location.href='index.html';">Home</button>
|
||||
<!-- <button id="settingsButton" onclick="window.location.href='settings.html';">Settings</button>
|
||||
@ -50,12 +50,66 @@
|
||||
<button id="aboutButton" onclick="window.location.href='about.html';">About</button>
|
||||
</div>
|
||||
<div class ="Grid">
|
||||
<div class = "Grid-cell" id="chartSA" ></div>
|
||||
<div class = "Grid-cell" id="chartSA" style="display:none">
|
||||
<!-- container for chart -->
|
||||
</div>
|
||||
|
||||
<div class = "Grid-cell" id="sigGen" style="display:block">
|
||||
<!-- container for sig gen controls -->
|
||||
<br />
|
||||
<div class="sigTitle">Signal Generator</div>
|
||||
<br />
|
||||
<div class="sigFreq">
|
||||
<button class = "inc-button" id="incButton">+</button>
|
||||
<br />
|
||||
<label for="setSigGenFreq8" class="sigFreqLabel">Frequency:</label>
|
||||
<input class="sigFreqInput" id="setSigGenFreq8" name="setSigGenFreq8" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq7" name="setSigGenFreq7" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq6" name="setSigGenFreq6" type="number" min=-1 max=10 value=0>
|
||||
<span class="sigFreqText">,</span>
|
||||
<input class="sigFreqInput" id="setSigGenFreq5" name="setSigGenFreq5" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq4" name="setSigGenFreq4" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq3" name="setSigGenFreq3" type="number" min=-1 max=10 value=0>
|
||||
<span class="sigFreqText">,</span>
|
||||
<input class="sigFreqInput" id="setSigGenFreq2" name="setSigGenFreq2" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq1" name="setSigGenFreq1" type="number" min=-1 max=10 value=0>
|
||||
<input class="sigFreqInput" id="setSigGenFreq0" name="setSigGenFreq0" type="number" min=0 max=10 value=0>
|
||||
<span class="sigFreqText">Hz </span>
|
||||
<button class = "on-button" id="sigOnButton">On/Off</button>
|
||||
<br />
|
||||
<button class = "inc-button" id="decButton">-</button>
|
||||
|
||||
|
||||
</div>
|
||||
<br /><br />
|
||||
<label for="setSigGenPower" class = "sigLevelLabel">Level:</label>
|
||||
<input class="sigLevelInput" id="setSigGenPower" name="setSigGenPower" type="number" min=-70 max=20 value=0>
|
||||
dBm
|
||||
<br /><br />
|
||||
<div class="slidecontainer">
|
||||
<input type="range" min=-70 max=20 value=0 class="slider" id="sigLevelSlider">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div class = "Grid-cell-side" id="postSweepSettings" >
|
||||
<!--<form style="width: 90vw; margin-left: 80px" action="doSetSweep" method="get"> -->
|
||||
<h1>Sweep</h1>
|
||||
<div class="setting" >
|
||||
<select class="Sweep-select" id="setMode" name="setMode">
|
||||
<option class="sweep-option" value="0">Sweep Low</option>
|
||||
<!-- <option class="sweep-option" value="1">Sweep High</option> -->
|
||||
<option class="sweep-option" value="2">Sig Gen</option>
|
||||
<!-- <option class="sweep-option" value="3">Sig Gen High</option> -->
|
||||
<option class="sweep-option" value="4">SAW Test</option>
|
||||
<!-- <option class="sweep-option" value="5">Zero Span</option> -->
|
||||
<!-- <option class="sweep-option" value="6">Zero Span High</option> -->
|
||||
<option class="sweep-option" value="7">Bandscope</option>
|
||||
<option class="sweep-option" value="8">RBW Test</option>
|
||||
</select>
|
||||
<img src="refresh.png" id="refresh" name = "refresh" height = "18">
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<label for="setStart" class="setting-label">Start:</label>
|
||||
<input class="value-input" name='setStart' type="number" id="setStart" maxlength="9" min="0" max="350" required>
|
||||
@ -113,9 +167,10 @@
|
||||
<br />
|
||||
<div class="setting" >
|
||||
<label for="setAtten" class="setting-label">Atten:</label>
|
||||
<input class="value-input" name='setAtten' type="number" step="1" id ="setAtten" maxlength="3" min="0" max="31" required>
|
||||
<input class="value-input" name='setAtten' type="number" step="1" id ="setAtten" maxlength=3 min=0 max=31 required>
|
||||
dB
|
||||
<label for="setExtern" class="setting-label">External:</label>
|
||||
<input class="value-input" name='setExtern' type="number" step="1" id ="setExtern" maxlength="3" min="-60" max="60" required>
|
||||
<input class="value-input" name='setExtern' type="number" step="1" id ="setExtern" maxlength=3 min=-60 max=60 required>
|
||||
<!--<select class="select-input" id="setAtten" name="setAtten"></select> -->
|
||||
dB
|
||||
</div>
|
||||
@ -137,25 +192,36 @@
|
||||
<br />
|
||||
<div id="spur">
|
||||
<div class="setting" >
|
||||
<label class="setting-label">Spur Reduce:</label>
|
||||
<label class="setting-widelabel">Spur Reduce:</label>
|
||||
<input class="checkbox-input" type="checkbox" id="spurReduction" size="1" value="0" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="tracking">
|
||||
<div class="setting" >
|
||||
<label class="setting-label">TrackGen:</label>
|
||||
<input class="checkbox-input" type="checkbox" id="trackGen" size="1" value="0" />
|
||||
<input class="value-input" type="number" id="setTrackGenPower" placeholder="setTrackGenPower" maxlength = "9" min="-60" max="20" value="0" />
|
||||
dBm
|
||||
<select class="select-input" id="trackGen" name="trackGen">
|
||||
<option class="select-option" value=0>Off</option>
|
||||
<option class="select-option" value=1>Track</option>
|
||||
<option class="select-option" value=2>Generate</option>
|
||||
</select>
|
||||
<br />
|
||||
<label class="setting-label">Level:</label>
|
||||
<input class="value-input" type="number" id="setTrackGenPower" placeholder="setTrackGenPower" maxlength = "6" min="-60" max="20" value="0" />
|
||||
dBm
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<label for="setTGFreq" class="setting-label">TG Freq:</label>
|
||||
<input class="value-input" name='setTGFreq' type="number" id="setTGFreq" maxlength="9" min=0 max=350 required>
|
||||
MHz
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<div id="signal_info">
|
||||
<div class="setting" >
|
||||
<label class="setting-label">Points:</label>
|
||||
<input class="value-display" type="text" disabled="1" id="sweepPoints" size="1" value="65000" />
|
||||
<label class="setting-label">Time:</label>
|
||||
<input class="value-display" type="text" disabled="1" id="sweepTime" size="1" value="290" />
|
||||
<input class="sweep-display" type="text" disabled="1" id="sweepPoints" size="1" value="65000" />
|
||||
pts
|
||||
<input class="sweep-display" type="text" disabled="1" id="sweepTime" size="1" value="290" />
|
||||
ms
|
||||
</div>
|
||||
</div>
|
||||
@ -179,7 +245,7 @@
|
||||
dB
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<button class = "set-button" type="submit" id="setActPower">Set Actual</button>
|
||||
<button id="setActPower">Set Actual</button>
|
||||
<input class="value-input" type="number" id="setPowerValue" placeholder="setPowerValue" maxlength = "9" min="-60" max="20" value="0" />
|
||||
dBm
|
||||
</div>
|
||||
@ -257,8 +323,9 @@
|
||||
<div style="width: 100px; display: inline-block">Pings:
|
||||
<input type="text" id="connectionPings" size="3" value="-" style="border: 0" />
|
||||
</div>
|
||||
<div style="width: 100px; display: inline-block">Refresh Interval:
|
||||
<div style="width: 160px; display: inline-block">Refresh:
|
||||
<input class="value-input" type="number" id="refreshInterval" size="3" min="100" max="3000" value="500" />
|
||||
ms
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -268,8 +335,17 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var frequency = 0;
|
||||
var freqStep = 1000000;
|
||||
|
||||
var chartDiv = document.getElementById('chartSA');
|
||||
var sigDiv = document.getElementById('sigGen');
|
||||
|
||||
var refreshInterval = document.getElementById('refreshInterval');
|
||||
|
||||
var refresh = document.getElementById('refresh');
|
||||
var setMode = document.getElementById('setMode');
|
||||
var sweepStart = document.getElementById('sweepStart');
|
||||
var sweepStop = document.getElementById('sweepStop');
|
||||
var setStart = document.getElementById('setStart');
|
||||
@ -292,12 +368,28 @@ var setPreAmp = document.getElementById('setPreAmp');
|
||||
var setAverage = document.getElementById('Average');
|
||||
var setTrackGen = document.getElementById('trackGen');
|
||||
var setTrackGenPower = document.getElementById('setTrackGenPower');
|
||||
var setTGFreq = document.getElementById('setTGFreq');
|
||||
var store1 = document.getElementById('store1');
|
||||
var store2 = document.getElementById('store2');
|
||||
var store3 = document.getElementById('store3');
|
||||
var store4 = document.getElementById('store4');
|
||||
//var messageWindow = document.getElementById('message');
|
||||
|
||||
var sigLevelSlider = document.getElementById('sigLevelSlider');
|
||||
var setSigGenPower = document.getElementById('setSigGenPower');
|
||||
var setSigGenFreq = document.getElementById('setSigGenFreq');
|
||||
var sigOnButton = document.getElementById('sigOnButton');
|
||||
|
||||
var setSigGenFreq0 = document.getElementById('setSigGenFreq0');
|
||||
var setSigGenFreq1 = document.getElementById('setSigGenFreq1');
|
||||
var setSigGenFreq2 = document.getElementById('setSigGenFreq2');
|
||||
var setSigGenFreq3 = document.getElementById('setSigGenFreq3');
|
||||
var setSigGenFreq4 = document.getElementById('setSigGenFreq4');
|
||||
var setSigGenFreq5 = document.getElementById('setSigGenFreq5');
|
||||
var setSigGenFreq6 = document.getElementById('setSigGenFreq6');
|
||||
var setSigGenFreq7 = document.getElementById('setSigGenFreq7');
|
||||
var setSigGenFreq8 = document.getElementById('setSigGenFreq8');
|
||||
|
||||
var tempCenter;
|
||||
|
||||
// initialise these to silly values to force an update first time round
|
||||
@ -316,6 +408,13 @@ var oldSweepPoints = 0;
|
||||
var oldSpur = 2;
|
||||
var oldTrackGen = 2;
|
||||
var oldTrackGenPower = 1000;
|
||||
var oldTGFreq = -1;
|
||||
var oldSigGen = -1;
|
||||
var oldSigGenPower = 1000;
|
||||
var oldSigGenFreq = -1;
|
||||
var oldSigGenMod = -1;
|
||||
var oldSigGenModFreq = -1;
|
||||
var oldSigOnButton = -1;
|
||||
|
||||
// Chart configuration - Scope
|
||||
var RSSISamples = [
|
||||
@ -410,17 +509,28 @@ var chartSA = new CanvasJS.Chart("chartSA",
|
||||
zoomType: "xy",
|
||||
//height:800,
|
||||
title: {
|
||||
text: "ESP32 TinySA",
|
||||
text: "simpleSA",
|
||||
fontSize: 28
|
||||
},
|
||||
axisX: {
|
||||
title: "Frequency (MHz)",
|
||||
titleFontSize: 24
|
||||
titleFontSize: 24,
|
||||
gridThickness: 1,
|
||||
gridColor: "WhiteSmoke",
|
||||
stripLines:[
|
||||
{
|
||||
startValue:50,
|
||||
thickness:1,
|
||||
color:"#d8d8d8",
|
||||
}
|
||||
]
|
||||
},
|
||||
axisY:
|
||||
{
|
||||
title: "dB",
|
||||
title: "dBm",
|
||||
titleFontSize: 24,
|
||||
gridThickness: 1,
|
||||
gridColor: "WhiteSmoke",
|
||||
minimum: -120
|
||||
},
|
||||
axisY2: [
|
||||
@ -439,6 +549,7 @@ var chartSA = new CanvasJS.Chart("chartSA",
|
||||
exportEnabled: true,
|
||||
legend: {
|
||||
cursor: "pointer",
|
||||
fontSize: 16,
|
||||
itemclick: function (e) {
|
||||
//console.log("legend click: " + e.dataPointIndex);
|
||||
//console.log(e);
|
||||
@ -526,9 +637,16 @@ renderChart();
|
||||
|
||||
// Add handlers for the change events in the input fields
|
||||
|
||||
refresh.addEventListener('click', (event) => {
|
||||
sendValue("r", 0);
|
||||
});
|
||||
|
||||
setMode.addEventListener('change', (event) => {
|
||||
sendValue("m", setMode.value);
|
||||
});
|
||||
|
||||
setStart.addEventListener('change', (event) => {
|
||||
sendValue("a", setStart.value);
|
||||
sendValue("a", setStart.value);
|
||||
});
|
||||
|
||||
setStop.addEventListener('change', (event) => {
|
||||
@ -589,13 +707,17 @@ setSpur.addEventListener('change', (event) => {
|
||||
});
|
||||
|
||||
setTrackGen.addEventListener('change', (event) => {
|
||||
if (setTrackGen.checked) {
|
||||
sendValue("t", 1);
|
||||
} else {
|
||||
sendValue("t", 0);
|
||||
}
|
||||
sendValue("t", setTrackGen.value);
|
||||
});
|
||||
|
||||
setTrackGenPower.addEventListener('change', (event) => {
|
||||
sendValue("T", setTrackGenPower.value);
|
||||
});
|
||||
|
||||
|
||||
setTGFreq.addEventListener('change', (event) => {
|
||||
sendValue("f", setTGFreq.value);
|
||||
});
|
||||
|
||||
store1.addEventListener('change', (event) => {
|
||||
if (store1.checked) {
|
||||
@ -653,6 +775,188 @@ store4.addEventListener('change', (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
function changeStep(newStep) {
|
||||
freqStep = newStep;
|
||||
setSigGenFreq0.style.color = "black";
|
||||
setSigGenFreq1.style.color = "black";
|
||||
setSigGenFreq2.style.color = "black";
|
||||
setSigGenFreq3.style.color = "black";
|
||||
setSigGenFreq4.style.color = "black";
|
||||
setSigGenFreq5.style.color = "black";
|
||||
setSigGenFreq6.style.color = "black";
|
||||
setSigGenFreq7.style.color = "black";
|
||||
setSigGenFreq8.style.color = "black";
|
||||
|
||||
switch(freqStep) {
|
||||
case 1:
|
||||
setSigGenFreq0.style.color = "red";
|
||||
break;
|
||||
case 10:
|
||||
setSigGenFreq1.style.color = "red";
|
||||
break;
|
||||
case 100:
|
||||
setSigGenFreq2.style.color = "red";
|
||||
break;
|
||||
case 1000:
|
||||
setSigGenFreq3.style.color = "red";
|
||||
break;
|
||||
case 10000:
|
||||
setSigGenFreq4.style.color = "red";
|
||||
break;
|
||||
case 100000:
|
||||
setSigGenFreq5.style.color = "red";
|
||||
break;
|
||||
case 1000000:
|
||||
setSigGenFreq6.style.color = "red";
|
||||
break;
|
||||
case 10000000:
|
||||
setSigGenFreq7.style.color = "red";
|
||||
break;
|
||||
case 100000000:
|
||||
setSigGenFreq8.style.color = "red";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
changeStep(freqStep); // initial pass
|
||||
|
||||
function incdec(direction, factor) {
|
||||
if (direction > 0) {
|
||||
if ( (frequency + factor) <= 250000000)
|
||||
frequency += factor;
|
||||
} else {
|
||||
if (frequency >= factor)
|
||||
frequency -= factor;
|
||||
}
|
||||
if (frequency > 250000000)
|
||||
frequency = 250000000;
|
||||
if (frequency < 0)
|
||||
frequency = 0;
|
||||
console.log("incdec:", frequency);
|
||||
var tempFreq = frequency;
|
||||
setSigGenFreq0.value = frequency%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq1.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq2.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq3.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq4.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq5.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq6.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq7.value = tempFreq%10;
|
||||
tempFreq = parseInt(tempFreq/10);
|
||||
setSigGenFreq8.value = tempFreq%10;
|
||||
|
||||
if (factor != 0)
|
||||
sendValue("F", frequency);
|
||||
}
|
||||
|
||||
incButton.onclick = function() {incdec(1, freqStep)};
|
||||
decButton.onclick = function() {incdec(-1, freqStep)};
|
||||
|
||||
setSigGenFreq0.onfocus = function() {changeStep(1)};
|
||||
setSigGenFreq1.onfocus = function() {changeStep(10)};
|
||||
setSigGenFreq2.onfocus = function() {changeStep(100)};
|
||||
setSigGenFreq3.onfocus = function() {changeStep(1000)};
|
||||
setSigGenFreq4.onfocus = function() {changeStep(10000)};
|
||||
setSigGenFreq5.onfocus = function() {changeStep(100000)};
|
||||
setSigGenFreq6.onfocus = function() {changeStep(1000000)};
|
||||
setSigGenFreq7.onfocus = function() {changeStep(10000000)};
|
||||
setSigGenFreq8.onfocus = function() {changeStep(100000000)};
|
||||
|
||||
|
||||
setSigGenFreq0.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(1);
|
||||
incdec(-event.deltaY,1);
|
||||
});
|
||||
|
||||
|
||||
setSigGenFreq1.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(10);
|
||||
incdec(-event.deltaY,10);
|
||||
});
|
||||
|
||||
setSigGenFreq2.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(100);
|
||||
incdec(-event.deltaY,100);
|
||||
});
|
||||
|
||||
setSigGenFreq3.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(1000);
|
||||
incdec(-event.deltaY,1000);
|
||||
});
|
||||
|
||||
setSigGenFreq4.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(10000);
|
||||
incdec(-event.deltaY,10000);
|
||||
});
|
||||
|
||||
setSigGenFreq5.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(100000);
|
||||
incdec(-event.deltaY,100000);
|
||||
});
|
||||
|
||||
setSigGenFreq6.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(1000000);
|
||||
incdec(-event.deltaY,1000000);
|
||||
});
|
||||
|
||||
setSigGenFreq7.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(10000000);
|
||||
incdec(-event.deltaY,10000000);
|
||||
});
|
||||
|
||||
setSigGenFreq8.addEventListener('wheel', (event) => {
|
||||
event.preventDefault();
|
||||
changeStep(100000000);
|
||||
incdec(-event.deltaY,100000000);
|
||||
});
|
||||
|
||||
|
||||
setSigGenPower.onchange = function() {
|
||||
sendValue("L", setSigGenPower.value);
|
||||
sigLevelSlider.value = this.value;
|
||||
};
|
||||
|
||||
// Update the current level value (each time you drag the slider handle)
|
||||
sigLevelSlider.oninput = function() {
|
||||
setSigGenPower.value = this.value;
|
||||
setSigGenPower.onchange();
|
||||
}
|
||||
|
||||
function styleSigGenButton ( val ) {
|
||||
if (sigOnButton.value == 1) {
|
||||
sigOnButton.style="background-color:green";
|
||||
} else {
|
||||
sigOnButton.style="background-color:lightgrey";
|
||||
}
|
||||
}
|
||||
|
||||
sigOnButton.onclick = function() {
|
||||
if (sigOnButton.value == 1) {
|
||||
sigOnButton.value = 0;
|
||||
} else {
|
||||
sigOnButton.value = 1;
|
||||
}
|
||||
styleSigGenButton (sigOnButton.value);
|
||||
sendValue("G", sigOnButton.value);
|
||||
}
|
||||
|
||||
//var roundtripTime = document.getElementById('roundtripTime');
|
||||
//var messageCount = document.getElementById('messageCount');
|
||||
//var missedReplies = document.getElementById('missedReplies');
|
||||
@ -685,7 +989,7 @@ function renderChart()
|
||||
//missedReplies.value = missedMessageCounter;
|
||||
hostName.value = "ws://" + location.host + ":81";
|
||||
|
||||
// connect to TinySA server
|
||||
// connect to simpleSA server
|
||||
connect(hostName.value);
|
||||
|
||||
// At this point the page is running
|
||||
@ -703,6 +1007,95 @@ var indexUpdateMilliSeconds = 1 * 1000;
|
||||
|
||||
function handleSettings (settings)
|
||||
{
|
||||
setMode.value = settings.mode;
|
||||
if (setMode.value == 8) { // RX Sweep (RBW test)
|
||||
setStart.max = settings.IF;
|
||||
setStop.max = 600;
|
||||
setStart.min = 350;
|
||||
setStart.disabled = false;
|
||||
setStop.min = settings.IF;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = true;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackGen.disabled = true;
|
||||
setTGFreq.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
sigDiv.style.display = "none";
|
||||
chartDiv.style.display = "block";
|
||||
} else if (settings.mode == 4 ) { // IF Sweep (SAW test)
|
||||
setStart.max = settings.IF;
|
||||
setStop.max = 460;
|
||||
setStart.min = 400;
|
||||
setStop.min = settings.IF;
|
||||
setStart.disabled = false;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = true;
|
||||
setRBW.disabled = true;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackGen.disabled = true;
|
||||
setTGFreq.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
sigDiv.style.display = "none";
|
||||
chartDiv.style.display = "block";
|
||||
} else if (settings.mode == 7 ) { // BANDSCOPE
|
||||
setStart.max = 350;
|
||||
setStop.max = 350;
|
||||
setStart.min = 0;
|
||||
setStop.min = 0;
|
||||
setStart.disabled = false;
|
||||
setStop.disabled = true;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = false;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackGen.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
sigDiv.style.display = "none";
|
||||
chartDiv.style.display = "block";
|
||||
} else if (settings.mode == 2 ) { // Signal Generator
|
||||
setStart.max = 350;
|
||||
setStop.max = 350;
|
||||
setStart.min = 0;
|
||||
setStop.min = 0;
|
||||
setStart.disabled = true;
|
||||
setStop.disabled = true;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = true;
|
||||
setRBW.disabled = true;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackGen.disabled = true;
|
||||
setTGFreq.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
sigDiv.style.display = "block";
|
||||
chartDiv.style.display = "none";
|
||||
} else {
|
||||
setStart.max = 350;
|
||||
setStop.max = 350;
|
||||
setStart.min = 0;
|
||||
setStop.min = 0;
|
||||
setStart.disabled = false;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = false;
|
||||
setSpan.disabled = false;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = false;
|
||||
setSpur.disabled = false;
|
||||
setTrackGen.disabled = false;
|
||||
setTGFreq.disabled = false;
|
||||
setTrackGenPower.disabled = false;
|
||||
sigDiv.style.display = "none";
|
||||
chartDiv.style.display = "block";
|
||||
}
|
||||
|
||||
|
||||
|
||||
actRBW.value = settings.bandwidth;
|
||||
|
||||
|
||||
@ -774,16 +1167,43 @@ function handleSettings (settings)
|
||||
oldSpur = settings.spur;
|
||||
}
|
||||
|
||||
if (settings.tg != oldTrackGen) {
|
||||
if (settings.tg) {
|
||||
setTrackGen.checked = true; // Tracking Generator checkbox
|
||||
} else {
|
||||
setTrackGen.checked = false; // Tracking Generator checkbox
|
||||
}
|
||||
if (settings.sg != oldSigGen) { // Sig gen on/off
|
||||
sigOnButton.value = settings.sg;
|
||||
oldSigGen = settings.sg;
|
||||
styleSigGenButton (sigOnButton.value);
|
||||
}
|
||||
|
||||
if (settings.sgFreq != oldSigGenFreq) { // sig gen frequency
|
||||
frequency = settings.sgFreq;
|
||||
oldSigGenFreq = settings.sgFreq;
|
||||
incdec(0,0);
|
||||
console.log("sigGenFreq=" + settings.sgFreq);
|
||||
}
|
||||
|
||||
sigLevelSlider.max = settings.sgCal; // Limits for sig gen power
|
||||
sigLevelSlider.min = settings.sgCal - settings.sgRange;
|
||||
setSigGenPower.max = settings.sgCal;
|
||||
setSigGenPower.min = settings.sgCal - settings.sgRange;
|
||||
|
||||
if (settings.sgPower != oldSigGenPower) {
|
||||
setSigGenPower.value = settings.sgPower;
|
||||
sigLevelSlider.value = settings.sgPower;
|
||||
oldSigGenPower = settings.sgPower;
|
||||
}
|
||||
|
||||
|
||||
if (settings.tg != oldTrackGen) { // tracking generator state
|
||||
setTrackGen.value = settings.tg;
|
||||
oldTrackGen = settings.tg;
|
||||
}
|
||||
|
||||
if (settings.tgPower != oldTrackGenPower) {
|
||||
if (settings.tgFreq != oldTGFreq) { // tracking generator frequency for sig gen mode
|
||||
setTGFreq.value = settings.tgFreq;
|
||||
oldTGFreq = settings.tgFreq;
|
||||
}
|
||||
|
||||
|
||||
if (settings.tgPower != oldTrackGenPower) { // tracking generator output power
|
||||
setTrackGenPower.value = settings.tgPower;
|
||||
oldTrackGenPower = settings.tgPower;
|
||||
}
|
||||
@ -1095,17 +1515,19 @@ function connect(host)
|
||||
connection.send('Hello from Browser :-) ' + new Date());
|
||||
sendMessage();
|
||||
sendPingVar = setInterval(function(){ sendPing() }, 30000);
|
||||
|
||||
sendValue("r",0); // request settings
|
||||
|
||||
// Get the settings to make sure current
|
||||
$.getJSON( "getSettings")
|
||||
.done(function (settings) {
|
||||
handleSettings(settings);
|
||||
})
|
||||
|
||||
.fail(function(jqxhr, textStatus, error) {
|
||||
var err = textStatus +", " + error;
|
||||
console.log("Settings Request Failed: " + err);
|
||||
});
|
||||
//$.getJSON( "getSettings")
|
||||
// .done(function (settings) {
|
||||
// handleSettings(settings);
|
||||
// })
|
||||
//
|
||||
// .fail(function(jqxhr, textStatus, error) {
|
||||
// var err = textStatus +", " + error;
|
||||
// console.log("Settings Request Failed: " + err);
|
||||
// });
|
||||
|
||||
var items = document.querySelectorAll(".value-input");
|
||||
var i;
|
||||
@ -1119,6 +1541,18 @@ function connect(host)
|
||||
items[i].disabled = false;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".select-button");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = false;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".checkbox-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
connection.onclose = function(event)
|
||||
@ -1141,6 +1575,18 @@ function connect(host)
|
||||
items[i].disabled = true;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".select-button");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = true;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".checkbox-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
connection.onerror = function(error)
|
||||
@ -1176,7 +1622,7 @@ function connect(host)
|
||||
}
|
||||
else if (myObject.mType == "chunkSweep")
|
||||
{
|
||||
console.log("handle chunk Sweep:" + myObject.StartIndex);
|
||||
//console.log("handle chunk Sweep:" + myObject.StartIndex);
|
||||
handleChunkData(myObject);
|
||||
}
|
||||
else
|
||||
@ -1210,19 +1656,30 @@ function sendValue(c, val)
|
||||
// s Span
|
||||
// d Local Oscillator Drive
|
||||
// g PreAmpGain/Mode
|
||||
// p set actual power to peak value
|
||||
// i IF frequency
|
||||
// m mode
|
||||
// p set actual power to peak value
|
||||
// o RefOut
|
||||
// r request Settings are pushed
|
||||
// A internal attenuation (PE4302)
|
||||
// E external gain ( eg attenuator(-ve) or preamp(+ve) )
|
||||
// R requested RBW
|
||||
// S Spur reduction Off/On
|
||||
// t trackGen Off/On/Fixed
|
||||
// T trackGen output level
|
||||
// f trackgen signal generator frequency
|
||||
// F Sig Gen frequency
|
||||
// L Sig Gen level (dBm)
|
||||
// G Sig Gen Off/On
|
||||
// P Sig Gen set max output level (dBm)
|
||||
//
|
||||
//connection.send("# " + messageCounter + " " + sampleThreshold + " " + sampleSize);
|
||||
connection.send("#" + c + " " + val);
|
||||
console.log("Command:" + c + val);
|
||||
if (connectionStatus.value == "Connected") {
|
||||
connection.send("#" + c + " " + val);
|
||||
console.log("Command:" + c + val);
|
||||
} else {
|
||||
console.log("No connection - Command:" + c + val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -627,7 +627,7 @@ store1.addEventListener('change', (event) => {
|
||||
});
|
||||
|
||||
store2.addEventListener('change', (event) => {
|
||||
if (store1.checked) {
|
||||
if (store2.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120;
|
||||
chartSA.options.data[6].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
@ -641,7 +641,7 @@ store2.addEventListener('change', (event) => {
|
||||
});
|
||||
|
||||
store3.addEventListener('change', (event) => {
|
||||
if (store1.checked) {
|
||||
if (store3.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120;
|
||||
chartSA.options.data[7].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
@ -655,7 +655,7 @@ store3.addEventListener('change', (event) => {
|
||||
});
|
||||
|
||||
store4.addEventListener('change', (event) => {
|
||||
if (store1.checked) {
|
||||
if (store4.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120;
|
||||
chartSA.options.data[8].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
|
BIN
data/refresh.png
Normal file
BIN
data/refresh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 655 B |
976
data/siggen.html
Normal file
976
data/siggen.html
Normal file
@ -0,0 +1,976 @@
|
||||
<!--
|
||||
This application is loosly based on the code found here:
|
||||
|
||||
Repository: https://github.com/krzychb/EspScopeA0
|
||||
Version: Delta
|
||||
Flie: index.htm
|
||||
Revision: 0.1.0
|
||||
Date: 10-Jul-2016
|
||||
Author: krzychb at gazeta.pl
|
||||
|
||||
Copyright (c) 2016 Krzysztof Budzynski. All rights reserved.
|
||||
|
||||
This modified version takes the samples from the TinySA
|
||||
spectrum analyser and displays in a web page.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>simpleSA-ESP</title>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css">
|
||||
<!-- get file below from http://canvasjs.com/ -->
|
||||
<script type="text/javascript" src="canvasjs.min.js"></script>
|
||||
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
|
||||
<script type="text/javascript" src="support.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="min-width:100vw">
|
||||
<div class='norm'>
|
||||
|
||||
<button id="homeButton" onclick="window.location.href='index.html';">Home</button>
|
||||
<!-- <button id="settingsButton" onclick="window.location.href='settings.html';">Settings</button>
|
||||
<button id="backupRestoreButton" onclick="window.location.href='backupRestore.html';">Backup/Restore</button>
|
||||
// <button id="helpButton" onclick="window.location.href='help.html';">Help</button> -->
|
||||
<button id="aboutButton" onclick="window.location.href='about.html';">About</button>
|
||||
</div>
|
||||
<div class ="Grid">
|
||||
<div class = "Grid-cell" id="chartSA" ></div>
|
||||
<br />
|
||||
|
||||
<div class = "Grid-cell-side" id="postSweepSettings" >
|
||||
<!--<form style="width: 90vw; margin-left: 80px" action="doSetSweep" method="get"> -->
|
||||
<div class="setting" >
|
||||
<select class="Sweep-select" id="setMode" name="setMode">
|
||||
<option class="sweep-option" value="0">Sweep Low</option>
|
||||
<!-- <option class="sweep-option" value="1">Sweep High</option> -->
|
||||
<option class="sweep-option" value="2">Sig Gen</option>
|
||||
<!-- <option class="sweep-option" value="3">Sig Gen High</option> -->
|
||||
<option class="sweep-option" value="4">SAW Test</option>
|
||||
<!-- <option class="sweep-option" value="5">Zero Span</option> -->
|
||||
<!-- <option class="sweep-option" value="6">Zero Span High</option> -->
|
||||
<option class="sweep-option" value="7">Bandscope</option>
|
||||
<option class="sweep-option" value="8">RBW Test</option>
|
||||
</select>
|
||||
<img src="refresh.png" id="refresh" name = "refresh" height = "18">
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<label for="setFreq" class="setting-label">Frequency:</label>
|
||||
<input class="value-input" name='setFreq' type="number" id="setFreq" maxlength="9" min="0" max="350" required>
|
||||
MHz
|
||||
</div>
|
||||
<br />
|
||||
<div class="setting" >
|
||||
<label for="setLevel" class="setting-label">Level:</label>
|
||||
<input class="value-input" name='setLevel' type="number" step="1" id ="setLevel" maxlength="4" min="-31" max="0" required>
|
||||
dBm
|
||||
</div>
|
||||
<hr />
|
||||
<h1>Settings</h1>
|
||||
<div class="setting" >
|
||||
<label for="calLevel" class="setting-label">Max Level:</label>
|
||||
<input class="value-display" type="text" disabled="1" id="calLevel" size="1" value="0" />
|
||||
dB
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<button class = "set-button" type="submit" id="setActPower">Set Max</button>
|
||||
<input class="value-input" type="number" id="setMaxPower" placeholder="setMaxPower" maxlength = "9" min="-60" max="20" value="0" />
|
||||
dBm
|
||||
</div>
|
||||
<br />
|
||||
<div class="setting" >
|
||||
<label for="setLODrive" class="setting-label">LO Drive:</label>
|
||||
<select class="select-input" id="setLODrive" name="setLODrive">
|
||||
<option class="select-option" value="0">-1</option>
|
||||
<option class="select-option" value="1">2</option>
|
||||
<option class="select-option" value="2">5</option>
|
||||
<option class="select-option" value="3">8</option>
|
||||
<option class="select-option" value="4">11</option>
|
||||
<option class="select-option" value="5">14</option>
|
||||
<option class="select-option" value="6">17</option>
|
||||
<option class="select-option" value="7">20</option>
|
||||
</select>
|
||||
dBm
|
||||
</div>
|
||||
<div class="setting" >
|
||||
<label for="setIF" class="setting-label">IF:</label>
|
||||
<input class="value-input" type="number" id="setIF" size="1" value="433.92" min="433" max=435 step=0.01 />
|
||||
MHz
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--</form> -->
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Below chart (hopefully!) -->
|
||||
|
||||
|
||||
<div class = "Grid">
|
||||
<div class = "Grid-cell-connection" id="status" >
|
||||
<hr />
|
||||
<div id="connection-status">
|
||||
<form onsubmit="return false;">
|
||||
<div style="width: 400px; display: inline-block">Host:
|
||||
<input type="text" id="hostName" value="ws://hostName:81" style="width:160px;"/>
|
||||
<input type="button" value="Connect" onclick="connect(hostName.value)" />
|
||||
<input type="button" value="Disconnect" onclick="disconnect()" />
|
||||
</div>
|
||||
<div style="width: 250px; display: inline-block">Status:
|
||||
<input type="text" id="connectionStatus" value="Idle" style="border: 0" />
|
||||
</div>
|
||||
<div style="width: 100px; display: inline-block">Pings:
|
||||
<input type="text" id="connectionPings" size="3" value="-" style="border: 0" />
|
||||
</div>
|
||||
<div style="width: 100px; display: inline-block">Refresh Interval:
|
||||
<input class="value-input" type="number" id="refreshInterval" size="3" min="100" max="3000" value="500" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- <input class="message-display" type="text" disabled="1" id="message" size="1" value="json message" /> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var refreshInterval = document.getElementById('refreshInterval');
|
||||
|
||||
var refresh = document.getElementById('refresh');
|
||||
var setMode = document.getElementById('setMode');
|
||||
var setFreq = document.getElementById('setFreq');
|
||||
var setLevel = document.getElementById('setLevel');
|
||||
var calLevel = document.getElementByID('calLevel');
|
||||
|
||||
var setActPower = document.getElementById('setActPower');
|
||||
var setMaxPower = document.getElementByID('setMaxPower');
|
||||
|
||||
var setLODrive = document.getElementById('setLODrive');
|
||||
var setIF = document.getElementById('setIF');
|
||||
|
||||
//var messageWindow = document.getElementById('message');
|
||||
|
||||
|
||||
// initialise these to silly values to force an update first time round
|
||||
var oldFreq = 0
|
||||
var oldSetLevel = 100;
|
||||
var oldCalLevel = 100;
|
||||
var oldMaxPower = 100;
|
||||
var oldLODrive = -1;
|
||||
var oldIF = 0;
|
||||
|
||||
|
||||
|
||||
// Add handlers for the change events in the input fields
|
||||
|
||||
refresh.addEventListener('click', (event) => {
|
||||
sendValue("r", 0);
|
||||
});
|
||||
|
||||
setMode.addEventListener('change', (event) => {
|
||||
sendValue("m", setMode.value);
|
||||
});
|
||||
|
||||
setFreq.addEventListener('change', (event) => {
|
||||
sendValue("a", setStart.value);
|
||||
});
|
||||
|
||||
setStop.addEventListener('change', (event) => {
|
||||
sendValue("b", setStop.value);
|
||||
});
|
||||
|
||||
setCenter.addEventListener('change', (event) => {
|
||||
sendValue("c", setCenter.value);
|
||||
});
|
||||
|
||||
setLODrive.addEventListener('change', (event) => {
|
||||
if ((setLODrive.value >=0) && (setLODrive.value <= 7))
|
||||
sendValue("d", setLODrive.value);
|
||||
});
|
||||
|
||||
setIF.addEventListener('change', (event) => {
|
||||
sendValue("i", setIF.value);
|
||||
});
|
||||
|
||||
setRefOut.addEventListener('change', (event) => {
|
||||
sendValue("o", setRefOut.value);
|
||||
});
|
||||
|
||||
setActPower.addEventListener('click', (event) => {
|
||||
sendValue("p", setPowerValue.value);
|
||||
});
|
||||
|
||||
setSpan.addEventListener('change', (event) => {
|
||||
sendValue("s", setSpan.value);
|
||||
});
|
||||
|
||||
setAtten.addEventListener('change', (event) => {
|
||||
sendValue("A", setAtten.value);
|
||||
});
|
||||
|
||||
setExtern.addEventListener('change', (event) => {
|
||||
sendValue("E", setExtern.value);
|
||||
});
|
||||
|
||||
setRBW.addEventListener('change', (event) => {
|
||||
sendValue("R", setRBW.value);
|
||||
});
|
||||
|
||||
setPreAmp.addEventListener('change', (event) => {
|
||||
if (setPreAmp.value == "96") {
|
||||
sendValue("g", setPreAmp.value);
|
||||
} else {
|
||||
sendValue("g", setPreAmp.selectedOptions[0].text);
|
||||
}
|
||||
});
|
||||
|
||||
setSpur.addEventListener('change', (event) => {
|
||||
if (setSpur.checked) {
|
||||
sendValue("S", 1);
|
||||
} else {
|
||||
sendValue("S", 0);
|
||||
}
|
||||
});
|
||||
|
||||
setTrackGen.addEventListener('change', (event) => {
|
||||
if (setTrackGen.checked) {
|
||||
sendValue("t", 1);
|
||||
} else {
|
||||
sendValue("t", 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
store1.addEventListener('change', (event) => {
|
||||
if (store1.checked) {
|
||||
var b = parseFloat(levelOffset.value) + parseFloat(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
chartSA.options.data[5].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = obj.y/2+b
|
||||
return rObj
|
||||
})
|
||||
} else {
|
||||
chartSA.options.data[5].dataPoints.length = 2; // reset
|
||||
}
|
||||
});
|
||||
|
||||
store2.addEventListener('change', (event) => {
|
||||
if (store2.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
chartSA.options.data[6].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = obj.y/2+b
|
||||
return rObj
|
||||
})
|
||||
} else {
|
||||
chartSA.options.data[6].dataPoints.length = 2; // reset
|
||||
}
|
||||
});
|
||||
|
||||
store3.addEventListener('change', (event) => {
|
||||
if (store3.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
chartSA.options.data[7].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = obj.y/2+b
|
||||
return rObj
|
||||
})
|
||||
} else {
|
||||
chartSA.options.data[7].dataPoints.length = 2; // reset
|
||||
}
|
||||
});
|
||||
|
||||
store4.addEventListener('change', (event) => {
|
||||
if (store4.checked) {
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
chartSA.options.data[8].dataPoints = chartSA.options.data[1].dataPoints.map(obj => {
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = obj.y/2+b
|
||||
return rObj
|
||||
})
|
||||
} else {
|
||||
chartSA.options.data[8].dataPoints.length = 2; // reset
|
||||
}
|
||||
});
|
||||
|
||||
//var roundtripTime = document.getElementById('roundtripTime');
|
||||
//var messageCount = document.getElementById('messageCount');
|
||||
//var missedReplies = document.getElementById('missedReplies');
|
||||
var messageCounter = 0;
|
||||
var missedMessageCounter = 0;
|
||||
var messageSendMilis;
|
||||
|
||||
var connection;
|
||||
var connectionStatus = document.getElementById('connectionStatus');
|
||||
var hostName = document.getElementById('hostName');
|
||||
|
||||
var pingCounter = 0;
|
||||
var sendPingVar;
|
||||
var dateObject;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Timed update of chart render to reduce load on slow smartphones or tablets
|
||||
*/
|
||||
function renderChart()
|
||||
{
|
||||
setTimeout(function(){renderChart()}, refreshInterval.value);
|
||||
chartSA.render();
|
||||
//setTimeout(renderChart, refreshInterval.value);
|
||||
}
|
||||
|
||||
|
||||
//messageCount.value = messageCounter;
|
||||
//missedReplies.value = missedMessageCounter;
|
||||
hostName.value = "ws://" + location.host + ":81";
|
||||
|
||||
// connect to TinySA server
|
||||
connect(hostName.value);
|
||||
|
||||
// At this point the page is running
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
update();
|
||||
var chartUpdateVar;
|
||||
// chartUpdateVar = setInterval(renderChart, 500);
|
||||
});
|
||||
|
||||
var initDone = false;
|
||||
var indexUpdateMilliSeconds = 1 * 1000;
|
||||
|
||||
|
||||
function handleSettings (settings)
|
||||
{
|
||||
setMode.value = settings.mode;
|
||||
if (setMode.value == 8) { // RX Sweep (RBW test)
|
||||
setStart.max = settings.IF;
|
||||
setStop.max = 600;
|
||||
setStart.min = 350;
|
||||
setStop.min = settings.IF;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = true;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackgen.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
} else if (settings.mode == 4 ) { // IF Sweep (SAW test)
|
||||
setStart.max = settings.IF;
|
||||
setStop.max = 460;
|
||||
setStart.min = 400;
|
||||
setStop.min = settings.IF;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = true;
|
||||
setRBW.disabled = true;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackgen.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
} else if (settings.mode == 7 ) { // BANDSCOPE
|
||||
setStart.max = 350;
|
||||
setStop.max = 350;
|
||||
setStart.min = 0;
|
||||
setStop.min = 0;
|
||||
setStop.disabled = true;
|
||||
setCenter.disabled = true;
|
||||
setSpan.disabled = false;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = true;
|
||||
setSpur.disabled = true;
|
||||
setTrackgen.disabled = true;
|
||||
setTrackGenPower.disabled = true;
|
||||
} else {
|
||||
setStart.max = 350;
|
||||
setStop.max = 350;
|
||||
setStart.min = 0;
|
||||
setStop.min = 0;
|
||||
setStop.disabled = false;
|
||||
setCenter.disabled = false;
|
||||
setSpan.disabled = false;
|
||||
setRBW.disabled = false;
|
||||
setRefOut.disabled = false;
|
||||
setSpur.disabled = false;
|
||||
setTrackgen.disabled = false;
|
||||
setTrackGenPower.disabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
actRBW.value = settings.bandwidth;
|
||||
|
||||
|
||||
levelOffset.value = settings.levelOffset;
|
||||
// console.log("levelOffset=" + settings.levelOffset);
|
||||
|
||||
if (settings.start/1000 != oldSweepStart) {
|
||||
//console.log("Start:" + settings.start + " Stop:" + settings.stop + " oldStart:" + oldSweepStart);
|
||||
//sweepStart.value = settings.start/1000;
|
||||
setStart.value = settings.start/1000; // change default if changed
|
||||
oldSweepStart = setStart.value;
|
||||
setSpan.value = (settings.stop - settings.start)/1000;
|
||||
}
|
||||
|
||||
if (settings.stop/1000 != oldSweepStop) {
|
||||
//sweepStop.value = settings.stop/1000;
|
||||
setStop.value = settings.stop/1000; // change default if changed
|
||||
oldSweepStop = setStop.value;
|
||||
setSpan.value = (settings.stop - settings.start)/1000;
|
||||
}
|
||||
|
||||
tempCenter = ( (parseFloat(settings.stop) - parseFloat(settings.start) )/2 + parseFloat(settings.start) ) / 1000; // calculate center
|
||||
if (tempCenter != oldSweepCenter) {
|
||||
setCenter.value = tempCenter;
|
||||
oldSweepCenter = tempCenter;
|
||||
}
|
||||
|
||||
if (settings.attenuation != oldAttenuation) {
|
||||
setAtten.value = settings.attenuation;
|
||||
oldAttenuation = settings.attenuation;
|
||||
}
|
||||
|
||||
if (settings.extGain != oldExternalGain) {
|
||||
setExtern.value = settings.extGain;
|
||||
oldExternalGain = settings.extGain;
|
||||
}
|
||||
|
||||
if (settings.setRBW != oldSetRBW) {
|
||||
setRBW.value = settings.setRBW;
|
||||
oldSetRBW = settings.setRBW;
|
||||
}
|
||||
|
||||
if (settings.RefOut != oldSetRefOut) {
|
||||
setRefOut.value = settings.RefOut; // reference output dropdown
|
||||
oldSetRefOut = settings.RefOut;
|
||||
}
|
||||
|
||||
if (settings.Drive != oldDrive) {
|
||||
setLODrive.value = settings.Drive; // LO Drive dropdown
|
||||
oldDrive = settings.Drive;
|
||||
}
|
||||
|
||||
if (settings.IF != oldIF) {
|
||||
setIF.value = settings.IF; // IF value
|
||||
oldIF = settings.IF;
|
||||
}
|
||||
|
||||
if (settings.PreAmp != oldPreAmp) {
|
||||
setPreAmp.value = settings.PreAmp; // PreAmp Gain value
|
||||
oldPreAmp = settings.PreAmp;
|
||||
}
|
||||
|
||||
if (settings.spur != oldSpur) {
|
||||
if (settings.spur) {
|
||||
spurReduction.checked = true; // Spur reduction checkbox
|
||||
} else {
|
||||
spurReduction.checked = false; // Spur reduction checkbox
|
||||
}
|
||||
oldSpur = settings.spur;
|
||||
}
|
||||
|
||||
if (settings.tg != oldTrackGen) {
|
||||
if (settings.tg) {
|
||||
setTrackGen.checked = true; // Tracking Generator checkbox
|
||||
} else {
|
||||
setTrackGen.checked = false; // Tracking Generator checkbox
|
||||
}
|
||||
oldTrackGen = settings.tg;
|
||||
}
|
||||
|
||||
if (settings.tgPower != oldTrackGenPower) {
|
||||
setTrackGenPower.value = settings.tgPower;
|
||||
oldTrackGenPower = settings.tgPower;
|
||||
}
|
||||
|
||||
|
||||
chartSA.options.axisX.minimum = setStart.value;
|
||||
chartSA.options.axisX.maximum = setStop.value;
|
||||
|
||||
initDone = false;
|
||||
|
||||
}
|
||||
|
||||
function handleData (data) // rarely used! see handleChunkData for most sweeps
|
||||
{
|
||||
|
||||
if (data.sweepPoints != sweepPoints.value) {
|
||||
// reset chart data
|
||||
chartSA.options.data[0].dataPoints.length = 2;
|
||||
chartSA.options.data[1].dataPoints.length = 2;
|
||||
chartSA.options.data[3].dataPoints.length = 2;
|
||||
sweepPoints.value = data.sweepPoints;
|
||||
}
|
||||
|
||||
|
||||
var b = parseFloat(levelOffset.value) + parseFloat(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
//chartSA.options.data[0].dataPoints = data.Points; // First series dB
|
||||
chartSA.options.data[0].dataPoints = data.Points.map(obj => {
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = obj.y/2+b
|
||||
return rObj
|
||||
})
|
||||
|
||||
chartSA.options.data[1].dataPoints = data.Points; // RSSI trace
|
||||
chartSA.options.data[1].axisYType = "secondary";
|
||||
|
||||
if ((initDone == 0) || (oldSweepPoints != data.sweepPoints) || (oldDataPointCount != data.Points.length)) {
|
||||
chartSA.options.data[3].dataPoints = chartSA.options.data[0].dataPoints // first run
|
||||
initDone = 1;
|
||||
oldSweepPoints = data.Points.length;
|
||||
oldDataPointCount = data.Points.length;
|
||||
}
|
||||
chartSA.options.data[3].dataPoints = chartSA.options.data[0].dataPoints.map((obj, index) => { // average trace
|
||||
let rObj = {}
|
||||
rObj.x = obj.x
|
||||
rObj.y = chartSA.options.data[3].dataPoints[index].y*(1-1/setAverage) + obj.y*1/setAverage;
|
||||
return rObj
|
||||
})
|
||||
|
||||
chartSA.options.axisX.minimum = setStart.value;
|
||||
chartSA.options.axisX.maximum = setStop.value;
|
||||
// chartSA.options.axisY.minimum = -120;
|
||||
// chartSA.options.axisY.maximum = 0;
|
||||
chartSA.options.axisY2.minimum = 0;
|
||||
chartSA.options.axisY2.maximum = 255;
|
||||
// RSSISamples.from(data.Points); // moves data
|
||||
//console.log(RSSISamples[10].y);
|
||||
// update the chart
|
||||
chartSA.render();
|
||||
}
|
||||
|
||||
|
||||
function handleChunkData (data)
|
||||
{
|
||||
var init = false;
|
||||
var n = data.sweepPoints;
|
||||
|
||||
if (n != oldSweepPoints) {
|
||||
// reset chart data
|
||||
chartSA.options.data[0].dataPoints.length = 0;
|
||||
chartSA.options.data[1].dataPoints.length = 0;
|
||||
chartSA.options.data[2].dataPoints.length = 0;
|
||||
chartSA.options.data[3].dataPoints.length = 0;
|
||||
chartSA.options.data[4].dataPoints.length = 0;
|
||||
|
||||
|
||||
// add dummy data points
|
||||
var i;
|
||||
for (i=0; i<n; i++) {
|
||||
var p = {x:250, y:-120};
|
||||
var q = {x:250, y:0};
|
||||
var r = {x:250, y:49};
|
||||
var s = {x:250, y:-120};
|
||||
var m = {x:250, y:10};
|
||||
chartSA.options.data[0].dataPoints.push(p); // dB
|
||||
chartSA.options.data[1].dataPoints.push(q); // RSSI
|
||||
chartSA.options.data[2].dataPoints.push(r); // gain
|
||||
chartSA.options.data[3].dataPoints.push(s); // average
|
||||
chartSA.options.data[4].dataPoints.push(m); // min - initialise to high value
|
||||
}
|
||||
|
||||
//chartSA.options.data[0].dataPoints.length = n; // reduces size if > no of data points
|
||||
//chartSA.options.data[1].dataPoints.length = n;
|
||||
//chartSA.options.data[2].dataPoints.length = n;
|
||||
//chartSA.options.data[3].dataPoints.length = n;
|
||||
|
||||
sweepPoints.value = data.sweepPoints;
|
||||
init = true;
|
||||
initDone = false;
|
||||
oldSweepPoints = n;
|
||||
//chartSA.render();
|
||||
}
|
||||
|
||||
var dataStart = data.StartIndex;
|
||||
|
||||
var b = parseInt(levelOffset.value) + parseInt(setAtten.value) - 120 - parseFloat(setExtern.value);
|
||||
|
||||
var a = 1/setAverage.value;
|
||||
|
||||
data.Points.forEach (function (point, index) { // copy data into the chart data series
|
||||
var p = {};
|
||||
p = point; // create a copy not a reference ??
|
||||
var f = {};
|
||||
f = point.x;
|
||||
chartSA.options.data[1].dataPoints[dataStart + index] = p; // RSSI
|
||||
|
||||
chartSA.options.data[0].dataPoints[dataStart + index].x = f * 1;
|
||||
var dB = p.y/2+b;
|
||||
chartSA.options.data[0].dataPoints[dataStart + index].y = dB * 1;
|
||||
|
||||
|
||||
//chartSA.options.data[3].dataPoints[dataStart + index] = point;
|
||||
//try {
|
||||
//chartSA.options.data[3].dataPoints[dataStart + index].x = f * 1;
|
||||
// if (initDone) {
|
||||
// var av = chartSA.options.data[3].dataPoints[dataStart + index].y*(1-a) + dB*a;
|
||||
// chartSA.options.data[3].dataPoints[dataStart + index].y = av * 1;
|
||||
// } else {
|
||||
// chartSA.options.data[3].dataPoints[dataStart + index].y = dB * 1;
|
||||
// }
|
||||
//}
|
||||
//catch {
|
||||
// chartSA.options.data[3].dataPoints[dataStart + index].y = point.y/2+b;
|
||||
//}
|
||||
|
||||
})
|
||||
|
||||
|
||||
// If end of sweep update the average and min data sets
|
||||
if (dataStart + data.Points.length >= data.sweepPoints) {
|
||||
if (!initDone) { // If first time then set the values to current dB series
|
||||
initDone = true;
|
||||
chartSA.options.data[3].dataPoints = chartSA.options.data[0].dataPoints.map((obj, index) => { // average trace
|
||||
let rObj = {}
|
||||
rObj.x = obj.x;
|
||||
rObj.y = obj.y*1;
|
||||
return rObj
|
||||
})
|
||||
chartSA.options.data[4].dataPoints = chartSA.options.data[0].dataPoints.map((obj, index) => { // average trace
|
||||
let rObj = {}
|
||||
rObj.x = obj.x;
|
||||
rObj.y = obj.y*1;
|
||||
return rObj
|
||||
})
|
||||
} else {
|
||||
chartSA.options.data[3].dataPoints = chartSA.options.data[0].dataPoints.map((obj, index) => { // average trace
|
||||
let rObj = {}
|
||||
rObj.x = obj.x;
|
||||
rObj.y = chartSA.options.data[3].dataPoints[index].y*(1-a) + obj.y*a;
|
||||
return rObj
|
||||
})
|
||||
chartSA.options.data[4].dataPoints = chartSA.options.data[0].dataPoints.map((obj, index) => { // average trace
|
||||
let rObj = {}
|
||||
rObj.x = obj.x;
|
||||
rObj.y = Math.min(chartSA.options.data[4].dataPoints[index].y, obj.y);
|
||||
return rObj
|
||||
})
|
||||
}
|
||||
|
||||
if (chartSA.options.data[2].visible) {
|
||||
$.getJSON( "getGainSweep") // proper line
|
||||
// $.getJSON( "getGainSweep.json") // for local test
|
||||
.done(function (data) {
|
||||
// We have the data, process it.
|
||||
chartSA.options.data[2].dataPoints = data.gainPoints; // Gain trace
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//chartSA.render();
|
||||
|
||||
// dataPoints.value = chartSA.options.data[0].dataPoints.length;
|
||||
sweepTime.value = data.sweepTime;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function update()
|
||||
{
|
||||
// Get the settings
|
||||
|
||||
$.getJSON( "getSettings")
|
||||
.done(function (settings) {
|
||||
handleSettings(settings);
|
||||
})
|
||||
|
||||
.fail(function(jqxhr, textStatus, error) {
|
||||
var err = textStatus +", " + error;
|
||||
console.log("Settings Request Failed: " + err);
|
||||
});
|
||||
|
||||
|
||||
// Get the sweep data
|
||||
|
||||
$.getJSON( "getSweep") // proper line
|
||||
// $.getJSON( "getSweep.json") // for local test
|
||||
.done(function (data) {
|
||||
// We have the data, process it.
|
||||
handleData(data);
|
||||
//setTimeout(update, indexUpdateMilliSeconds);
|
||||
|
||||
})
|
||||
|
||||
.fail(function(jqxhr, textStatus, error) {
|
||||
var err = textStatus +", " + error;
|
||||
console.log("Sweep Request Failed: " + err);
|
||||
});
|
||||
|
||||
|
||||
if (chartSA.options.data[2].visible) {
|
||||
$.getJSON( "getGainSweep") // proper line
|
||||
// $.getJSON( "getGainSweep.json") // for local test
|
||||
.done(function (data) {
|
||||
// We have the data, process it.
|
||||
chartSA.options.data[2].dataPoints = data.gainPoints; // Gain trace
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// This method is called to add all necessary options to a
|
||||
// select representing the available resolution bandwidths(RBW).
|
||||
// default is auto
|
||||
*/
|
||||
function buildRBWSelect()
|
||||
{
|
||||
let dropdown = $('#setRBW');
|
||||
|
||||
dropdown.empty();
|
||||
|
||||
// Populate dropdown with list of RBW
|
||||
$.getJSON("getRbwList", function (data) {
|
||||
dropdown.append($('<option class="select-option" ></option>').attr('value', 0).text("Auto"));
|
||||
|
||||
$.each(data, function (key, bpf) {
|
||||
dropdown.append($('<option class="select-option" ></option>').attr('value', bpf.bw10).text(bpf.bw));
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
//dropdown.prop('selectedIndex', 0);
|
||||
}
|
||||
|
||||
buildRBWSelect();
|
||||
|
||||
|
||||
/*
|
||||
// This method is called to add all necessary options to a
|
||||
// select representing the available attenuations.
|
||||
// default is auto
|
||||
*/
|
||||
function buildAttenSelect()
|
||||
{
|
||||
let dropdown = $('#setAtten');
|
||||
|
||||
dropdown.empty();
|
||||
|
||||
// Populate dropdown with list of RBW
|
||||
$.getJSON("getAttenList", function (data) {
|
||||
$.each(data, function (key, att) {
|
||||
dropdown.append($('<option class="select-option" ></option>').attr('value', att.dB).text(att.dB));
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
//dropdown.prop('selectedIndex', 0);
|
||||
}
|
||||
|
||||
//buildAttenSelect();
|
||||
|
||||
|
||||
|
||||
function connect(host)
|
||||
{
|
||||
if(connection)
|
||||
{
|
||||
//connection.close(); // restart
|
||||
return; // already connected
|
||||
}
|
||||
|
||||
connectionStatus.value = "Connecting...";
|
||||
connection = new WebSocket(host, ['arduino']);
|
||||
|
||||
connection.onopen = function()
|
||||
{
|
||||
connectionStatus.value = "Connected";
|
||||
connectionStatus.style = "background-color:lightgreen";
|
||||
connection.send('Hello from Browser :-) ' + new Date());
|
||||
sendMessage();
|
||||
sendPingVar = setInterval(function(){ sendPing() }, 30000);
|
||||
|
||||
sendValue("r",0); // request settings
|
||||
|
||||
// Get the settings to make sure current
|
||||
//$.getJSON( "getSettings")
|
||||
// .done(function (settings) {
|
||||
// handleSettings(settings);
|
||||
// })
|
||||
//
|
||||
// .fail(function(jqxhr, textStatus, error) {
|
||||
// var err = textStatus +", " + error;
|
||||
// console.log("Settings Request Failed: " + err);
|
||||
// });
|
||||
|
||||
var items = document.querySelectorAll(".value-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = false;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".select-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
connection.onclose = function(event)
|
||||
{
|
||||
clearInterval(sendPingVar);
|
||||
connectionStatus.value = "Disconnected";
|
||||
connectionStatus.style = "background-color:red";
|
||||
//connection.removeEventListeners();
|
||||
connection = null;
|
||||
// Disable user input
|
||||
var items = document.querySelectorAll(".value-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = true;
|
||||
}
|
||||
|
||||
var items = document.querySelectorAll(".select-input");
|
||||
var i;
|
||||
for (i = 0; i< items.length; i++) {
|
||||
items[i].disabled = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
connection.onerror = function(error)
|
||||
{
|
||||
console.log("WebSocket Error ", error);
|
||||
};
|
||||
|
||||
connection.onmessage = function(message) // to be used later when we send data at each sweep
|
||||
{
|
||||
//console.log("Websocket message received");
|
||||
|
||||
// show message
|
||||
//messageWindow.value = message.data;
|
||||
//messageSize.value = message.data.length;
|
||||
|
||||
// check only messages begining with '{'
|
||||
if(message.data[0] == "{")
|
||||
{
|
||||
// //console.log("Parsing message");
|
||||
myObject = JSON.parse(message.data);
|
||||
//console.log("message type " + myObject.mType);
|
||||
if (myObject.mType == "Settings")
|
||||
{
|
||||
pointsCount = myObject.dispPoints;
|
||||
// sweepSamples = myObject.Points;
|
||||
//console.log("handle settings");
|
||||
handleSettings(myObject);
|
||||
}
|
||||
else if (myObject.mType == "fullSweep")
|
||||
{
|
||||
//console.log("handle full Sweep");
|
||||
handleData(myObject);
|
||||
}
|
||||
else if (myObject.mType == "chunkSweep")
|
||||
{
|
||||
//console.log("handle chunk Sweep:" + myObject.StartIndex);
|
||||
handleChunkData(myObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("Invalid json message type");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function disconnect()
|
||||
{
|
||||
if(connection)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionStatus.value = "Not connected yet";
|
||||
}
|
||||
}
|
||||
|
||||
function sendValue(c, val)
|
||||
{
|
||||
//
|
||||
// Message format
|
||||
// #(code) value where code is a single char. Case is important
|
||||
// a start freq (MHz) - sig gen freq if in sig gen mode
|
||||
// b stop frequency
|
||||
// c centre frequency
|
||||
// s Span
|
||||
// d Local Oscillator Drive
|
||||
// g PreAmpGain/Mode
|
||||
// i IF frequency
|
||||
// m mode
|
||||
// p set actual power to peak value
|
||||
// o RefOut
|
||||
// r request Settings are pushed
|
||||
// A internal attenuation (PE4302)
|
||||
// E external gain ( eg attenuator(-ve) or preamp(+ve) )
|
||||
// R requested RBW
|
||||
// S Spur reduction Off/On
|
||||
// t trackGen Off/On/Fixed
|
||||
// T trackGen output level
|
||||
// L Sig Gen level (dBm)
|
||||
// G Sig Gen Off/On
|
||||
// P Sig Gen set max output level (dBm)
|
||||
//
|
||||
//connection.send("# " + messageCounter + " " + sampleThreshold + " " + sampleSize);
|
||||
connection.send("#" + c + " " + val);
|
||||
console.log("Command:" + c + val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sendMessage()
|
||||
{
|
||||
messageCounter++;
|
||||
//messageCount.value = messageCounter;
|
||||
dateObject = new Date();
|
||||
messageSendMilis = dateObject.getTime();
|
||||
//
|
||||
// Message format
|
||||
// # MESSAGE_NUMBER SAMPLE_THRESHOLD NUMBER_OF_SAMPLES
|
||||
//
|
||||
//connection.send("# " + messageCounter + " " + sampleThreshold + " " + sampleSize);
|
||||
connection.send("# " + messageCounter + " " + sweepStart + " " + sweepStop);
|
||||
}
|
||||
|
||||
function sendPing()
|
||||
{
|
||||
connection.send('ping');
|
||||
pingCounter++;
|
||||
connectionPings.value = pingCounter;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
158
data/styles.css
158
data/styles.css
@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
.norm {
|
||||
width: 100%;
|
||||
width: 95%;
|
||||
height: 3vh;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-top: 5px;
|
||||
@ -127,6 +127,14 @@ input[type="number"] {
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
.sweep-display {
|
||||
border: 0;
|
||||
text-align: right;
|
||||
width: 65px;
|
||||
display: inline-block;
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
.message-display {
|
||||
border: 0;
|
||||
text-align: left;
|
||||
@ -156,17 +164,47 @@ input[type="number"] {
|
||||
border: solid 1px grey;
|
||||
text-align: right;
|
||||
text-align-last: right;
|
||||
width: 75px;
|
||||
width: 77px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Sweep-select {
|
||||
border: solid 1px grey;
|
||||
text-align: left;
|
||||
text-align-last: left;
|
||||
width: 150px;
|
||||
display: inline-block;
|
||||
color: black;
|
||||
font-weight: bolder;
|
||||
background-repeat: no-repeat;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.select-option {
|
||||
text-align: right;
|
||||
text-align-last: right;
|
||||
}
|
||||
.sweep-option {
|
||||
text-align: left;
|
||||
text-align-last: left;
|
||||
}
|
||||
|
||||
.set-button {
|
||||
font-size: 14px;
|
||||
.inc-button {
|
||||
width: 60px;
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
float: right;
|
||||
margin-right:60px;
|
||||
margin-top:3px;
|
||||
}
|
||||
|
||||
.on-button {
|
||||
width: 60px;
|
||||
height: 33px;
|
||||
font-size: 14px;
|
||||
float: right;
|
||||
margin-right:0px;
|
||||
margin-top:3px;
|
||||
}
|
||||
|
||||
.setting {
|
||||
@ -176,8 +214,120 @@ input[type="number"] {
|
||||
.setting-label {
|
||||
width: 80px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.setting-widelabel {
|
||||
width: 138px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sigTitle {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sigFreq {
|
||||
font-weight: bolder;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
letter-spacing: -10px;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.sigFreqLabel {
|
||||
width: 180px;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
.sigFreqText {
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
input.sigFreqInput {
|
||||
border: solid 1px grey;
|
||||
text-align: right;
|
||||
width: 18px;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input.sigFrequencyInput {
|
||||
border: solid 1px grey;
|
||||
text-align: right;
|
||||
width: 180px;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input.sigFreqInput::-webkit-outer-spin-button,
|
||||
input.sigFreqInput::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
input.sigFreqInput {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.sigLevelLabel {
|
||||
width: 180px;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
input.sigLevelInput {
|
||||
border: solid 1px grey;
|
||||
text-align: right;
|
||||
width: 180px;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
|
||||
TH, .bold {
|
||||
background-color: lightblue;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 340px;
|
||||
height: 15px;
|
||||
border-radius: 5px;
|
||||
background: #d3d3d3;
|
||||
outline: none;
|
||||
opacity: 0.7;
|
||||
-webkit-transition: .2s;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
4
my_SA.h
4
my_SA.h
@ -25,6 +25,7 @@
|
||||
|
||||
#define USE_WIFI true // Changed in Version 2.6 to true/false
|
||||
// #define USE_ACCESS_POINT // Comment out if want to connect to SSID, leave in to use access point
|
||||
// #define AP_PASSWORD "none"
|
||||
|
||||
#define WIFI_SSID ":)" // SSID of your WiFi if not using access point
|
||||
#define WIFI_PASSWORD "S0ftR0ckRXTX" // Password for your WiFi
|
||||
@ -64,6 +65,9 @@
|
||||
// #define SLIDER_MAX_POWER -13.0
|
||||
#define ATTENUATOR_RANGE 30 // in dB
|
||||
|
||||
// the B3555 SAW filter has max power rating of 10dBm.
|
||||
// Drive of 4 = 11dBm but 1 dB pad in my build. If you have a larger attenuator pad you can try higher powers
|
||||
#define RX_SI4432_MAX_DRIVE 4 // corresponds to 11dBm
|
||||
|
||||
/*
|
||||
* These definitions control the values that get set when you select "AUTO SETTINGS" from
|
||||
|
@ -272,7 +272,7 @@ const char* unit[4] = { "RX", "TX", "TGIF", "TGLO" }; // For debugging
|
||||
|
||||
WriteByte ( REG_OFC1, SW_RESET ); // Always perform a system reset
|
||||
|
||||
while ( millis() - startTime < 10000 ) // Try for 10 seconds
|
||||
while ( millis() - startTime < 2000 ) // Try for 2 seconds
|
||||
{
|
||||
regRead = ReadByte ( REG_IS2 );
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
#define PROGRAM_NAME "simpleSA" // These are for the WiFi interface
|
||||
#define PROGRAM_VERSION "0.01" // Current version is 0.01 - beta!
|
||||
#define PROGRAM_VERSION "Version 0.1" // Current version - beta!
|
||||
|
||||
|
||||
/*
|
||||
@ -186,7 +186,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, RX_SWEEP };
|
||||
IF_SWEEP, ZERO_SPAN_LOW_RANGE, ZERO_SPAN_HIGH_RANGE, BANDSCOPE, RX_SWEEP };
|
||||
|
||||
|
||||
/*
|
||||
|
48
simpleSA.ino
48
simpleSA.ino
@ -127,11 +127,20 @@
|
||||
* Additional functions in ui.cmd to allow signed frequency entry.
|
||||
*
|
||||
* Version 3.0f Changes by M0WID
|
||||
*
|
||||
* Version 0.03
|
||||
* 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! Version numbering changed - still in beta!
|
||||
*
|
||||
* Version 0.1
|
||||
* Tracking generator now can be used as a signal generator
|
||||
* Web page for signal generator
|
||||
* RX sweep for testing the SI4432 FIR filters
|
||||
* Output range of signal generator increased by also reducing SI4432 output power as well as uing attenuator
|
||||
* Storage feature - temporary only not to disk - added to web page traces
|
||||
* X grid lines added to web chart
|
||||
*/
|
||||
|
||||
|
||||
@ -348,13 +357,14 @@ uint8_t numberOfWebsocketClients; // How many connections
|
||||
uint16_t wiFiPoints; // Push data to the wifi clinets when this many points collected
|
||||
unsigned long wiFiTargetTime = WIFI_UPDATE_TARGET_TIME;
|
||||
unsigned long websocketInterval = WEBSOCKET_INTERVAL;
|
||||
uint16_t websocketFailCount;
|
||||
|
||||
#ifdef USE_WIFI
|
||||
// Json document buffers
|
||||
size_t capacity = JSON_ARRAY_SIZE ( MAX_WIFI_POINTS + 1 )
|
||||
+ ( MAX_WIFI_POINTS + 1 ) * JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE( 5 );
|
||||
//size_t capacity = JSON_ARRAY_SIZE ( MAX_WIFI_POINTS + 1 )
|
||||
// + ( MAX_WIFI_POINTS + 1 ) * JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE( 5 );
|
||||
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // Buffer for json data to be pushed to the web clients
|
||||
static DynamicJsonDocument jsonDocument ( 4000 ); // Buffer for json data to be pushed to the web clients
|
||||
static JsonArray Points = jsonDocument.createNestedArray ( "Points" ); // add Points array
|
||||
#endif
|
||||
|
||||
@ -380,7 +390,7 @@ 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", "BScp", "RXSw" }; // For mode display
|
||||
const char *modeText[] = { "SALo", "SAHi", "SGLo", "SGHi", "IFSw", "0SpL", "0SpH", "BScp", "RXSw" }; // For mode display
|
||||
|
||||
|
||||
float bandwidth; // The current bandwidth (not * 10)
|
||||
@ -503,7 +513,7 @@ uint16_t spacing = 10000;
|
||||
|
||||
bool paused = false;
|
||||
|
||||
bool sigGenOutputOn = false;
|
||||
uint16_t sigGenOutputOn = false;
|
||||
uint32_t oldFreq; // to store the current Signal Generator frequency
|
||||
|
||||
/*
|
||||
@ -671,6 +681,7 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
|
||||
// If the tracking generator IF SI4432 is defined, then check to see if it is connected
|
||||
tgIF_OK = false;
|
||||
|
||||
#ifdef SI_TG_IF_CS
|
||||
// pinMode (SI_TG_IF_CS, INPUT); //Start off in input mode, no pullup
|
||||
// delay(2);
|
||||
@ -680,6 +691,8 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
// delay(2);
|
||||
// tgIF_OK = tg_if.Init ( config.tgIF_capacitance );
|
||||
|
||||
tft.setCursor(0,180);
|
||||
tft.println ( "Initializing track gen IF SI4432" );
|
||||
if ( tg_if.Init ( config.tgIF_capacitance ) )
|
||||
{
|
||||
tft.println ("Tracking IF initialised");
|
||||
@ -708,6 +721,7 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
|
||||
// If the tracking generator LO SI4432 is defined, then check to see if it is connected
|
||||
tgLO_OK = false;
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
// pinMode (SI_TG_LO_CS, INPUT); //Start off in input mode, no pullup
|
||||
// delay(2);
|
||||
@ -715,6 +729,9 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
// // Tracking gen LO present - initialise it, but not in TX mode yet
|
||||
// pinMode (SI_TG_LO_CS, OUTPUT);
|
||||
// delay(2);
|
||||
|
||||
tft.println ( "Initializing track gen LO SI4432" );
|
||||
|
||||
tgLO_OK = tg_lo.Init ( config.tgLO_capacitance );
|
||||
if ( tgLO_OK )
|
||||
tft.println ("Tracking LO initialised");
|
||||
@ -729,7 +746,9 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
// pinMode (SI_TG_LO_CS, OUTPUT);
|
||||
// digitalWrite(SI_TG_LO_CS, HIGH); // make sure it doesn't get selected
|
||||
// }
|
||||
|
||||
#else
|
||||
pinMode (25, OUTPUT);
|
||||
digitalWrite(25, HIGH); // make sure it doesn't get selected
|
||||
#endif
|
||||
|
||||
|
||||
@ -809,7 +828,7 @@ bool fsStatus = false; // True if SPIFFS loads ok
|
||||
|
||||
// tft.println("Setup Complete");
|
||||
|
||||
Serial.printf ( "\nTinySA Version %s Initialization Complete\n", PROGRAM_VERSION );
|
||||
Serial.printf ( "\nsimpleSA %s Initialization Complete\n", PROGRAM_VERSION );
|
||||
|
||||
ShowMenu (); // Display the menu of commands on serial monitor
|
||||
|
||||
@ -1113,6 +1132,21 @@ void init_sweep()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the JSON document that is used to push the sweep data to the web clients
|
||||
* Used in all the sweep modes
|
||||
*/
|
||||
void initChunkSweepDoc (uint32_t startIndex)
|
||||
{
|
||||
jsonDocument.clear ();
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
jsonDocument["mType"] = "chunkSweep";
|
||||
jsonDocument["StartIndex"] = startIndex;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["sweepTime"] = (uint32_t)(sweepMicros/1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Initialise high frequency mode sweep.
|
||||
|
@ -33,12 +33,15 @@ extern uint16_t displayPoints;
|
||||
extern uint16_t xDelta;
|
||||
extern uint16_t waterfallHeight;
|
||||
|
||||
extern unsigned long sweepMicros; // To report the scan time
|
||||
|
||||
|
||||
extern int bpfCount; // Number of elements in the bandpassFilters array
|
||||
extern int updateSidebar; // Flag to indicate no of clients has changed
|
||||
extern void ClearDisplay ();
|
||||
extern void DisplayError ( uint8_t severity, const char *l1, const char *l2, const char *l3, const char *l4 );
|
||||
|
||||
extern void setMode (uint16_t newMode);
|
||||
|
||||
/*
|
||||
* In Version 1.8, the transmitter and receiver Si4432 modules are implemented as
|
||||
@ -54,6 +57,7 @@ extern uint8_t AGC_Reg; // Fixed value for preampGain if not auto
|
||||
extern uint32_t startFreq_IF;
|
||||
extern uint32_t stopFreq_IF;
|
||||
extern uint32_t sigFreq_IF;
|
||||
extern uint16_t sigGenOutputOn;
|
||||
|
||||
extern uint32_t startFreq_RX;
|
||||
extern uint32_t stopFreq_RX;
|
||||
@ -101,7 +105,14 @@ boolean startAP () // Start the WiFi Access Point, keep the user informed.
|
||||
{
|
||||
ClearDisplay (); // Fade to black
|
||||
|
||||
|
||||
|
||||
Serial.println ( "Starting Access Point" ); // Put in the instructions
|
||||
|
||||
delay(2000);
|
||||
|
||||
// Scan WiFi SSIDs
|
||||
WiFi.scanNetworks(true);
|
||||
|
||||
|
||||
/*
|
||||
@ -123,9 +134,9 @@ boolean startAP () // Start the WiFi Access Point, keep the user informed.
|
||||
DisplayError ( ERR_WARN, "Failed to open AP:", "WiFi Disabled", NULL, NULL );
|
||||
|
||||
else
|
||||
ipAddress = WiFi.localIP ();
|
||||
ipAddress = WiFi.softAPIP();
|
||||
|
||||
Serial.printf ( "Access Point started, result = %b \n", result );
|
||||
Serial.printf ( "Access Point started, result = %i \n", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -210,10 +221,32 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
|
||||
|
||||
/*
|
||||
* Format of message to process
|
||||
*
|
||||
* #a 123.123 Start frequency
|
||||
* #b 123.123 Stop frequency
|
||||
* Message format
|
||||
* #(code) value where code is a single char. Case is important
|
||||
*
|
||||
* a start freq (MHz) - sig gen freq if in sig gen mode
|
||||
* b stop frequency
|
||||
* c centre frequency
|
||||
* s Span
|
||||
* d Local Oscillator Drive
|
||||
* g PreAmpGain/Mode
|
||||
* i IF frequency
|
||||
* m mode
|
||||
* p set actual power to peak value
|
||||
* o RefOut
|
||||
* r request Settings are pushed
|
||||
* A internal attenuation (PE4302)
|
||||
* E external gain ( eg attenuator(-ve) or preamp(+ve) )
|
||||
* R requested RBW
|
||||
* S Spur reduction Off/On
|
||||
* t trackGen Off/On/Generate
|
||||
* T trackGen output level
|
||||
* f trackgen signal generator frequency
|
||||
* F Sig Gen frequency
|
||||
* L Sig Gen level (dBm)
|
||||
* G Sig Gen Off/On
|
||||
* P Sig Gen set max output level (dBm)
|
||||
*
|
||||
* Other formats are ignored
|
||||
*/
|
||||
@ -234,11 +267,37 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
switch ( payload[1] )
|
||||
{
|
||||
case 'a':
|
||||
SetSweepStart ( value * 1000000.0 ); // Set sweep start frequency
|
||||
switch (setting.Mode) {
|
||||
case SA_LOW_RANGE:
|
||||
SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency
|
||||
break;
|
||||
case SIG_GEN_LOW_RANGE:
|
||||
SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency
|
||||
break;
|
||||
case IF_SWEEP:
|
||||
SetIFsweepStart ( value * 1000000.0 ); // Set IF sweep start frequency
|
||||
break;
|
||||
case RX_SWEEP:
|
||||
SetRXsweepStart ( value * 1000000.0 ); // Set RX sweep start frequency
|
||||
break;
|
||||
case BANDSCOPE:
|
||||
SetBandscopeStart ( value * 1000000.0 ); // Set sweep start frequency
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
SetSweepStop ( value * 1000000.0 ); // Set sweep stop frequency
|
||||
switch (setting.Mode) {
|
||||
case SA_LOW_RANGE:
|
||||
SetSweepStop ( value * 1000000.0 ); // Set Low range sweep start frequency
|
||||
break;
|
||||
case IF_SWEEP:
|
||||
SetIFsweepStop ( value * 1000000.0 ); // Set IF sweep start frequency
|
||||
break;
|
||||
case RX_SWEEP:
|
||||
SetRXsweepStop ( value * 1000000.0 ); // Set RX sweep start frequency
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
@ -249,6 +308,10 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
SetLoDrive ( (uint8_t) value );
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
SetTGFreq ( value );
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
SetPreampGain( (int) value ); // Set PreAmp gain register
|
||||
break;
|
||||
@ -257,6 +320,10 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
SetIFFrequency ( (int32_t) ( value * 1000000.0 ));
|
||||
break;
|
||||
|
||||
case 'm': // Set mode
|
||||
setMode ( (int16_t) ( value ));
|
||||
break;
|
||||
|
||||
case 'o': // Ref Output (LO GPIO2)
|
||||
SetRefOutput ( (int) value );
|
||||
break;
|
||||
@ -265,10 +332,43 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
RequestSetPowerLevel( value );
|
||||
break;
|
||||
|
||||
case 'r': // request of settings by client
|
||||
switch (setting.Mode)
|
||||
{
|
||||
case (SA_LOW_RANGE):
|
||||
pushSettings();
|
||||
break;
|
||||
|
||||
case (IF_SWEEP):
|
||||
pushIFSweepSettings();
|
||||
break;
|
||||
|
||||
case (RX_SWEEP):
|
||||
pushRXSweepSettings();
|
||||
break;
|
||||
|
||||
case (BANDSCOPE):
|
||||
pushBandscopeSettings();
|
||||
break;
|
||||
|
||||
case (SIG_GEN_LOW_RANGE):
|
||||
pushSigGenSettings();
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.println("Invalid mode in Request setting handler - simpleSA_wifi.cpp");
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': // Adjust sweep span
|
||||
SetSweepSpan ( (int32_t) ( value * 1000000.0 ));
|
||||
break;
|
||||
|
||||
case 't': // Tracking Generator off/on/generate
|
||||
SetTracking ( (int8_t)value );
|
||||
break;
|
||||
|
||||
case 'A': // Internal Attenuation (PE4302)
|
||||
SetAttenuation ( value );
|
||||
break;
|
||||
@ -277,6 +377,18 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
SetExtGain ( value );
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
SetSGFreq ( value ); // Signal Generator Frequency
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
SetSGState ( (uint16_t)value ); // Signal Generator output on/off
|
||||
break;
|
||||
|
||||
case 'L': // Signal Generator output power (dBm)
|
||||
SetSGPower ( value );
|
||||
break;
|
||||
|
||||
case 'R': // Requested RBW. 0=Auto
|
||||
SetRBW ( value );
|
||||
Serial.printf("Wifi RBW %f\n", value);
|
||||
@ -286,10 +398,6 @@ void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t paylo
|
||||
SetSpur ( (int8_t)value );
|
||||
break;
|
||||
|
||||
case 't': // Tracking Generator on/off
|
||||
SetTracking ( (int8_t)value );
|
||||
break;
|
||||
|
||||
case 'T': // Tracking Generator output power (dBm)
|
||||
SetTGPower ( value );
|
||||
break;
|
||||
@ -508,6 +616,7 @@ void onGetSettings (AsyncWebServerRequest *request)
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["mType"] = "Settings";
|
||||
root["mode"] = setting.Mode;
|
||||
root["dispPoints"] = displayPoints;
|
||||
root["start"] = setting.ScanStart / 1000.0;
|
||||
root["stop"] = setting.ScanStop / 1000.0;
|
||||
@ -523,6 +632,18 @@ void onGetSettings (AsyncWebServerRequest *request)
|
||||
root["spur"] = setting.Spur;
|
||||
root["tg"] = trackGenSetting.Mode;
|
||||
root["tgPower"] = trackGenSetting.Power;
|
||||
root["tgFreq"] = trackGenSetting.Frequency;
|
||||
root["tgMod"] = trackGenSetting.ModulationType;
|
||||
root["tgModFreq"] = trackGenSetting.ModFrequency;
|
||||
root["sg"] = sigGenOutputOn; //
|
||||
root["sgPower"] = sigGenSetting.Power;
|
||||
root["sgMod"] = sigGenSetting.ModulationType;
|
||||
root["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
root["sgFreq"] = sigGenSetting.Frequency;
|
||||
root["sgCal"] = sigGenSetting.Calibration;
|
||||
root["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
root["tgCal"] = trackGenSetting.Calibration;
|
||||
root["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
root["PreAmp"] = 0x60; // Auto
|
||||
@ -546,10 +667,11 @@ if ( numberOfWebsocketClients == 0 )
|
||||
return;
|
||||
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 16 );
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["mode"] = setting.Mode;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = setting.ScanStart / 1000.0;
|
||||
jsonDocument["stop"] = setting.ScanStop / 1000.0;
|
||||
@ -565,10 +687,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
jsonDocument["spur"] = setting.Spur;
|
||||
jsonDocument["tg"] = trackGenSetting.Mode;
|
||||
jsonDocument["tgPower"] = trackGenSetting.Power;
|
||||
|
||||
jsonDocument["tgFreq"] = trackGenSetting.Frequency;
|
||||
jsonDocument["tgMod"] = trackGenSetting.ModulationType;
|
||||
jsonDocument["tgModFreq"] = trackGenSetting.ModFrequency;
|
||||
jsonDocument["sg"] = sigGenOutputOn; //
|
||||
jsonDocument["sgPower"] = sigGenSetting.Power;
|
||||
jsonDocument["sgMod"] = sigGenSetting.ModulationType;
|
||||
jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
jsonDocument["sgFreq"] = sigGenSetting.Frequency;
|
||||
jsonDocument["sgCal"] = sigGenSetting.Calibration;
|
||||
jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
jsonDocument["tgCal"] = trackGenSetting.Calibration;
|
||||
jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
jsonDocument["PreAmp"] = 0x60; // Auto
|
||||
|
||||
else
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
|
||||
@ -579,7 +712,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
|
||||
@ -593,14 +725,15 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
void pushIFSweepSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["mode"] = setting.Mode;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = startFreq_IF / 1000.0;
|
||||
jsonDocument["stop"] = stopFreq_IF / 1000.0;
|
||||
jsonDocument["IF"] = sigFreq_IF / 1000000.0;
|
||||
jsonDocument["IF"] = setting.IF_Freq / 1000000.0;
|
||||
jsonDocument["attenuation"] = setting.Attenuate;
|
||||
jsonDocument["extGain"] = setting.ExternalGain;
|
||||
jsonDocument["levelOffset"] = setting.LevelOffset;
|
||||
@ -610,10 +743,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
jsonDocument["Drive"] = setting.Drive;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["spur"] = setting.Spur;
|
||||
|
||||
jsonDocument["tg"] = trackGenSetting.Mode;
|
||||
jsonDocument["tgPower"] = trackGenSetting.Power;
|
||||
jsonDocument["tgFreq"] = trackGenSetting.Frequency;
|
||||
jsonDocument["sg"] = sigGenOutputOn; //
|
||||
jsonDocument["sgPower"] = sigGenSetting.Power;
|
||||
jsonDocument["sgMod"] = sigGenSetting.ModulationType;
|
||||
jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
jsonDocument["sgFreq"] = sigGenSetting.Frequency;
|
||||
jsonDocument["sgCal"] = sigGenSetting.Calibration;
|
||||
jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
jsonDocument["tgCal"] = trackGenSetting.Calibration;
|
||||
jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
jsonDocument["PreAmp"] = 0x60; // Auto
|
||||
|
||||
else
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
|
||||
@ -624,7 +768,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
|
||||
@ -638,10 +781,11 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
void pushRXSweepSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["mode"] = setting.Mode;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = startFreq_RX / 1000.0;
|
||||
jsonDocument["stop"] = stopFreq_RX / 1000.0;
|
||||
@ -655,10 +799,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
jsonDocument["Drive"] = setting.Drive;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["spur"] = setting.Spur;
|
||||
|
||||
jsonDocument["tg"] = trackGenSetting.Mode;
|
||||
jsonDocument["tgPower"] = trackGenSetting.Power;
|
||||
jsonDocument["tgFreq"] = trackGenSetting.Frequency;
|
||||
jsonDocument["sg"] = sigGenOutputOn; //
|
||||
jsonDocument["sgPower"] = sigGenSetting.Power;
|
||||
jsonDocument["sgMod"] = sigGenSetting.ModulationType;
|
||||
jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
jsonDocument["sgFreq"] = sigGenSetting.Frequency;
|
||||
jsonDocument["sgCal"] = sigGenSetting.Calibration;
|
||||
jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
jsonDocument["tgCal"] = trackGenSetting.Calibration;
|
||||
jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
jsonDocument["PreAmp"] = 0x60; // Auto
|
||||
|
||||
else
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
|
||||
@ -669,7 +824,6 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
|
||||
@ -683,10 +837,11 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
void pushBandscopeSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 13 );
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["mode"] = setting.Mode;
|
||||
jsonDocument["dispPoints"] = setting.BandscopePoints;
|
||||
jsonDocument["start"] = setting.BandscopeStart / 1000.0;
|
||||
jsonDocument["stop"] = ( setting.BandscopeStart + setting.BandscopeSpan ) / 1000.0;
|
||||
@ -700,10 +855,21 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
jsonDocument["Drive"] = setting.Drive;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["spur"] = setting.Spur;
|
||||
|
||||
jsonDocument["tg"] = trackGenSetting.Mode;
|
||||
jsonDocument["tgPower"] = trackGenSetting.Power;
|
||||
jsonDocument["tgFreq"] = trackGenSetting.Frequency;
|
||||
jsonDocument["sg"] = sigGenOutputOn; //
|
||||
jsonDocument["sgPower"] = sigGenSetting.Power;
|
||||
jsonDocument["sgMod"] = sigGenSetting.ModulationType;
|
||||
jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
jsonDocument["sgFreq"] = sigGenSetting.Frequency;
|
||||
jsonDocument["sgCal"] = sigGenSetting.Calibration;
|
||||
jsonDocument["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
jsonDocument["tgCal"] = trackGenSetting.Calibration;
|
||||
jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
jsonDocument["PreAmp"] = 0x60; // Auto
|
||||
|
||||
else
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
|
||||
@ -714,13 +880,74 @@ static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
|
||||
// Serial.printf ( "Push Settings sweepPoints %u\n", sweepPoints );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Push the settings data to the websocket clients
|
||||
*/
|
||||
void pushSigGenSettings ()
|
||||
{
|
||||
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
||||
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
||||
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
||||
|
||||
jsonDocument["mType"] = "Settings";
|
||||
jsonDocument["mode"] = setting.Mode;
|
||||
jsonDocument["dispPoints"] = displayPoints;
|
||||
jsonDocument["start"] = startFreq_IF / 1000.0;
|
||||
jsonDocument["stop"] = stopFreq_IF / 1000.0;
|
||||
jsonDocument["IF"] = setting.IF_Freq / 1000000.0;
|
||||
jsonDocument["attenuation"] = setting.Attenuate;
|
||||
jsonDocument["extGain"] = setting.ExternalGain;
|
||||
jsonDocument["levelOffset"] = setting.LevelOffset;
|
||||
jsonDocument["setRBW"] = setting.Bandwidth10;
|
||||
jsonDocument["bandwidth"] = bandwidth;
|
||||
jsonDocument["RefOut"] = setting.ReferenceOut;
|
||||
jsonDocument["Drive"] = setting.Drive;
|
||||
jsonDocument["sweepPoints"] = sweepPoints;
|
||||
jsonDocument["spur"] = setting.Spur;
|
||||
jsonDocument["tg"] = trackGenSetting.Mode;
|
||||
jsonDocument["tgPower"] = trackGenSetting.Power;
|
||||
jsonDocument["tgMod"] = trackGenSetting.ModulationType;
|
||||
jsonDocument["tgModFreq"] = trackGenSetting.ModFrequency;
|
||||
jsonDocument["tgFreq"] = trackGenSetting.Frequency;
|
||||
jsonDocument["sg"] = sigGenOutputOn; //
|
||||
jsonDocument["sgPower"] = sigGenSetting.Power;
|
||||
jsonDocument["sgMod"] = sigGenSetting.ModulationType;
|
||||
jsonDocument["sgModFreq"] = sigGenSetting.ModFrequency;
|
||||
jsonDocument["sgFreq"] = sigGenSetting.Frequency;
|
||||
jsonDocument["sgCal"] = sigGenSetting.Calibration;
|
||||
jsonDocument["sgRange"] = (ATTENUATOR_RANGE + RX_SI4432_MAX_DRIVE * 3); // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
||||
jsonDocument["tgCal"] = trackGenSetting.Calibration;
|
||||
jsonDocument["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so full 20dBm output is possible.
|
||||
|
||||
if ( AGC_On )
|
||||
jsonDocument["PreAmp"] = 0x60; // Auto
|
||||
else
|
||||
jsonDocument["PreAmp"] = setting.PreampGain; // Fixed gain
|
||||
|
||||
String wsBuffer;
|
||||
|
||||
if ( wsBuffer )
|
||||
{
|
||||
serializeJson ( jsonDocument, wsBuffer );
|
||||
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
||||
}
|
||||
else
|
||||
Serial.println ( "No buffer :(");
|
||||
|
||||
// Serial.printf ( "Push Settings sweepPoints %u\n", sweepPoints );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prepare a response ready for push to web clients
|
||||
*/
|
||||
|
@ -33,21 +33,26 @@
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define SSID_NAME "TinySA" // Name of access point
|
||||
#define SSID_NAME "simpleSA" // Name of access point
|
||||
|
||||
|
||||
/*
|
||||
* Function prototypes:
|
||||
*/
|
||||
|
||||
extern boolean startAP ();
|
||||
extern boolean connectWiFi ();
|
||||
extern void buildServer ();
|
||||
extern void addTagNameValue ( char *b, char *_name, char *value );
|
||||
extern char *escapeXML ( char *s );
|
||||
extern void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t lenght );
|
||||
extern char *FormatIPAddress ( IPAddress ipAddress );
|
||||
|
||||
boolean startAP ();
|
||||
boolean connectWiFi ();
|
||||
void buildServer ();
|
||||
void addTagNameValue ( char *b, char *_name, char *value );
|
||||
char *escapeXML ( char *s );
|
||||
void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t lenght );
|
||||
char *FormatIPAddress ( IPAddress ipAddress );
|
||||
void pushSettings ();
|
||||
void pushIFSweepSettings ();
|
||||
void pushRXSweepSettings ();
|
||||
void pushBandscopeSettings ();
|
||||
void pushSigGenSettings ();
|
||||
void initChunkSweepDoc (uint32_t startIndex);
|
||||
|
||||
/*
|
||||
* Functions outside of "TinySA_wifi:
|
||||
|
60
ui.cpp
60
ui.cpp
@ -197,7 +197,7 @@ 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_IFSIG, KM_TGOFFSET, KM_TGFREQ, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART,
|
||||
KM_WFMIN, KM_WFGAIN, KM_BANDSCOPELEVEL, KM_RXSPAN, KM_RXSIG, KM_RBW,
|
||||
KM_EXTERN };
|
||||
|
||||
@ -216,7 +216,7 @@ 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",
|
||||
"IF Sig Freq", "TG OFFSET", "TG FREQ", "TG LO Drive", "TG IF Drive", "START",
|
||||
"WF MIN", "WF GAIN", "REF LEVEL", "RX SPAN", "RX Sig Freq", "RBW",
|
||||
"EXTERNAL"
|
||||
};
|
||||
@ -291,6 +291,7 @@ 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
|
||||
static void menu_tg_frequency_cb(int item); // M0WID - added in 3.0e
|
||||
static void menu_tgIF_drive_cb(int item); // M0WID - added in 3.0e
|
||||
static void menu_tgLO_drive_cb(int item); // M0WID - added in 3.0e
|
||||
|
||||
@ -489,11 +490,13 @@ static Menuitem menu_tracking[] = // Tracking generator mode
|
||||
{
|
||||
Menuitem ( MT_FUNC, "OFF", menu_tracking_cb ),
|
||||
Menuitem ( MT_FUNC, "ON", menu_tracking_cb ),
|
||||
Menuitem ( MT_FUNC, "OFFSET", menu_tg_offset_cb ),
|
||||
Menuitem ( MT_FUNC, "\2IF\0DRIVE", menu_tgIF_drive_cb ),
|
||||
#ifdef SI_TG_LO_CS
|
||||
Menuitem ( MT_FUNC, "GENERATE", menu_tracking_cb ),
|
||||
Menuitem ( MT_FUNC, "FREQUENCY",menu_tg_frequency_cb ),
|
||||
Menuitem ( MT_FUNC, "OFFSET", menu_tg_offset_cb ),
|
||||
Menuitem ( MT_FUNC, "\2LO\0DRIVE", menu_tgLO_drive_cb ),
|
||||
#endif
|
||||
Menuitem ( MT_FUNC, "\2IF\0DRIVE", menu_tgIF_drive_cb ),
|
||||
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
|
||||
Menuitem ( MT_END ) // End marker
|
||||
};
|
||||
@ -1168,7 +1171,7 @@ void ShowSplash ( void )
|
||||
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 0.01", 160, 100 );
|
||||
tft.drawString ( PROGRAM_VERSION, 160, 100 );
|
||||
tft.drawString ( "Original tinySA by Erik (PD0EK)", 160, 120 );
|
||||
|
||||
tft.setTextDatum ( TL_DATUM ); // Back to default top left
|
||||
@ -1387,6 +1390,17 @@ void menu_tg_offset_cb ( int item )
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
/*
|
||||
* "menu_tg_frequency_cb" - Handles setting the tracking generator frequency when in sig gen mode
|
||||
*/
|
||||
|
||||
void menu_tg_frequency_cb ( int item )
|
||||
{
|
||||
int km = KM_TGFREQ;
|
||||
tft.fillScreen ( bg );
|
||||
ui_mode_keypad ( km );
|
||||
ui_process_keypad ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -1449,6 +1463,11 @@ static void menu_tracking_cb (int item )
|
||||
ui_mode_normal (); // Back to sweep
|
||||
break;
|
||||
|
||||
case 2: // Turn Sig gen mode
|
||||
SetTracking (2);
|
||||
ui_mode_normal (); // Back to sweep
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -2132,6 +2151,7 @@ static const keypads_t * const keypads_mode_tbl[] =
|
||||
keypads_freq, // KM_IFSTOP.........IF Sweep stop frequency
|
||||
keypads_freq, // KM_IFSIG..........IF Sweep signal frequency
|
||||
keypads_signed_freq, // KM_TGOFFSET.......Offset Frequency of TG IF compared to SA IF
|
||||
keypads_freq, // KM_TGFREQ.........Frequency of TG in sig gen mode
|
||||
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
|
||||
@ -2521,6 +2541,10 @@ static void fetch_numeric_target ( void )
|
||||
uistat.value = trackGenSetting.Offset;
|
||||
break;
|
||||
|
||||
case KM_TGFREQ:
|
||||
uistat.value = trackGenSetting.Frequency;
|
||||
break;
|
||||
|
||||
case KM_TGIF_DRIVE:
|
||||
uistat.value = trackGenSetting.IF_Drive;
|
||||
break;
|
||||
@ -2944,6 +2968,23 @@ static int keypad_click ( int key )
|
||||
SetTGOffset ( (int32_t)value );
|
||||
break;
|
||||
|
||||
|
||||
case KM_TGFREQ:
|
||||
if ( (value > MAX_SIGLO_FREQ) || (value < MIN_SIGLO_FREQ) )
|
||||
{
|
||||
strcpy ( fBuff, FormatSignedFrequency (( int32_t ) value ));
|
||||
|
||||
DisplayError ( ERR_WARN,
|
||||
fBuff,
|
||||
"Invalid Frequency!",
|
||||
NULL,
|
||||
NULL );
|
||||
}
|
||||
else
|
||||
SetTGFreq ( (int32_t)value );
|
||||
break;
|
||||
|
||||
|
||||
case KM_TGIF_DRIVE:
|
||||
if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) )
|
||||
{
|
||||
@ -2957,6 +2998,8 @@ static int keypad_click ( int key )
|
||||
SetTGIfDrive ( (uint8_t)value );
|
||||
break;
|
||||
|
||||
|
||||
#ifdef SI_TG_LO_CS
|
||||
case KM_TGLO_DRIVE:
|
||||
if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) )
|
||||
{
|
||||
@ -2969,7 +3012,8 @@ static int keypad_click ( int key )
|
||||
else
|
||||
SetTGLoDrive ( (uint8_t)value );
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
case KM_BANDSCOPESTART: // Bandscope Start frequency entered?
|
||||
SetBandscopeStart (( int32_t ) value );
|
||||
@ -3227,21 +3271,25 @@ void UiProcessTouch ( void )
|
||||
if ( (touch_y < 10) && (touch_x < 160) )
|
||||
{
|
||||
marker[0].Toggle(); // marker 1
|
||||
setting.MkrStatus[0] = marker[0].Status();
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 10) && (touch_x > 160) )
|
||||
{
|
||||
marker[2].Toggle(); // marker 3
|
||||
setting.MkrStatus[2] = marker[2].Status();
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x < 160) )
|
||||
{
|
||||
marker[1].Toggle(); // marker 2
|
||||
setting.MkrStatus[1] = marker[1].Status();
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 20) && (touch_x > 160) )
|
||||
{
|
||||
marker[3].Toggle(); // marker 4
|
||||
setting.MkrStatus[3] = marker[3].Status();
|
||||
return;
|
||||
}
|
||||
else if ( (touch_y < 40) && (touch_x > 30) )
|
||||
|
Loading…
Reference in New Issue
Block a user