some web interface updates
This commit is contained in:
parent
0d64f8d05d
commit
7b58febb45
17
README.md
17
README.md
|
|
@ -43,3 +43,20 @@ A SHORT press will switch to the next channel in channels.txt
|
||||||
|
|
||||||
A medium press will active scan the whole band (400..406 MHz) and display a
|
A medium press will active scan the whole band (400..406 MHz) and display a
|
||||||
spectrum diagram (each line == 50 kHz)
|
spectrum diagram (each line == 50 kHz)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Download https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
|
||||||
|
and move to your Arduino IDE's libraries directory
|
||||||
|
Rename to (name without "-master")
|
||||||
|
|
||||||
|
Download https://github.com/me-no-dev/AsyncTCP/archive/master.zip
|
||||||
|
and move to your Arduino IDE's libraries directory
|
||||||
|
Rename to (name without "-master")
|
||||||
|
|
||||||
|
Install Arduino ESP32 file system uploader
|
||||||
|
https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/
|
||||||
|
Download https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/download/1.0/ESP32FS-1.0.zip
|
||||||
|
Move to your Arduino IDE's tools directory
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,58 +48,29 @@ String processor(const String& var){
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupAsyncServer() {
|
#define MAX_QRG 10
|
||||||
// Route for root / web page
|
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send(200, "text/plain", "Hello, world");
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/index.html", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send(SPIFFS, "/index.html", String(), false, processor);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route to load style.css file
|
|
||||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
request->send(SPIFFS, "/style.css", "text/css");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route to set GPIO to HIGH
|
const String sondeTypeSelect(int activeType) {
|
||||||
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
|
String sts = "";
|
||||||
digitalWrite(ledPin, HIGH);
|
for(int i=0; i<3; i++) {
|
||||||
request->send(SPIFFS, "/index.html", String(), false, processor);
|
sts += "<option value=\"";
|
||||||
});
|
sts += sondeTypeStr[i];
|
||||||
|
sts += "\"";
|
||||||
// Route to set GPIO to LOW
|
if(activeType==i) { sts += " selected"; }
|
||||||
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
|
sts += ">";
|
||||||
digitalWrite(ledPin, LOW);
|
sts += sondeTypeStr[i];
|
||||||
request->send(SPIFFS, "/index.html", String(), false, processor);
|
sts += "</option>";
|
||||||
});
|
}
|
||||||
|
return sts;
|
||||||
// Start server
|
|
||||||
server.begin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nNetworks;
|
|
||||||
struct { String id; String pw; } networks[20];
|
|
||||||
|
|
||||||
void setupWifiList() {
|
//trying to work around
|
||||||
File file = SPIFFS.open("/networks.txt", "r");
|
//"assertion "heap != NULL && "free() target pointer is outside heap areas"" failed:"
|
||||||
if(!file){
|
// which happens if request->send is called in createQRGForm!?!??
|
||||||
Serial.println("There was an error opening the file '/networks.txt' for reading");
|
char message[10240];
|
||||||
return;
|
|
||||||
}
|
///////////////////////// Functions for Reading / Writing QRG list from/to qrg.txt
|
||||||
int i=0;
|
|
||||||
while(file.available()) {
|
|
||||||
String line = file.readStringUntil('\n');
|
|
||||||
if(!file.available()) break;
|
|
||||||
networks[i].id = line;
|
|
||||||
networks[i].pw = file.readStringUntil('\n');
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
nNetworks = i;
|
|
||||||
Serial.print(i); Serial.println(" networks in networks.txt\n");
|
|
||||||
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupChannelList() {
|
void setupChannelList() {
|
||||||
File file = SPIFFS.open("/qrg.txt", "r");
|
File file = SPIFFS.open("/qrg.txt", "r");
|
||||||
|
|
@ -122,16 +93,211 @@ void setupChannelList() {
|
||||||
else if (space[1]=='9') { type=STYPE_DFM09; }
|
else if (space[1]=='9') { type=STYPE_DFM09; }
|
||||||
else if (space[1]=='6') { type=STYPE_DFM06; }
|
else if (space[1]=='6') { type=STYPE_DFM06; }
|
||||||
else continue;
|
else continue;
|
||||||
Serial.printf("Adding %f with type %d\b",freq,type);
|
int active = space[3]=='+'?1:0;
|
||||||
sonde.addSonde(freq, type);
|
Serial.printf("Adding %f with type %d (active: %d)\n",freq,type,active);
|
||||||
|
sonde.addSonde(freq, type, active);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *createQRGForm() {
|
||||||
|
char *ptr = message;
|
||||||
|
strcpy(ptr,"<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"></head><body><form action=\"qrg.html\" method=\"post\"><table><tr><th>ID</th><th>Active</th><th>Freq</th><th>Mode</th></tr>");
|
||||||
|
for(int i=0; i<10; i++) {
|
||||||
|
String s = sondeTypeSelect(i>=sonde.nSonde?2:sonde.sondeList[i].type);
|
||||||
|
sprintf(ptr+strlen(ptr), "<tr><td>%d</td><td><input name=\"A%d\" type=\"checkbox\" %s/></td>"
|
||||||
|
"<td><input name=\"F%d\" type=\"text\" value=\"%3.3f\"></td>"
|
||||||
|
"<td><select name=\"T%d\">%s</select></td>",
|
||||||
|
i+1,
|
||||||
|
i+1, (i<sonde.nSonde&&sonde.sondeList[i].active)?"checked":"",
|
||||||
|
i+1, i>=sonde.nSonde?400.000:sonde.sondeList[i].freq,
|
||||||
|
i+1, s.c_str());
|
||||||
|
}
|
||||||
|
strcat(ptr,"</table><input type=\"submit\" value=\"Update\"/></form></body></html>");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *handleQRGPost(AsyncWebServerRequest *request) {
|
||||||
|
char label[10];
|
||||||
|
// parameters: a_i, f_1, t_i (active/frequency/type)
|
||||||
|
#if 1
|
||||||
|
File f = SPIFFS.open("/qrg.txt", "w");
|
||||||
|
if(!f) {
|
||||||
|
Serial.println("Error while opening '/qrg.txt' for writing");
|
||||||
|
return "Error while opening '/qrg.txt' for writing";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Serial.println("Handling post request");
|
||||||
|
#if 0
|
||||||
|
int params = request->params();
|
||||||
|
for(int i=0; i<params; i++) {
|
||||||
|
Serial.println(request->getParam(i)->name().c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for(int i=1; i<=MAX_QRG; i++) {
|
||||||
|
snprintf(label, 10, "A%d", i);
|
||||||
|
AsyncWebParameter *active = request->getParam(label, true);
|
||||||
|
snprintf(label, 10, "F%d", i);
|
||||||
|
AsyncWebParameter *freq = request->getParam(label, true);
|
||||||
|
if(!freq) continue;
|
||||||
|
snprintf(label, 10, "T%d", i);
|
||||||
|
AsyncWebParameter *type = request->getParam(label, true);
|
||||||
|
if(!type) continue;
|
||||||
|
const char *fstr = freq->value().c_str();
|
||||||
|
const char *tstr = type->value().c_str();
|
||||||
|
Serial.printf("Processing a=%s, f=%s, t=%s\n", active?"YES":"NO", fstr, tstr);
|
||||||
|
char typech = (tstr[2]=='4'?'4':tstr[3]); // Ugly TODO
|
||||||
|
f.printf("%3.3f %c %c\n", atof(fstr), typech, active?'+':'-');
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
setupChannelList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////// Functions for reading/writing Wifi networks from networks.txt
|
||||||
|
|
||||||
|
#define MAX_WIFI 10
|
||||||
|
int nNetworks;
|
||||||
|
struct { String id; String pw; } networks[MAX_WIFI];
|
||||||
|
|
||||||
|
// FIXME: For now, we don't uspport wifi networks that contain newline or null characters
|
||||||
|
// ... would require a more sophisicated file format (currently one line SSID; one line Password
|
||||||
|
void setupWifiList() {
|
||||||
|
File file = SPIFFS.open("/networks.txt", "r");
|
||||||
|
if(!file){
|
||||||
|
Serial.println("There was an error opening the file '/networks.txt' for reading");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while(file.available()) {
|
||||||
|
String line = file.readStringUntil('\n');
|
||||||
|
if(!file.available()) break;
|
||||||
|
networks[i].id = line;
|
||||||
|
networks[i].pw = file.readStringUntil('\n');
|
||||||
|
i++;
|
||||||
|
}
|
||||||
nNetworks = i;
|
nNetworks = i;
|
||||||
Serial.print(i); Serial.println(" networks in networks.txt\n");
|
Serial.print(i); Serial.println(" networks in networks.txt\n");
|
||||||
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *createWIFIForm() {
|
||||||
|
char *ptr = message;
|
||||||
|
char tmp[4];
|
||||||
|
strcpy(ptr,"<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"></head><body><form action=\"wifi.html\" method=\"post\"><table><tr><th>Nr</th><th>SSID</th><th>Password</th></tr>");
|
||||||
|
for(int i=0; i<MAX_WIFI; i++) {
|
||||||
|
sprintf(tmp,"%d",i);
|
||||||
|
sprintf(ptr+strlen(ptr), "<tr><td>%s</td><td><input name=\"S%d\" type=\"text\" value=\"%s\"/></td>"
|
||||||
|
"<td><input name=\"P%d\" type=\"text\" value=\"%s\"/></td>",
|
||||||
|
i==0?"<b>AP</b>":tmp,
|
||||||
|
i+1, i<nNetworks?networks[i].id.c_str():"",
|
||||||
|
i+1, i<nNetworks?networks[i].pw.c_str():"");
|
||||||
|
}
|
||||||
|
strcat(ptr,"</table><input type=\"submit\" value=\"Update\"></input></form></body></html>");
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *handleWIFIPost(AsyncWebServerRequest *request) {
|
||||||
|
char label[10];
|
||||||
|
// parameters: a_i, f_1, t_i (active/frequency/type)
|
||||||
|
#if 1
|
||||||
|
File f = SPIFFS.open("/networks.txt", "w");
|
||||||
|
if(!f) {
|
||||||
|
Serial.println("Error while opening '/networks.txt' for writing");
|
||||||
|
return "Error while opening '/networks.txt' for writing";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Serial.println("Handling post request");
|
||||||
|
#if 0
|
||||||
|
int params = request->params();
|
||||||
|
for(int i=0; i<params; i++) {
|
||||||
|
Serial.println(request->getParam(i)->name().c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for(int i=1; i<=MAX_WIFI; i++) {
|
||||||
|
snprintf(label, 10, "S%d", i);
|
||||||
|
AsyncWebParameter *ssid = request->getParam(label, true);
|
||||||
|
if(!ssid) continue;
|
||||||
|
snprintf(label, 10, "P%d", i);
|
||||||
|
AsyncWebParameter *pw = request->getParam(label, true);
|
||||||
|
if(!pw) continue;
|
||||||
|
const char *sstr = ssid->value().c_str();
|
||||||
|
const char *pstr = pw->value().c_str();
|
||||||
|
if(strlen(sstr)==0) continue;
|
||||||
|
Serial.printf("Processing S=%s, P=%s\n", sstr, pstr);
|
||||||
|
f.printf("%s\n%s\n", sstr, pstr);
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
setupWifiList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* PARAM_MESSAGE = "message";
|
||||||
|
void SetupAsyncServer() {
|
||||||
|
// Route for root / web page
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", "Hello, world");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/index.html", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(SPIFFS, "/index.html", String(), false, processor);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/test.html", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(SPIFFS, "/test.html", String(), false, processor);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/qrg.html", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/html", createQRGForm());
|
||||||
|
});
|
||||||
|
server.on("/qrg.html", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
handleQRGPost(request);
|
||||||
|
request->send(200, "text/html", createQRGForm());
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/wifi.html", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/html", createWIFIForm());
|
||||||
|
});
|
||||||
|
server.on("/wifi.html", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
handleWIFIPost(request);
|
||||||
|
request->send(200, "text/html", createWIFIForm());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to load style.css file
|
||||||
|
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(SPIFFS, "/style.css", "text/css");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to set GPIO to HIGH
|
||||||
|
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
digitalWrite(ledPin, HIGH);
|
||||||
|
request->send(SPIFFS, "/index.html", String(), false, processor);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to set GPIO to HIGH
|
||||||
|
server.on("/test.php", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
//digitalWrite(ledPin, HIGH);
|
||||||
|
request->send(SPIFFS, "/index.html", String(), false, processor);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to set GPIO to LOW
|
||||||
|
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
digitalWrite(ledPin, LOW);
|
||||||
|
request->send(SPIFFS, "/index.html", String(), false, processor);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a POST request to <IP>/post with a form field message set to <message>
|
||||||
|
server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
handleQRGPost(request);
|
||||||
|
request->send(200, "text/plain", "Hello, POST done");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *fetchWifiPw(const char *id) {
|
const char *fetchWifiPw(const char *id) {
|
||||||
for(int i=0; i<nNetworks; i++) {
|
for(int i=0; i<nNetworks; i++) {
|
||||||
Serial.print("Comparing '");
|
Serial.print("Comparing '");
|
||||||
|
|
@ -369,7 +535,7 @@ void loopWifiScan() {
|
||||||
pw=fetchWifiPw(id);
|
pw=fetchWifiPw(id);
|
||||||
if(pw) break;
|
if(pw) break;
|
||||||
}
|
}
|
||||||
if(1||!pw) { id="test"; pw="test"; }
|
if(!pw) { id="test"; pw="test"; }
|
||||||
Serial.print("Connecting to: "); Serial.println(id);
|
Serial.print("Connecting to: "); Serial.println(id);
|
||||||
u8x8.drawString(0,6, "Conn:");
|
u8x8.drawString(0,6, "Conn:");
|
||||||
u8x8.drawString(6,6, id);
|
u8x8.drawString(6,6, id);
|
||||||
|
|
@ -386,11 +552,13 @@ void loopWifiScan() {
|
||||||
if(cnt==10) {
|
if(cnt==10) {
|
||||||
WiFi.disconnect();
|
WiFi.disconnect();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
WiFi.softAP("sonde","sondesonde");
|
WiFi.softAP(networks[0].id.c_str(),networks[0].pw.c_str());
|
||||||
IPAddress myIP = WiFi.softAPIP();
|
IPAddress myIP = WiFi.softAPIP();
|
||||||
Serial.print("AP IP address: ");
|
Serial.print("AP IP address: ");
|
||||||
Serial.println(myIP);
|
Serial.println(myIP);
|
||||||
sonde.setIP(myIP.toString().c_str());
|
u8x8.drawString(0,6, "AP: ");
|
||||||
|
u8x8.drawString(6,6, networks[0].id.c_str());
|
||||||
|
sonde.setIP(myIP.toString().c_str(), true);
|
||||||
sonde.updateDisplayIP();
|
sonde.updateDisplayIP();
|
||||||
SetupAsyncServer();
|
SetupAsyncServer();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
@ -403,7 +571,7 @@ void loopWifiScan() {
|
||||||
Serial.println("WiFi connected");
|
Serial.println("WiFi connected");
|
||||||
Serial.println("IP address: ");
|
Serial.println("IP address: ");
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
sonde.setIP(WiFi.localIP().toString().c_str());
|
sonde.setIP(WiFi.localIP().toString().c_str(), false);
|
||||||
sonde.updateDisplayIP();
|
sonde.updateDisplayIP();
|
||||||
SetupAsyncServer();
|
SetupAsyncServer();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,44 @@
|
||||||
<p><a href="/on"><button class="button">ON</button></a></p>
|
<p><a href="/on"><button class="button">ON</button></a></p>
|
||||||
<p><a href="/off"><button class="button button2">OFF</button></a></p>
|
<p><a href="/off"><button class="button button2">OFF</button></a></p>
|
||||||
-->
|
-->
|
||||||
<table class="KKK">
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th style="width:100px">ID</th>
|
|
||||||
<th style="width:100px">PW</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1</td>
|
|
||||||
<td contenteditable>DinoGast</td>
|
|
||||||
<td contenteditable>Schokolade</td>
|
|
||||||
<tr>
|
|
||||||
<td>2</td>
|
|
||||||
<td contenteditable></td>
|
|
||||||
<td contenteditable></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
<div class="tab">
|
||||||
|
<button class="tablinks" onclick="selTab(event,'QRG')" id="defaultTab">QRG</button>
|
||||||
|
<button class="tablinks" onclick="selTab(event,'WIFI')">WLAN</button>
|
||||||
|
<button class="tablinks" onclick="selTab(event,'About')">About</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="QRG" class="tabcontent">
|
||||||
|
<h3> QRG</h3>
|
||||||
|
<iframe src="qrg.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="WIFI" class="tabcontent">
|
||||||
|
<h3> WIFI</h3>
|
||||||
|
<iframe src="wifi.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="About" class="tabcontent">
|
||||||
|
<h3>About</h3>
|
||||||
|
RDZSonde
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function selTab(evt, id) {
|
||||||
|
var i, tabcontent, tablinks;
|
||||||
|
tabcontent=document.getElementsByClassName("tabcontent");
|
||||||
|
for(i=0; i<tabcontent.length; i++) {
|
||||||
|
tabcontent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
tablinks=document.getElementsByClassName("tablinks");
|
||||||
|
for(i=0; i<tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
document.getElementById(id).style.display = "block";
|
||||||
|
evt.currentTarget.className += " active";
|
||||||
|
}
|
||||||
|
document.getElementById("defaultTab").click();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
RDZsonde
|
||||||
|
RDZsonde
|
||||||
DinoGast
|
DinoGast
|
||||||
Schokolade
|
Schokolade
|
||||||
AndroidDD
|
AndroidDD
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Frequency in Mhz (format nnn.nnn)
|
# Frequency in Mhz (format nnn.nnn)
|
||||||
# Type (4=RS41, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09)
|
# Type (4=RS41, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09)
|
||||||
#
|
#
|
||||||
402.700 4
|
402.700 4 +
|
||||||
402.300 4
|
402.300 4 +
|
||||||
403.450 9
|
403.450 9 +
|
||||||
405.100 4
|
405.100 4 -
|
||||||
# end
|
# end
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,40 @@
|
||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button {
|
||||||
|
background-color: inherit;
|
||||||
|
float: left;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 14px 16px;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button.active {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-top: none;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: Helvetica;
|
font-family: Helvetica;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,18 @@
|
||||||
|
|
||||||
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;
|
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;
|
||||||
|
|
||||||
#define CHANBW 25
|
#define CHANBW 10
|
||||||
#define SMOOTH 2
|
#define PIXSAMPL (50/CHANBW)
|
||||||
|
#define SMOOTH 4
|
||||||
#define STARTF 400000000
|
#define STARTF 400000000
|
||||||
#define NCHAN ((int)(6000/CHANBW))
|
#define NCHAN ((int)(6000/CHANBW))
|
||||||
|
|
||||||
int scanresult[NCHAN];
|
int scanresult[NCHAN];
|
||||||
int scandisp[NCHAN/2];
|
int scandisp[NCHAN/PIXSAMPL];
|
||||||
|
|
||||||
#define PLOT_N 120
|
#define PLOT_N 120
|
||||||
|
#define TICK1 (120/6)
|
||||||
|
#define TICK2 (TICK1/4)
|
||||||
#define PLOT_MIN -220
|
#define PLOT_MIN -220
|
||||||
#define PLOT_SCALE(x) (x<PLOT_MIN?0:(x-PLOT_MIN)/2)
|
#define PLOT_SCALE(x) (x<PLOT_MIN?0:(x-PLOT_MIN)/2)
|
||||||
|
|
||||||
|
|
@ -37,6 +40,8 @@ void Scanner::plotResult()
|
||||||
for(int i=0; i<PLOT_N; i+=8) {
|
for(int i=0; i<PLOT_N; i+=8) {
|
||||||
for(int j=0; j<8; j++) {
|
for(int j=0; j<8; j++) {
|
||||||
fillTiles(row+j, PLOT_SCALE(scandisp[i+j]));
|
fillTiles(row+j, PLOT_SCALE(scandisp[i+j]));
|
||||||
|
if( ((i+j)%TICK1)==0) { row[j] |= 0x07; }
|
||||||
|
if( ((i+j)%TICK2)==0) { row[j] |= 0x01; }
|
||||||
}
|
}
|
||||||
for(int y=0; y<8; y++) {
|
for(int y=0; y<8; y++) {
|
||||||
u8x8.drawTile(i/8, y, 1, row+8*y);
|
u8x8.drawTile(i/8, y, 1, row+8*y);
|
||||||
|
|
@ -59,11 +64,12 @@ void Scanner::scan()
|
||||||
sx1278.writeRegister(REG_RSSI_CONFIG, SMOOTH&0x07);
|
sx1278.writeRegister(REG_RSSI_CONFIG, SMOOTH&0x07);
|
||||||
sx1278.setFrequency(STARTF);
|
sx1278.setFrequency(STARTF);
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
delay(5);
|
delay(20);
|
||||||
|
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
uint32_t lastfrf=-1;
|
uint32_t lastfrf=-1;
|
||||||
for(int i=0; i<NCHAN; i++) {
|
for(int iter=0; iter<2; iter++) { // two interations, to catch all RS41 transmissions
|
||||||
|
for(int i=0; i<NCHAN; i++) {
|
||||||
float freq = STARTF + 1000.0*i*CHANBW;
|
float freq = STARTF + 1000.0*i*CHANBW;
|
||||||
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
|
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
|
||||||
if( (lastfrf>>16)!=(frf>>16) ) {
|
if( (lastfrf>>16)!=(frf>>16) ) {
|
||||||
|
|
@ -78,16 +84,24 @@ void Scanner::scan()
|
||||||
int wait = 20 + 1000*(1<<(SMOOTH+1))/4/CHANBW;
|
int wait = 20 + 1000*(1<<(SMOOTH+1))/4/CHANBW;
|
||||||
delayMicroseconds(wait);
|
delayMicroseconds(wait);
|
||||||
int rssi = -(int)sx1278.readRegister(REG_RSSI_VALUE_FSK);
|
int rssi = -(int)sx1278.readRegister(REG_RSSI_VALUE_FSK);
|
||||||
scanresult[i] = rssi;
|
if(iter==0) { scanresult[i] = rssi; } else {
|
||||||
|
if(rssi>scanresult[i]) scanresult[i]=rssi;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unsigned long duration = millis()-start;
|
unsigned long duration = millis()-start;
|
||||||
Serial.print("Scan time: ");
|
Serial.print("Scan time: ");
|
||||||
Serial.println(duration);
|
Serial.println(duration);
|
||||||
for(int i=0; i<NCHAN; i+=2) {
|
for(int i=0; i<NCHAN; i+=PIXSAMPL) {
|
||||||
scandisp[i/2] = scanresult[i];
|
scandisp[i/PIXSAMPL]=scanresult[i];
|
||||||
for(int j=1; j<2; j++) { if(scanresult[i+j]>scandisp[i/2]) scandisp[i/2] = scanresult[i+j]; }
|
for(int j=1; j<PIXSAMPL; j++) { scandisp[i/PIXSAMPL]+=scanresult[i+j]; }
|
||||||
|
//for(int j=1; j<PIXSAMPL; j++) { if(scanresult[i+j]>scandisp[i/PIXSAMPL]) scandisp[i/PIXSAMPL] = scanresult[i+j]; }
|
||||||
Serial.print(scanresult[i]); Serial.print(", ");
|
Serial.print(scanresult[i]); Serial.print(", ");
|
||||||
if(((i+1)%32) == 0) Serial.println();
|
}
|
||||||
|
Serial.println("\n");
|
||||||
|
for(int i=0; i<NCHAN/PIXSAMPL; i++) {
|
||||||
|
scandisp[i]/=PIXSAMPL;
|
||||||
|
Serial.print(scandisp[i]); Serial.print(", ");
|
||||||
}
|
}
|
||||||
Serial.println("\n");
|
Serial.println("\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ static unsigned char stattiles[4][4] = {
|
||||||
0x1F, 0x15, 0x15, 0x00 ,
|
0x1F, 0x15, 0x15, 0x00 ,
|
||||||
0x00, 0x1F, 0x00, 0x00 };
|
0x00, 0x1F, 0x00, 0x00 };
|
||||||
|
|
||||||
byte myIP_tiles[8*10];
|
byte myIP_tiles[8*11];
|
||||||
|
|
||||||
static const uint8_t font[10][5]={
|
static const uint8_t font[10][5]={
|
||||||
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
||||||
|
|
@ -37,12 +37,23 @@ static const uint8_t font[10][5]={
|
||||||
0x06, 0x49, 0x39, 0x29, 0x1E }; // 9; .=0x40
|
0x06, 0x49, 0x39, 0x29, 0x1E }; // 9; .=0x40
|
||||||
|
|
||||||
static uint8_t halfdb_tile[8]={0x80, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00};
|
static uint8_t halfdb_tile[8]={0x80, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00};
|
||||||
|
|
||||||
|
static uint8_t halfdb_tile1[8]={0x00, 0x38, 0x28, 0x28, 0x28, 0xC8, 0x00, 0x00};
|
||||||
|
static uint8_t halfdb_tile2[8]={0x00, 0x11, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00};
|
||||||
|
|
||||||
static uint8_t empty_tile[8]={0x80, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00};
|
static uint8_t empty_tile[8]={0x80, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00};
|
||||||
|
|
||||||
|
static uint8_t empty_tile1[8]={0x00, 0xF0, 0x88, 0x48, 0x28, 0xF0, 0x00, 0x00};
|
||||||
|
static uint8_t empty_tile2[8]={0x00, 0x11, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00};
|
||||||
|
static uint8_t ap_tile[8]={0x00,0x04,0x22,0x92, 0x92, 0x22, 0x04, 0x00};
|
||||||
|
|
||||||
void Sonde::setIP(const char *ip) {
|
|
||||||
int tp = 0;
|
void Sonde::setIP(const char *ip, bool AP) {
|
||||||
|
memset(myIP_tiles, 0, 11*8);
|
||||||
int len = strlen(ip);
|
int len = strlen(ip);
|
||||||
|
int pix = (len-3)*6+6;
|
||||||
|
int tp = 80-pix+8;
|
||||||
|
if(AP) memcpy(myIP_tiles+(tp<16?0:8), ap_tile, 8);
|
||||||
for(int i=0; i<len; i++) {
|
for(int i=0; i<len; i++) {
|
||||||
if(ip[i]=='.') { myIP_tiles[tp++]=0x40; myIP_tiles[tp++]=0x00; }
|
if(ip[i]=='.') { myIP_tiles[tp++]=0x40; myIP_tiles[tp++]=0x00; }
|
||||||
else {
|
else {
|
||||||
|
|
@ -58,18 +69,26 @@ void Sonde::setIP(const char *ip) {
|
||||||
void Sonde::clearSonde() {
|
void Sonde::clearSonde() {
|
||||||
nSonde = 0;
|
nSonde = 0;
|
||||||
}
|
}
|
||||||
void Sonde::addSonde(float frequency, SondeType type) {
|
void Sonde::addSonde(float frequency, SondeType type, int active) {
|
||||||
if(nSonde>=MAXSONDE) {
|
if(nSonde>=MAXSONDE) {
|
||||||
Serial.println("Cannot add another sonde, MAXSONDE reached");
|
Serial.println("Cannot add another sonde, MAXSONDE reached");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sondeList[nSonde].type = type;
|
sondeList[nSonde].type = type;
|
||||||
sondeList[nSonde].freq = frequency;
|
sondeList[nSonde].freq = frequency;
|
||||||
|
sondeList[nSonde].active = active;
|
||||||
memcpy(sondeList[nSonde].rxStat, "\x00\x01\x2\x3\x2\x1\x1\x2\x0\x3\x0\x0\x1\x2\x3\x1\x0", 18);
|
memcpy(sondeList[nSonde].rxStat, "\x00\x01\x2\x3\x2\x1\x1\x2\x0\x3\x0\x0\x1\x2\x3\x1\x0", 18);
|
||||||
nSonde++;
|
nSonde++;
|
||||||
}
|
}
|
||||||
void Sonde::nextConfig() {
|
void Sonde::nextConfig() {
|
||||||
currentSonde++;
|
currentSonde++;
|
||||||
|
// Skip non-active entries (but don't loop forever if there are no active ones
|
||||||
|
for(int i=0; i<MAXSONDE; i++) {
|
||||||
|
if(!sondeList[currentSonde].active) {
|
||||||
|
currentSonde++;
|
||||||
|
if(currentSonde>=nSonde) currentSonde=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(currentSonde>=nSonde) {
|
if(currentSonde>=nSonde) {
|
||||||
currentSonde=0;
|
currentSonde=0;
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +179,8 @@ void Sonde::updateDisplayRSSI() {
|
||||||
int len=strlen(buf)-3;
|
int len=strlen(buf)-3;
|
||||||
buf[5]=0;
|
buf[5]=0;
|
||||||
u8x8.drawString(0,6,buf);
|
u8x8.drawString(0,6,buf);
|
||||||
u8x8.drawTile(len,6,1,(sonde.si()->rssi&1)?halfdb_tile:empty_tile);
|
u8x8.drawTile(len,6,1,(sonde.si()->rssi&1)?halfdb_tile1:empty_tile1);
|
||||||
|
u8x8.drawTile(len,7,1,(sonde.si()->rssi&1)?halfdb_tile2:empty_tile2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonde::updateStat() {
|
void Sonde::updateStat() {
|
||||||
|
|
@ -183,7 +203,7 @@ void Sonde::updateDisplayRXConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonde::updateDisplayIP() {
|
void Sonde::updateDisplayIP() {
|
||||||
u8x8.drawTile(6, 7, 10, myIP_tiles);
|
u8x8.drawTile(5, 7, 11, myIP_tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probing RS41
|
// Probing RS41
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ extern const char *sondeTypeStr[5];
|
||||||
|
|
||||||
typedef struct st_sondeinfo {
|
typedef struct st_sondeinfo {
|
||||||
// receiver configuration
|
// receiver configuration
|
||||||
|
bool active;
|
||||||
SondeType type;
|
SondeType type;
|
||||||
float freq;
|
float freq;
|
||||||
// decoded ID
|
// decoded ID
|
||||||
|
|
@ -37,12 +38,13 @@ typedef struct st_sondeinfo {
|
||||||
class Sonde
|
class Sonde
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int nSonde;
|
|
||||||
int currentSonde = 0;
|
int currentSonde = 0;
|
||||||
SondeInfo sondeList[MAXSONDE+1];
|
|
||||||
public:
|
public:
|
||||||
|
int nSonde;
|
||||||
|
SondeInfo sondeList[MAXSONDE+1];
|
||||||
|
|
||||||
void clearSonde();
|
void clearSonde();
|
||||||
void addSonde(float frequency, SondeType type);
|
void addSonde(float frequency, SondeType type, int active);
|
||||||
void nextConfig();
|
void nextConfig();
|
||||||
void setup();
|
void setup();
|
||||||
|
|
||||||
|
|
@ -59,7 +61,7 @@ public:
|
||||||
void updateDisplay();
|
void updateDisplay();
|
||||||
void updateDisplayScanner();
|
void updateDisplayScanner();
|
||||||
void clearDisplay();
|
void clearDisplay();
|
||||||
void setIP(const char *ip);
|
void setIP(const char *ip, bool isAP);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Sonde sonde;
|
extern Sonde sonde;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue