2020-08-16 02:03:43 +08:00
|
|
|
/*
|
2020-08-16 02:50:26 +08:00
|
|
|
* "simpleSA_wifi.cpp"
|
2020-08-16 02:03:43 +08:00
|
|
|
*
|
|
|
|
* Trial wifi charting functionality to see if WiFi affects the scan results
|
|
|
|
* Based on example here https://circuits4you.com/2019/01/11/esp8266-data-logging-with-real-time-graphs/
|
|
|
|
*
|
|
|
|
* Requires some files to be placed into the spiffs area of flash
|
|
|
|
*
|
|
|
|
* Modified in Version 2.1 by WA2FZW:
|
|
|
|
*
|
|
|
|
* Eliminated all calls to "WriteSettings". All of the functions in "Cmd.cpp"
|
|
|
|
* that actually update the "setting" structure elements now handle that task
|
|
|
|
* and do so based on whether or not the value of the parameter actually
|
|
|
|
* changed or not which wasn't the case before.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2020-08-16 02:50:26 +08:00
|
|
|
#include "simpleSA_wifi.h" // WiFi definitions
|
2020-08-17 05:24:08 +08:00
|
|
|
#include "si4432.h" // Si4432 definitions
|
|
|
|
#include "cmd.h" // Command processing functions
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Variables to determine size of grid and waterfall
|
|
|
|
* In Bandscope mode the grid is reduced. In future it may be possible to add
|
|
|
|
* a waterfall to the main sweep, but not yet
|
|
|
|
*/
|
|
|
|
extern uint16_t gridHeight;
|
|
|
|
extern uint16_t gridWidth;
|
|
|
|
extern uint16_t yGrid; // no of grid divisions
|
|
|
|
extern uint16_t yDelta; // no of points/division
|
|
|
|
extern uint16_t xGrid;
|
|
|
|
extern uint16_t displayPoints;
|
|
|
|
extern uint16_t xDelta;
|
|
|
|
extern uint16_t waterfallHeight;
|
|
|
|
|
2020-09-15 04:49:22 +08:00
|
|
|
extern unsigned long sweepMicros; // To report the scan time
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
|
2020-10-13 06:35:14 +08:00
|
|
|
extern uint16_t bpfCount; // Number of elements in the bandpassFilters array
|
2020-10-16 05:37:01 +08:00
|
|
|
extern double bpfCalibrations[MAX_SI4432_FILTERS]; // temporary storage for calibration values
|
|
|
|
extern uint16_t bpfIndex; // Index for current rbw filter
|
2020-10-13 06:35:14 +08:00
|
|
|
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 );
|
2020-08-16 02:03:43 +08:00
|
|
|
|
2020-10-13 06:35:14 +08:00
|
|
|
extern void setMode (uint16_t newMode);
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* In Version 1.8, the transmitter and receiver Si4432 modules are implemented as
|
|
|
|
* objects.
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern Si4432 rcvr; // Object for the receiver
|
|
|
|
extern Si4432 xmit; // And the transmitter
|
|
|
|
|
|
|
|
extern bool AGC_On; // Flag indicates if Preamp AGC is enabled
|
|
|
|
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;
|
2020-10-05 05:36:46 +08:00
|
|
|
extern uint16_t sigGenOutputOn;
|
2020-08-16 02:03:43 +08:00
|
|
|
|
2020-09-03 06:22:08 +08:00
|
|
|
extern uint32_t startFreq_RX;
|
|
|
|
extern uint32_t stopFreq_RX;
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
AsyncWebServer server ( 80 ); // Create the webserver object
|
|
|
|
AsyncResponseStream *response;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install WebSockets library by Markus Sattler
|
|
|
|
* https://github.com/Links2004/arduinoWebSockets
|
|
|
|
*/
|
|
|
|
|
|
|
|
WebSocketsServer webSocket = WebSocketsServer ( 81 );
|
|
|
|
|
|
|
|
uint8_t socketNumber;
|
|
|
|
unsigned long messageNumber;
|
|
|
|
|
|
|
|
extern uint8_t numberOfWebsocketClients;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tracking of number of Wi-Fi reconnects and total connection time
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned long numberOfReconnects;
|
|
|
|
unsigned long millisConnected;
|
|
|
|
|
|
|
|
IPAddress ipAddress; // Store the IP address for use elsewhere, eg info
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function to format IP address nicely
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *FormatIPAddress ( IPAddress ipAddress )
|
|
|
|
{
|
|
|
|
static char formatBuffer[20] = {0};
|
|
|
|
sprintf( formatBuffer, "%d.%d.%d.%d", ipAddress[0], ipAddress[1],
|
|
|
|
ipAddress[2], ipAddress[3] );
|
|
|
|
return formatBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boolean startAP () // Start the WiFi Access Point, keep the user informed.
|
|
|
|
{
|
|
|
|
ClearDisplay (); // Fade to black
|
|
|
|
|
2020-09-09 06:17:41 +08:00
|
|
|
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
Serial.println ( "Starting Access Point" ); // Put in the instructions
|
2020-09-09 06:17:41 +08:00
|
|
|
|
|
|
|
delay(2000);
|
|
|
|
|
|
|
|
// Scan WiFi SSIDs
|
|
|
|
WiFi.scanNetworks(true);
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start by kicking off the soft-AP. Call depends on whether or not password
|
|
|
|
* is required to connect
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef AP_PASSWORD
|
|
|
|
|
|
|
|
boolean result = WiFi.softAP ( PROGRAM_NAME, AP_PASSWORD );
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
boolean result = WiFi.softAP ( PROGRAM_NAME );
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( !result ) // This has failed, tell the user
|
|
|
|
DisplayError ( ERR_WARN, "Failed to open AP:", "WiFi Disabled", NULL, NULL );
|
|
|
|
|
|
|
|
else
|
2020-09-09 06:17:41 +08:00
|
|
|
ipAddress = WiFi.softAPIP();
|
2020-08-16 02:03:43 +08:00
|
|
|
|
2020-09-09 06:17:41 +08:00
|
|
|
Serial.printf ( "Access Point started, result = %i \n", result );
|
2020-08-16 02:03:43 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boolean connectWiFi() // Connect to Wifi using SSID (ie via Router)
|
|
|
|
{
|
|
|
|
|
|
|
|
Serial.printf ( "Connecting to: %s \n", WIFI_SSID );
|
|
|
|
// Serial.println( (char *) &configuration.WiFi_SSID[0] );
|
|
|
|
|
|
|
|
WiFi.softAPdisconnect (); // Disconnect anything that we may have
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the connection:
|
|
|
|
*/
|
|
|
|
|
|
|
|
// WiFi.begin ( (char *) &configuration.WiFi_SSID[0], (char *) &configuration.WiFi_Password[0] );
|
|
|
|
WiFi.begin ( WIFI_SSID, WIFI_PASSWORD );
|
|
|
|
|
|
|
|
WiFi.setSleep (false ); // Disable sleep
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2020-10-20 06:25:56 +08:00
|
|
|
* Apply hostname
|
2020-08-16 02:03:43 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
WiFi.setHostname ( PROGRAM_NAME );
|
|
|
|
|
|
|
|
int maxTry = 10; // Wait for the connection to be made.
|
|
|
|
|
|
|
|
tft.setCursor ( 0, 190 );
|
|
|
|
tft.printf ( "Connecting to WiFi %s", WIFI_SSID );
|
|
|
|
|
|
|
|
while (( WiFi.status() != WL_CONNECTED ) && ( maxTry > 0 ))
|
|
|
|
{
|
|
|
|
tft.print("."); // Nice touch!!!
|
|
|
|
delay ( 1000 ); // Wait and update the try count.
|
|
|
|
maxTry--;
|
|
|
|
|
|
|
|
if ( maxTry <= 0 )
|
|
|
|
{
|
|
|
|
DisplayError ( ERR_WARN, "Connecting to", WIFI_SSID, "failed!", "WiFi Disabled" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ipAddress = WiFi.localIP (); // We are connected, display the IP address
|
|
|
|
|
|
|
|
Serial.printf ( "Connected - IP %s \n", FormatIPAddress ( ipAddress ));
|
|
|
|
tft.printf ( "\n\nConnected - IP %s \n", FormatIPAddress ( ipAddress ));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle websocket events
|
|
|
|
* This is how dta is sent from the web page to the ESP32
|
|
|
|
*/
|
|
|
|
|
|
|
|
void webSocketEvent ( uint8_t num, WStype_t type, uint8_t* payload, size_t payloadLength )
|
|
|
|
{
|
|
|
|
switch ( type )
|
|
|
|
{
|
|
|
|
case WStype_DISCONNECTED:
|
|
|
|
Serial.printf("[%u] Disconnected!\n", num);
|
|
|
|
if ( numberOfWebsocketClients > 0 )
|
|
|
|
numberOfWebsocketClients--;
|
|
|
|
updateSidebar = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WStype_CONNECTED:
|
|
|
|
Serial.printf ( "[%u] Connected from ", num );
|
|
|
|
Serial.println ( webSocket.remoteIP ( num ));
|
|
|
|
numberOfWebsocketClients++;
|
|
|
|
updateSidebar = true;
|
|
|
|
webSocket.sendTXT ( num, "Connected" ); // send message back to client
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
2020-09-29 05:44:47 +08:00
|
|
|
* 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
|
2020-09-30 06:16:59 +08:00
|
|
|
* t trackGen Off/On/Generate
|
2020-09-29 05:44:47 +08:00
|
|
|
* T trackGen output level
|
2020-09-30 06:16:59 +08:00
|
|
|
* f trackgen signal generator frequency
|
2020-09-29 05:44:47 +08:00
|
|
|
* F Sig Gen frequency
|
|
|
|
* L Sig Gen level (dBm)
|
|
|
|
* G Sig Gen Off/On
|
|
|
|
* P Sig Gen set max output level (dBm)
|
2020-08-16 02:03:43 +08:00
|
|
|
*
|
|
|
|
* Other formats are ignored
|
|
|
|
*/
|
|
|
|
|
|
|
|
case WStype_TEXT:
|
|
|
|
if ( payload[0] == '#' )
|
|
|
|
{
|
|
|
|
if ( payloadLength > 3 )
|
|
|
|
{
|
|
|
|
char* field = strtok ( (char*) &payload[3], " " ); // Extract the field value as string
|
|
|
|
float value = atof ( field ); // Convert to float
|
|
|
|
|
|
|
|
if ( isnan ( value )) // If not a number
|
|
|
|
return; // Bail out!
|
|
|
|
|
|
|
|
Serial.printf ( "payload command %c value %f\n", payload[1], value );
|
|
|
|
|
|
|
|
switch ( payload[1] )
|
|
|
|
{
|
|
|
|
case 'a':
|
2020-09-09 06:17:41 +08:00
|
|
|
switch (setting.Mode) {
|
|
|
|
case SA_LOW_RANGE:
|
|
|
|
SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency
|
|
|
|
break;
|
2020-09-29 05:44:47 +08:00
|
|
|
case SIG_GEN_LOW_RANGE:
|
|
|
|
SetSweepStart ( value * 1000000.0 ); // Set Low range sweep start frequency
|
|
|
|
break;
|
2020-09-09 06:17:41 +08:00
|
|
|
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;
|
|
|
|
}
|
2020-08-16 02:03:43 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'b':
|
2020-09-09 06:17:41 +08:00
|
|
|
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;
|
|
|
|
}
|
2020-08-16 02:03:43 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
SetSweepCenter ( value * 1000000.0, WIDE ); // Set sweep center frequency
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
SetLoDrive ( (uint8_t) value );
|
|
|
|
break;
|
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
case 'f':
|
|
|
|
SetTGFreq ( value );
|
|
|
|
break;
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
case 'g':
|
|
|
|
SetPreampGain( (int) value ); // Set PreAmp gain register
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'i': // IF Frequency
|
|
|
|
SetIFFrequency ( (int32_t) ( value * 1000000.0 ));
|
|
|
|
break;
|
|
|
|
|
2020-09-08 06:31:06 +08:00
|
|
|
case 'm': // Set mode
|
|
|
|
setMode ( (int16_t) ( value ));
|
|
|
|
break;
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
case 'o': // Ref Output (LO GPIO2)
|
|
|
|
SetRefOutput ( (int) value );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'p': // Adjust actual power level
|
|
|
|
RequestSetPowerLevel( value );
|
|
|
|
break;
|
|
|
|
|
2020-09-08 06:31:06 +08:00
|
|
|
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;
|
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
case (SIG_GEN_LOW_RANGE):
|
|
|
|
pushSigGenSettings();
|
|
|
|
break;
|
|
|
|
|
2020-09-08 06:31:06 +08:00
|
|
|
default:
|
|
|
|
Serial.println("Invalid mode in Request setting handler - simpleSA_wifi.cpp");
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
case 's': // Adjust sweep span
|
|
|
|
SetSweepSpan ( (int32_t) ( value * 1000000.0 ));
|
|
|
|
break;
|
2020-10-10 04:14:58 +08:00
|
|
|
#ifdef TG_IF_INSTALLED
|
2020-10-05 05:36:46 +08:00
|
|
|
case 't': // Tracking Generator off/on/generate
|
|
|
|
SetTracking ( (int8_t)value );
|
|
|
|
break;
|
2020-10-10 04:14:58 +08:00
|
|
|
#endif
|
2020-10-05 05:36:46 +08:00
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
case 'A': // Internal Attenuation (PE4302)
|
|
|
|
SetAttenuation ( value );
|
|
|
|
break;
|
|
|
|
|
2020-09-03 06:22:08 +08:00
|
|
|
case 'E': // External Gain (+ve) or Attenuation (-ve)
|
|
|
|
SetExtGain ( value );
|
|
|
|
break;
|
|
|
|
|
2020-10-04 06:17:19 +08:00
|
|
|
case 'F':
|
2020-10-05 05:36:46 +08:00
|
|
|
SetSGFreq ( value ); // Signal Generator Frequency
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'G':
|
|
|
|
SetSGState ( (uint16_t)value ); // Signal Generator output on/off
|
2020-10-04 06:17:19 +08:00
|
|
|
break;
|
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
case 'L': // Signal Generator output power (dBm)
|
2020-10-04 06:17:19 +08:00
|
|
|
SetSGPower ( value );
|
|
|
|
break;
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
case 'R': // Requested RBW. 0=Auto
|
|
|
|
SetRBW ( value );
|
2020-09-03 06:22:08 +08:00
|
|
|
Serial.printf("Wifi RBW %f\n", value);
|
2020-08-16 02:03:43 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'S': // Spur Reduction on/off
|
2020-09-03 06:22:08 +08:00
|
|
|
SetSpur ( (int8_t)value );
|
|
|
|
break;
|
|
|
|
|
2020-10-10 04:14:58 +08:00
|
|
|
#ifdef TG_IF_INSTALLED
|
2020-09-03 06:22:08 +08:00
|
|
|
case 'T': // Tracking Generator output power (dBm)
|
|
|
|
SetTGPower ( value );
|
2020-08-16 02:03:43 +08:00
|
|
|
break;
|
2020-10-10 04:14:58 +08:00
|
|
|
#endif
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
Serial.printf ( "payload[1] was %c\n", payload[1] );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else // payload[0] is not '#'
|
|
|
|
{
|
|
|
|
webSocket.sendTXT ( num, "pong" ); // send message back to client to keep connection alive
|
|
|
|
Serial.printf ( "[%u] get Text: %s\n", num, payload );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Serial.println ( "Case?" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Monitor Wi-Fi connection if it is alive. If not alive then wait until it reconnects.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void isWiFiAlive ( void )
|
|
|
|
{
|
|
|
|
if ( WiFi.status() != WL_CONNECTED )
|
|
|
|
{
|
|
|
|
Serial.print ( "not connected" );
|
|
|
|
|
|
|
|
while ( WiFi.status() != WL_CONNECTED )
|
|
|
|
{
|
|
|
|
Serial.print ( "." );
|
|
|
|
delay(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
numberOfReconnects++;
|
|
|
|
millisConnected = millis();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some routines for XML
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *escapeXML ( char *s ) // Use special codes for some characters
|
|
|
|
{
|
|
|
|
static char b[1024];
|
|
|
|
|
|
|
|
b[0] = '\0'; // Null terminator
|
|
|
|
|
|
|
|
for ( int i = 0; i < strlen(s); i++ )
|
|
|
|
{
|
|
|
|
switch ( s[i] )
|
|
|
|
{
|
|
|
|
case '\"':
|
|
|
|
strcat ( b,""" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '&':
|
|
|
|
strcat (b, "&" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '<':
|
|
|
|
strcat ( b,"<" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
strcat ( b,">" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
int l = strlen ( b );
|
|
|
|
b[l] = s[i];
|
|
|
|
b[l + 1] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an XML tag with its value to the buffer b
|
|
|
|
*/
|
|
|
|
|
|
|
|
void addTagNameValue ( char *b, char *_name, char *value )
|
|
|
|
{
|
|
|
|
strcat ( b,_name );
|
|
|
|
strcat ( b, "=\"" );
|
|
|
|
strcat ( b,value );
|
|
|
|
strcat ( b,"\" " );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2020-10-20 06:25:56 +08:00
|
|
|
* Handle settings that are common to all modes
|
2020-08-16 02:03:43 +08:00
|
|
|
*/
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
void addCommonSettings ( JsonDocument& jDoc )
|
|
|
|
{
|
|
|
|
jDoc["mType"] = "Settings";
|
|
|
|
jDoc["mode"] = setting.Mode;
|
|
|
|
jDoc["IF"] = setting.IF_Freq / 1000000.0;
|
|
|
|
jDoc["attenuation"] = setting.Attenuate;
|
|
|
|
jDoc["extGain"] = setting.ExternalGain;
|
|
|
|
jDoc["filterCal"] = bpfCalibrations[bpfIndex];
|
|
|
|
jDoc["setRBW"] = setting.Bandwidth10;
|
|
|
|
jDoc["bandwidth"] = bandwidth;
|
|
|
|
jDoc["RefOut"] = setting.ReferenceOut;
|
|
|
|
jDoc["Drive"] = setting.Drive;
|
|
|
|
jDoc["sweepPoints"] = sweepPoints;
|
|
|
|
jDoc["spur"] = setting.Spur;
|
|
|
|
jDoc["tg"] = trackGenSetting.Mode;
|
|
|
|
jDoc["tgPower"] = trackGenSetting.Power;
|
|
|
|
jDoc["tgFreq"] = trackGenSetting.Frequency;
|
|
|
|
jDoc["tgMod"] = trackGenSetting.ModulationType;
|
|
|
|
jDoc["tgModFreq"] = trackGenSetting.ModFrequency;
|
|
|
|
jDoc["sg"] = sigGenOutputOn; //
|
|
|
|
jDoc["sgPower"] = sigGenSetting.Power;
|
|
|
|
jDoc["sgMod"] = sigGenSetting.ModulationType;
|
|
|
|
jDoc["sgModFreq"] = sigGenSetting.ModFrequency;
|
|
|
|
jDoc["sgFreq"] = sigGenSetting.Frequency;
|
|
|
|
jDoc["sgCal"] = sigGenSetting.Calibration;
|
|
|
|
jDoc["sgRange"] = ATTENUATOR_RANGE + 11; // SI4432 output can be adjusted over 21dBm but max to SAW filter is 10dBm
|
|
|
|
jDoc["tgCal"] = trackGenSetting.Calibration;
|
|
|
|
jDoc["tgRange"] = ATTENUATOR_RANGE + 21; // no SAW filter so 20dBm output is possible.
|
|
|
|
|
|
|
|
if ( AGC_On )
|
|
|
|
jDoc["PreAmp"] = 0x60; // Auto
|
|
|
|
else
|
|
|
|
jDoc["PreAmp"] = setting.PreampGain; // Fixed gain
|
|
|
|
}
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Push the settings data to the websocket clients
|
2020-10-20 06:25:56 +08:00
|
|
|
* Slightly different for each mode
|
|
|
|
*
|
|
|
|
* Could economise by splitting so common fields are in one function
|
2020-08-16 02:03:43 +08:00
|
|
|
*/
|
|
|
|
void pushSettings ()
|
|
|
|
{
|
2020-09-03 06:22:08 +08:00
|
|
|
|
|
|
|
if ( numberOfWebsocketClients == 0 )
|
|
|
|
return;
|
|
|
|
|
2020-08-17 05:24:08 +08:00
|
|
|
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
2020-09-08 06:31:06 +08:00
|
|
|
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
2020-08-16 02:03:43 +08:00
|
|
|
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
addCommonSettings(jsonDocument);
|
|
|
|
|
2020-08-17 05:24:08 +08:00
|
|
|
jsonDocument["dispPoints"] = displayPoints;
|
2020-08-16 02:03:43 +08:00
|
|
|
jsonDocument["start"] = setting.ScanStart / 1000.0;
|
|
|
|
jsonDocument["stop"] = setting.ScanStop / 1000.0;
|
|
|
|
jsonDocument["levelOffset"] = setting.LevelOffset;
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
/*
|
|
|
|
* Push the settings data to the websocket clients
|
|
|
|
*/
|
|
|
|
void pushIFSweepSettings ()
|
|
|
|
{
|
2020-08-17 05:24:08 +08:00
|
|
|
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
2020-09-08 06:31:06 +08:00
|
|
|
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
2020-08-16 02:03:43 +08:00
|
|
|
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
addCommonSettings(jsonDocument);
|
|
|
|
|
2020-08-17 05:24:08 +08:00
|
|
|
jsonDocument["dispPoints"] = displayPoints;
|
2020-08-16 02:03:43 +08:00
|
|
|
jsonDocument["start"] = startFreq_IF / 1000.0;
|
|
|
|
jsonDocument["stop"] = stopFreq_IF / 1000.0;
|
|
|
|
jsonDocument["levelOffset"] = setting.LevelOffset;
|
|
|
|
|
|
|
|
String wsBuffer;
|
|
|
|
|
|
|
|
if ( wsBuffer )
|
|
|
|
{
|
|
|
|
serializeJson ( jsonDocument, wsBuffer );
|
|
|
|
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Serial.println ( "No buffer :(");
|
|
|
|
}
|
|
|
|
|
2020-09-03 06:22:08 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Push the settings data to the websocket clients
|
|
|
|
*/
|
|
|
|
void pushRXSweepSettings ()
|
|
|
|
{
|
|
|
|
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
2020-09-08 06:31:06 +08:00
|
|
|
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
2020-09-03 06:22:08 +08:00
|
|
|
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
addCommonSettings(jsonDocument);
|
|
|
|
|
2020-09-03 06:22:08 +08:00
|
|
|
jsonDocument["dispPoints"] = displayPoints;
|
|
|
|
jsonDocument["start"] = startFreq_RX / 1000.0;
|
|
|
|
jsonDocument["stop"] = stopFreq_RX / 1000.0;
|
2020-10-09 06:08:59 +08:00
|
|
|
jsonDocument["levelOffset"] = 0;
|
2020-09-03 06:22:08 +08:00
|
|
|
|
|
|
|
String wsBuffer;
|
|
|
|
|
|
|
|
if ( wsBuffer )
|
|
|
|
{
|
|
|
|
serializeJson ( jsonDocument, wsBuffer );
|
|
|
|
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Serial.println ( "No buffer :(");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
/*
|
|
|
|
* Push the settings data to the websocket clients
|
|
|
|
*/
|
|
|
|
void pushBandscopeSettings ()
|
|
|
|
{
|
2020-08-17 05:24:08 +08:00
|
|
|
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
|
2020-09-08 06:31:06 +08:00
|
|
|
+ SCREEN_WIDTH*JSON_OBJECT_SIZE ( 2 ) + JSON_OBJECT_SIZE ( 17 );
|
2020-08-16 02:03:43 +08:00
|
|
|
static DynamicJsonDocument jsonDocument ( capacity ); // buffer for json data to be pushed to the web clients
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
addCommonSettings(jsonDocument);
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
jsonDocument["dispPoints"] = setting.BandscopePoints;
|
|
|
|
jsonDocument["start"] = setting.BandscopeStart / 1000.0;
|
|
|
|
jsonDocument["stop"] = ( setting.BandscopeStart + setting.BandscopeSpan ) / 1000.0;
|
|
|
|
jsonDocument["levelOffset"] = setting.LevelOffset;
|
|
|
|
|
|
|
|
String wsBuffer;
|
|
|
|
|
|
|
|
if ( wsBuffer )
|
|
|
|
{
|
|
|
|
serializeJson ( jsonDocument, wsBuffer );
|
|
|
|
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
|
|
|
}
|
2020-10-05 05:36:46 +08:00
|
|
|
else
|
|
|
|
Serial.println ( "No buffer :(");
|
|
|
|
}
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2020-10-20 06:25:56 +08:00
|
|
|
addCommonSettings(jsonDocument);
|
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
jsonDocument["dispPoints"] = displayPoints;
|
|
|
|
jsonDocument["start"] = startFreq_IF / 1000.0;
|
|
|
|
jsonDocument["stop"] = stopFreq_IF / 1000.0;
|
|
|
|
jsonDocument["levelOffset"] = setting.LevelOffset;
|
|
|
|
|
|
|
|
String wsBuffer;
|
|
|
|
|
|
|
|
if ( wsBuffer )
|
|
|
|
{
|
|
|
|
serializeJson ( jsonDocument, wsBuffer );
|
|
|
|
webSocket.broadcastTXT ( wsBuffer ); // Send to all connected websocket clients
|
|
|
|
}
|
2020-08-16 02:03:43 +08:00
|
|
|
else
|
|
|
|
Serial.println ( "No buffer :(");
|
|
|
|
}
|
|
|
|
|
2020-10-05 05:36:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-16 02:03:43 +08:00
|
|
|
/*
|
|
|
|
* Prepare a response ready for push to web clients
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On request from web page return the list of valid RBW settings from the
|
|
|
|
* "bandpassFilters" array (found in the ".ino" file).
|
|
|
|
*/
|
|
|
|
|
|
|
|
void onGetRbwList ( AsyncWebServerRequest *request )
|
|
|
|
{
|
|
|
|
response = request->beginResponseStream ( "application/json" );
|
|
|
|
// Serial.println ( "onGetRbwList" );
|
|
|
|
|
|
|
|
response->print ( "[" ); // Start of object
|
|
|
|
|
|
|
|
int filterCount = rcvr.GetBandpassFilterCount ();
|
|
|
|
|
|
|
|
for ( int i = 0; i < filterCount-1 ; i++ ) // For each element in the bandpassfilters array
|
|
|
|
response->printf ( "{\"bw10\":%i,\"bw\":%5.1f},",
|
|
|
|
rcvr.GetBandpassFilter10(i),
|
|
|
|
(float) rcvr.GetBandpassFilter10(i) / 10.0 );
|
|
|
|
|
|
|
|
response->printf ( "{\"bw10\":%i,\"bw\":%5.1f}", rcvr.GetBandpassFilter10(filterCount-1),
|
|
|
|
(float) rcvr.GetBandpassFilter10(filterCount-1) / 10.0 );
|
|
|
|
|
|
|
|
response->println ( "]" ); // End of object
|
|
|
|
request->send ( response );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On request from web page return the list of valid attenuations
|
|
|
|
* In the case of the PE4302 this is 0-31.5 in 0.5db steps,
|
|
|
|
* but we will reduce this to 3dB steps
|
|
|
|
* Insertion loss is about 1.5dB
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void onGetAttenList ( AsyncWebServerRequest *request )
|
|
|
|
{
|
|
|
|
response = request->beginResponseStream ( "application/json" );
|
|
|
|
// Serial.println ( "onGetAttList" );
|
|
|
|
|
|
|
|
response->print ( "[" ); // Start of object
|
|
|
|
|
|
|
|
for ( int i = 0; i < 30 ; i = i + 3 ) // For each possible attenuation
|
|
|
|
response->printf ( "{\"dB\":%i},", i );
|
|
|
|
|
|
|
|
response->printf ( "{\"dB\":%i}", 30 );
|
|
|
|
response->println ( "]" ); // End of object
|
|
|
|
request->send ( response );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Functions to execute when the user presses buttons on the webpage
|
|
|
|
*/
|
|
|
|
|
|
|
|
void onDoReboot ( AsyncWebServerRequest *request )
|
|
|
|
{
|
|
|
|
request->redirect ( "index.html" ); // Redirect to the index page
|
|
|
|
ESP.restart ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void onGetNameVersion ( AsyncWebServerRequest *request )
|
|
|
|
{
|
|
|
|
AsyncResponseStream *response = request->beginResponseStream ( "text/xml" );
|
|
|
|
|
|
|
|
response->printf ( "<?xml version=\"1.0\" encoding=\"utf-16\"?>" );
|
|
|
|
response->printf ( "<IndexNameVersion " );
|
|
|
|
|
|
|
|
response->printf ( "Name=\"%s\" ",PROGRAM_NAME );
|
2020-10-20 06:25:56 +08:00
|
|
|
response->printf ( "Version=\"%s\" ",PROGRAM_VERSION );
|
|
|
|
response->printf ( "Copyright=\"M0WID\"" );
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
response->printf ( "/>" );
|
|
|
|
|
|
|
|
request->send(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void onGetSIDDs ( AsyncWebServerRequest *request )
|
|
|
|
{
|
|
|
|
char b[1024];
|
|
|
|
b[0] = '\0';
|
|
|
|
|
|
|
|
Serial.println ( "" );
|
|
|
|
Serial.println ( "Scanning for SSIDs" );
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to return a blob of XML containing the visible SSIDs
|
|
|
|
*/
|
|
|
|
strcpy ( b, "<SSIDs>" ); // Start of XML
|
|
|
|
|
|
|
|
int n = WiFi.scanComplete ();
|
|
|
|
|
|
|
|
if ( n == -2 )
|
|
|
|
WiFi.scanNetworks ( true );
|
|
|
|
else if ( n )
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < n; ++i )
|
|
|
|
{
|
|
|
|
strcat ( b,"<SSID Name = \"" ); // Add the SSID to the result
|
|
|
|
strcat ( b, WiFi.SSID (i).c_str() );
|
|
|
|
strcat ( b,"\" />" );
|
|
|
|
Serial.println ( "... " + WiFi.SSID (i) );
|
|
|
|
}
|
|
|
|
WiFi.scanDelete ();
|
|
|
|
if ( WiFi.scanComplete() == -2 )
|
|
|
|
WiFi.scanNetworks ( true );
|
|
|
|
}
|
|
|
|
strcat ( b, "</SSIDs>" ); // Complete the XML
|
|
|
|
request->send ( 200, "text/xml", b ); // Send it to the server
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the web server
|
|
|
|
* the order here is important - put frequent ones at top of list to improve performance
|
|
|
|
*/
|
|
|
|
void buildServer () // We can now configure and start the server
|
|
|
|
{
|
|
|
|
Serial.println ( "Building Server.." );
|
|
|
|
server.reset (); // Clear any existing settings and events
|
|
|
|
server.on ( "/getRbwList", HTTP_GET, onGetRbwList ); // Set event to return RBW options as JSON array
|
|
|
|
server.on ( "/getAttenList", HTTP_GET, onGetAttenList ); // Set event to return attenuator options as JSON array
|
|
|
|
server.on ( "/getSSIDs", HTTP_GET, onGetSIDDs ); // Set event to return list of SSID as XML
|
2020-10-20 06:25:56 +08:00
|
|
|
server.on ( "/getNameVersion", HTTP_GET, onGetNameVersion );// Set event to return name and version
|
|
|
|
server.on ( "/doReboot", HTTP_GET, onDoReboot ); // Set event to reboot the ESP32
|
2020-08-16 02:03:43 +08:00
|
|
|
|
|
|
|
server.serveStatic ( "/", SPIFFS, "/" ).setDefaultFile ( "index.html" );
|
|
|
|
|
|
|
|
server.begin ();
|
|
|
|
}
|