simpleSA/simpleSA_wifi.cpp

1062 lines
30 KiB
C++
Raw Normal View History

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
#include "si4432.h" // Si4432 definitions
#include "cmd.h" // Command processing functions
/*
* Variables to determine size of grid and waterfall
* In Bandscope mode the grid is reduced. In future it may be possible to add
* a waterfall to the main sweep, but not yet
*/
extern uint16_t gridHeight;
extern uint16_t gridWidth;
extern uint16_t yGrid; // no of grid divisions
extern uint16_t yDelta; // no of points/division
extern uint16_t xGrid;
extern uint16_t displayPoints;
extern uint16_t xDelta;
extern uint16_t waterfallHeight;
extern unsigned long sweepMicros; // To report the scan time
2020-08-16 02:03:43 +08:00
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);
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;
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-08-16 02:03:43 +08:00
Serial.println ( "Starting Access Point" ); // Put in the instructions
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
ipAddress = WiFi.softAPIP();
2020-08-16 02:03:43 +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
/*
* Apply any hostname that we may have
*/
// if ( strlen ( (char *) &configuration.Hostname[0]) > 0 )
// WiFi.setHostname ( (char *) &configuration.Hostname[0] );
// else
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;
/*
*
* 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
* T trackGen output level
2020-09-30 06:16:59 +08:00
* 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)
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':
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;
}
2020-08-16 02:03:43 +08:00
break;
case 'b':
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;
case 'g':
SetPreampGain( (int) value ); // Set PreAmp gain register
break;
case 'i': // IF Frequency
SetIFFrequency ( (int32_t) ( value * 1000000.0 ));
break;
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;
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;
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;
case 'A': // Internal Attenuation (PE4302)
SetAttenuation ( value );
break;
case 'E': // External Gain (+ve) or Attenuation (-ve)
SetExtGain ( value );
break;
case 'F':
SetSGFreq ( value );
break;
case 'L': // Tracking Generator output power (dBm)
SetSGPower ( value );
break;
2020-08-16 02:03:43 +08:00
case 'R': // Requested RBW. 0=Auto
SetRBW ( value );
Serial.printf("Wifi RBW %f\n", value);
2020-08-16 02:03:43 +08:00
break;
case 'S': // Spur Reduction on/off
SetSpur ( (int8_t)value );
break;
2020-09-30 06:16:59 +08:00
case 't': // Tracking Generator off/on/generate
SetTracking ( (int8_t)value );
break;
case 'T': // Tracking Generator output power (dBm)
SetTGPower ( value );
2020-08-16 02:03:43 +08:00
break;
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,"&quot;" );
break;
case '&':
strcat (b, "&amp;" );
break;
case '<':
strcat ( b,"&lt;" );
break;
case '>':
strcat ( b,"&gt;" );
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,"\" " );
}
/*
* On request from web page convert the data from a scan into XML and send
*
* Ideally we would push the data to the web page at the end of a scan,
* or perhaps just create the xml at the end of each scan - investigate later
*/
void onGetScan ( AsyncWebServerRequest *request )
{
response = request->beginResponseStream ( "text/xml" );
// Serial.println ( "onGetScan" );
response->print ( "<?xml version=\"1.0\" encoding=\"utf-16\"?>" );
response->println ( "<Points>" );
for( int i = 0; i < displayPoints-1; i++ ) // For each data point
2020-08-16 02:03:43 +08:00
{
// Serial.printf ( "<Point F=\"%i\" RSSI=\"%i\"/> %i\n",myFreq[i], myData[i], i );
response->printf ( "<P F=\"%i\" R=\"%i\"/>\n", myFreq[i], myData[i] );
}
response->print ( "</Points>" );
request->send ( response );
}
/*
* On request from web page convert the gain data from a sweep into JSON and send
* Ideally we would push the data to the web page at the end of a scan,
*/
void onGetGainSweep ( AsyncWebServerRequest *request )
{
size_t bufferSize = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
+ JSON_OBJECT_SIZE ( 1 ) + SCREEN_WIDTH * JSON_OBJECT_SIZE ( 2 );
2020-08-16 02:03:43 +08:00
AsyncJsonResponse * response = new AsyncJsonResponse ( false, bufferSize );
// response->addHeader ( "Server","ESP Async Web Server" );
JsonObject root = response->getRoot();
JsonArray gainPoints = root.createNestedArray ( "gainPoints" ); // Add gainPoints array
/*
* Add the objects to the array
*/
for ( int i = 0; i < displayPoints; i++ ) // For each data point
2020-08-16 02:03:43 +08:00
{
JsonObject dataPoint = gainPoints.createNestedObject(); // Add an object to the array
dataPoint["x"] = myFreq[i]/1000000.0; // set the x(frequency) value
dataPoint["y"] = myGain[i]; // set the y (gain) value
}
response->setLength();
request->send ( response );
}
/*
* On request from web page convert the data from a sweep into JSON and send.
* Ideally we would push the data to the web page at the end of a scan.
*/
void onGetSweep ( AsyncWebServerRequest *request )
{
size_t bufferSize = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
+ JSON_OBJECT_SIZE ( 14 ) + SCREEN_WIDTH * JSON_OBJECT_SIZE ( 2 );
2020-08-16 02:03:43 +08:00
AsyncJsonResponse * response = new AsyncJsonResponse ( false, bufferSize );
JsonObject root = response->getRoot();
root["dispPoints"] = displayPoints;
2020-08-16 02:03:43 +08:00
root["start"] = setting.ScanStart / 1000.0;
root["stop"] = setting.ScanStop / 1000.0;
root["IF"] = setting.IF_Freq / 1000000.0;
root["attenuation"] = setting.Attenuate;
root["extGain"] = setting.ExternalGain;
2020-08-16 02:03:43 +08:00
root["levelOffset"] = setting.LevelOffset;
root["setRBW"] = setting.Bandwidth10;
root["bandwidth"] = bandwidth;
root["RefOut"] = setting.ReferenceOut;
root["Drive"] = setting.Drive;
root["sweepPoints"] = sweepPoints;
if ( AGC_On )
root["PreAmp"] = 0x60; // Auto
else
root["PreAmp"] = setting.PreampGain; // Fixed gain
JsonArray Points = root.createNestedArray ( "Points" ); // Add Points array
for ( int i = 0; i < displayPoints; i++ ) //For each data point
2020-08-16 02:03:43 +08:00
{
JsonObject dataPoint = Points.createNestedObject(); // add an object to the array
dataPoint["x"] = myFreq[i]/1000000.0; // set the x(frequency) value
dataPoint["y"] = myData[i]; // set the y (RSSI) value
}
response->setLength();
request->send ( response );
}
/*
* On request from web page send the settings as JSON
*/
void onGetSettings (AsyncWebServerRequest *request)
{
AsyncJsonResponse * response = new AsyncJsonResponse(false) ;
JsonObject root = response->getRoot();
root["mType"] = "Settings";
root["mode"] = setting.Mode;
root["dispPoints"] = displayPoints;
2020-08-16 02:03:43 +08:00
root["start"] = setting.ScanStart / 1000.0;
root["stop"] = setting.ScanStop / 1000.0;
root["IF"] = setting.IF_Freq / 1000000.0;
root["attenuation"] = setting.Attenuate;
root["extGain"] = setting.ExternalGain;
2020-08-16 02:03:43 +08:00
root["levelOffset"] = setting.LevelOffset;
root["setRBW"] = setting.Bandwidth10;
root["bandwidth"] = bandwidth;
root["RefOut"] = setting.ReferenceOut;
root["Drive"] = setting.Drive;
root["sweepPoints"] = sweepPoints;
root["spur"] = setting.Spur;
root["tg"] = trackGenSetting.Mode;
root["tgPower"] = trackGenSetting.Power;
2020-08-16 02:03:43 +08:00
if ( AGC_On )
root["PreAmp"] = 0x60; // Auto
else
root["PreAmp"] = setting.PreampGain; // Fixed gain
response->setLength();
request->send ( response );
// Serial.printf ( "Get Settings sweepPoints %u\n", sweepPoints );
}
/*
* Push the settings data to the websocket clients
*/
void pushSettings ()
{
if ( numberOfWebsocketClients == 0 )
return;
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
+ 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
jsonDocument["mType"] = "Settings";
jsonDocument["mode"] = setting.Mode;
jsonDocument["dispPoints"] = displayPoints;
2020-08-16 02:03:43 +08:00
jsonDocument["start"] = setting.ScanStart / 1000.0;
jsonDocument["stop"] = setting.ScanStop / 1000.0;
jsonDocument["IF"] = setting.IF_Freq / 1000000.0;
jsonDocument["attenuation"] = setting.Attenuate;
jsonDocument["extGain"] = setting.ExternalGain;
2020-08-16 02:03:43 +08:00
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;
2020-08-16 02:03:43 +08:00
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 );
}
/*
* Push the settings data to the websocket clients
*/
void pushIFSweepSettings ()
{
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
+ 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
jsonDocument["mType"] = "Settings";
jsonDocument["mode"] = setting.Mode;
jsonDocument["dispPoints"] = displayPoints;
2020-08-16 02:03:43 +08:00
jsonDocument["start"] = startFreq_IF / 1000.0;
jsonDocument["stop"] = stopFreq_IF / 1000.0;
jsonDocument["IF"] = setting.IF_Freq / 1000000.0;
2020-08-16 02:03:43 +08:00
jsonDocument["attenuation"] = setting.Attenuate;
jsonDocument["extGain"] = setting.ExternalGain;
2020-08-16 02:03:43 +08:00
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;
2020-08-16 02:03:43 +08:00
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 );
}
/*
* Push the settings data to the websocket clients
*/
void pushRXSweepSettings ()
{
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_RX / 1000.0;
jsonDocument["stop"] = stopFreq_RX / 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;
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 );
}
2020-08-16 02:03:43 +08:00
/*
* Push the settings data to the websocket clients
*/
void pushBandscopeSettings ()
{
size_t capacity = JSON_ARRAY_SIZE ( SCREEN_WIDTH )
+ 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
jsonDocument["mType"] = "Settings";
jsonDocument["mode"] = setting.Mode;
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["IF"] = setting.IF_Freq / 1000000.0;
jsonDocument["attenuation"] = setting.Attenuate;
jsonDocument["extGain"] = setting.ExternalGain;
2020-08-16 02:03:43 +08:00
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;
2020-08-16 02:03:43 +08:00
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
*/
/*
* 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 ();
}
/*
* Function sets the sweep parameters based on the data in the form posted by the web page
* No longer used
*/
// doSetSweep ? setStart = 10 & setStop = 20 & setExtGain = 0 & setRBW = 26
void onSetSweep ( AsyncWebServerRequest *request )
{
Serial.print ( request->url ()); // Get the paramaters passed from the
Serial.print ( ":-" ); // web page, checking they exist
if ( request->hasParam ( "setStart" ))
{
Serial.print ( "setStart;" );
AsyncWebParameter* startInput = request->getParam ( "setStart" );
SetSweepStart ( atof ( startInput->value().c_str()) * 1000000.0 );
}
if ( request->hasParam ( "setStop" ))
{
Serial.print ( "setStop;" );
AsyncWebParameter* stopInput = request->getParam ( "setStop" );
SetSweepStop( atof ( stopInput->value().c_str()) * 1000000.0 );
}
if ( request->hasParam ( "setExtGain" ))
{
Serial.print ( "setExtGain;" );
AsyncWebParameter* extGainInput = request->getParam ( "setExtGain" );
// Need to add function later
}
if ( request->hasParam ( "refOut" ))
{
Serial.print ( "refOut;" );
AsyncWebParameter* setRefOut = request->getParam ( "setRefOut" );
setting.ReferenceOut = atoi ( setRefOut->value().c_str() );
xmit.SetPowerReference ( setting.ReferenceOut );
}
if ( request->hasParam ( "setAtten" ))
{
Serial.print ( "setAtten:" );
AsyncWebParameter* setAtten = request->getParam ( "setAtten");
SetAttenuation ( atoi ( setAtten->value().c_str() ));
Serial.print ( atoi ( setAtten->value().c_str() ));
Serial.print ( "; " );
}
if ( request->hasParam ( "setRBW" ))
{
Serial.print ( "setRBW ");
AsyncWebParameter* rbwInput = request->getParam ( "setRBW" );
SetRBW ( atoi ( rbwInput->value().c_str() ));
Serial.printf ( "setting.bandwidth = %i, input = %i;", setting.Bandwidth10, atoi ( rbwInput->value().c_str() ));
}
Serial.println ();
request->redirect ( "index.html" ); // redirect to the index page
}
/*
* Function sets the sweep parameters based on the data in the form posted by the web page
* No longer used
*/
// doSetSweep ? setStart = 10 &setStop = 20 & setExtGain = 0 & setRBW = 26
void onSettings ( AsyncWebServerRequest *request )
{
Serial.print ( request->url() ); // Get the paramaters passed from the web
Serial.print ( ":-" ); // page, checking they exist
if ( request->hasParam ( "setActPower" ))
{
Serial.print ( "setActPower;" );
AsyncWebParameter* setLevelInput = request->getParam ( "setActPower" );
SetPowerLevel ( atof ( setLevelInput->value().c_str()) );
}
Serial.println();
request->redirect ( "index.html"); // Redirect to the index page
}
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 );
response->printf ( "Version=\"V%s\" ",PROGRAM_VERSION );
response->printf ( "Copyright=\"PD0EK\"" );
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 ( "/getSweep", HTTP_GET, onGetSweep ); // Set event to return sweep data as JSON array
server.on ( "/getGainSweep", HTTP_GET, onGetGainSweep ); // Set event to return sweep gain data as JSON array
server.on ( "/getSettings", HTTP_GET, onGetSettings ); // Set event to return settings data as JSON array
server.on ( "/doSetSweep", HTTP_POST, onSetSweep ); // Set event to set sweep values received from client
server.on ( "/doReboot", HTTP_GET, onDoReboot ); // Set event to reboot the ESP32
server.on ( "/getNameVersion", HTTP_GET, onGetNameVersion );// Set event to return name and version
server.on ( "/getScan", HTTP_GET, onGetScan ); // Set event to return sweep data as XML
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
server.on ( "/doSettings", HTTP_POST, onSettings ); // Set event to set setting values received from client
server.serveStatic ( "/", SPIFFS, "/" ).setDefaultFile ( "index.html" );
server.begin ();
}