v0.6b: DL2MF pull request #8 from DL2MF and some minor local modifications

- Configure and show launch site information for each frequency
 - mDNS (access your device with http://rdzsonde.local instead of IP address)
 - Wifi services (mDNS and UDP) work again also in wifi mode 3
 - experimental OTA update support
 - Better button initialization, works now also with TTGO T-Beam

Squashed commit of the following:

commit 84566ec4dd
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri May 3 14:07:39 2019 +0200

    enable network services in all wifi modes

commit 7cf4b116a6
Merge: 3ae104d b676149
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri May 3 13:34:35 2019 +0200

    Merge branch 'p8' (pull request #8) into devel

commit b6761498aa
Author: DL2MF <meinhard.guenther@gmail.com>
Date:   Fri May 3 13:07:08 2019 +0200

    Fixed RX display line 1

commit 3ae104d10f
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri May 3 11:55:26 2019 +0200

    + default AP name if networks.txt is missing

commit c0fc4980c2
Author: DL2MF <meinhard.guenther@gmail.com>
Date:   Fri May 3 11:38:21 2019 +0200

    Added launchsite info to scan and webinterface

commit c259e75ce6
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri May 3 08:15:33 2019 +0200

    ...and update version info

commit 2eaba4fe7e
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri May 3 07:53:21 2019 +0200

    lokale IP per mDNS annoncieren (http://rdzsonde.local/)

commit 1732f17cce
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Wed May 1 19:21:29 2019 +0200

    fix travis directory listing

commit dc16c9fa07
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Wed May 1 19:14:36 2019 +0200

    explicitly set button pin as input

commit 8bd087a9f0
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Wed May 1 00:27:17 2019 +0200

    playing around with OTA updates
pull/22/head
Hansi, dl9rdz 2019-05-03 14:11:18 +02:00
rodzic 98bd469dd8
commit 1b68b096a7
6 zmienionych plików z 318 dodań i 65 usunięć

Wyświetl plik

@ -7,7 +7,7 @@ generate_website_index() {
echo "<html><head>" > download.html
echo "<meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" >> download.html
echo "<title>rdz_ttgo_sonde</title>" >> download.html
echo '<link rel="stylesheet" href="/rdz_ttgo_sonde/assets/css/style.css?v=a43710928bb200926b87aed147b540673ccb0378">' >> download.html
echo '<link rel="stylesheet" href="/assets/css/style.css?v=a43710928bb200926b87aed147b540673ccb0378">' >> download.html
echo "</head><body>" >> download.html
echo '<div class="wrapper"><header><h1><a href="https://dl9rdz.github.io/rdz_ttgo_sonde/">rdz_ttgo_sonde</a></h1><p></p>' >> download.html
echo '<p class="view"><a href="https://github.com/dl9rdz/rdz_ttgo_sonde">View the Project on GitHub <small>dl9rdz/rdz_ttgo_sonde</small></a></p>' >> download.html
@ -21,6 +21,7 @@ generate_website_index() {
echo "</ul><h2>Development repository</h2><ul>" >> download.html
for i in `ls devel`; do
TS=`git log devel/$i | grep "Date:" | head -1 | awk '{$1="";$2="";$7="";print substr($0,3,length($0)-3)}'`
if [ -z "$TS" ]; then TS=`date`; fi
echo "<li><a href=\"devel/$i\">$i</a> ($TS)</li>\n" >> download.html;
done
echo "</ul></section></body></html>" >> download.html
@ -40,6 +41,8 @@ commit_website_files() {
mkdir -p devel
cp ${MYPATH}/out.bin ${BRANCH}/${VERSION}-full.bin
git add ${BRANCH}/${VERSION}-full.bin
cp ${MYPATH}/build/RX_FSK.ino.bin ${BRANCH}/update.ino.bin
git add ${BRANCH}/update.ino.bin
# git commit --message "Travis build: $TRAVIS_BUILD_NUMBER"
}
upload_files() {

Wyświetl plik

@ -5,6 +5,8 @@
#include <U8x8lib.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Update.h>
#include <ESPmDNS.h>
#include <SX1278FSK.h>
#include <Sonde.h>
@ -21,12 +23,22 @@ U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8 = NULL; // initialize later after readin
int LORA_LED = 9; // default POUT for LORA LED used as serial monitor
int e;
enum MainState { ST_DECODER, ST_SCANNER, ST_SPECTRUM, ST_WIFISCAN, ST_UPDATE };
static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN;
AsyncWebServer server(80);
String updateHost = "rdzsonde.my.to";
int updatePort = 80;
String updateBinM = "/master/update.ino.bin";
String updateBinD = "/devel/update.ino.bin";
String *updateBin = &updateBinM;
#define LOCALUDPPORT 9002
boolean connected = false;
WiFiUDP udp;
WiFiClient client;
// Set LED GPIO
int ledPin = 1;
@ -49,10 +61,10 @@ String processor(const String& var) {
Serial.print(ledState);
return ledState;
}
if(var == "VERSION_NAME") {
if (var == "VERSION_NAME") {
return String(version_name);
}
if(var == "VERSION_ID") {
if (var == "VERSION_ID") {
return String(version_id);
}
return String();
@ -78,7 +90,7 @@ const String sondeTypeSelect(int activeType) {
//trying to work around
//"assertion "heap != NULL && "free() target pointer is outside heap areas"" failed:"
// which happens if request->send is called in createQRGForm!?!??
char message[10240*4]; //needs to be large enough for all forms (not checked in code)
char message[10240 * 4]; //needs to be large enough for all forms (not checked in code)
// QRG form is currently about 24kb with 100 entries
///////////////////////// Functions for Reading / Writing QRG list from/to qrg.txt
@ -90,10 +102,12 @@ void setupChannelList() {
return;
}
int i = 0;
char launchsite[17];
sonde.clearSonde();
Serial.println("Reading channel config:");
while (file.available()) {
String line = file.readStringUntil('\n');
String sitename;
if (!file.available()) break;
if (line[0] == '#') continue;
char *space = strchr(line.c_str(), ' ');
@ -112,24 +126,37 @@ void setupChannelList() {
}
else continue;
int active = space[3] == '+' ? 1 : 0;
char *launchsite = strchr(line.c_str(), ' ');
Serial.printf("Add %f - type %d (on/off: %d)- Site: \n", freq, type, active, launchsite);
if (space[4] == ' ') {
sitename = line.substring(12) + " "; // Don't change start of substr(12) !!!!
int str_len = sitename.length() + 1;
sitename.toCharArray(launchsite, 17);
if (sonde.config.debug == 1) {
Serial.printf("Add %f - sondetype: %d (on/off: %d) - site #%d - name: %s\n ", freq, type, active, i, launchsite);
//Serial.println(sitename);
}
}
sonde.addSonde(freq, type, active, launchsite);
i++;
}
file.close();
}
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>");
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>Launchsite</th><th>Mode</th></tr>");
for (int i = 0; i < sonde.config.maxsonde; i++) {
String s = sondeTypeSelect(i >= sonde.nSonde ? 2 : sonde.sondeList[i].type);
String site = sonde.sondeList[i].launchsite;
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><input name=\"S%d\" type=\"text\" value=\"%s\"></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, i >= sonde.nSonde ? " " : sonde.sondeList[i].launchsite,
i + 1, s.c_str());
}
strcat(ptr, "</table><input type=\"submit\" value=\"Update\"/></form></body></html>");
@ -140,8 +167,8 @@ 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) {
File file = SPIFFS.open("/qrg.txt", "w");
if (!file) {
Serial.println("Error while opening '/qrg.txt' for writing");
return "Error while opening '/qrg.txt' for writing";
}
@ -159,22 +186,27 @@ const char *handleQRGPost(AsyncWebServerRequest *request) {
AsyncWebParameter *active = request->getParam(label, true);
snprintf(label, 10, "F%d", i);
AsyncWebParameter *freq = request->getParam(label, true);
snprintf(label, 10, "S%d", i);
AsyncWebParameter *launchsite = request->getParam(label, true);
if (!freq) continue;
snprintf(label, 10, "T%d", i);
AsyncWebParameter *type = request->getParam(label, true);
if (!type) continue;
String fstring = freq->value();
String tstring = type->value();
String sstring = launchsite->value();
const char *fstr = fstring.c_str();
const char *tstr = tstring.c_str();
Serial.printf("Processing a=%s, f=%s, t=%s\n", active ? "YES" : "NO", fstr, tstr);
const char *sstr = sstring.c_str();
Serial.printf("Processing a=%s, f=%s, t=%s, site=%s\n", active ? "YES" : "NO", fstr, tstr, sstr);
char typech = (tstr[2] == '4' ? '4' : tstr[3]); // Ugly TODO
f.printf("%3.3f %c %c\n", atof(fstr), typech, active ? '+' : '-');
file.printf("%3.3f %c %c %s\n", atof(fstr), typech, active ? '+' : '-', sstr);
}
f.close();
file.close();
Serial.println("Channel setup finished");
Serial.println();
delay(500);
setupChannelList();
}
@ -194,6 +226,8 @@ void setupWifiList() {
File file = SPIFFS.open("/networks.txt", "r");
if (!file) {
Serial.println("There was an error opening the file '/networks.txt' for reading");
networks[0].id = "RDZsonde";
networks[0].pw = "RDZsonde";
return;
}
int i = 0;
@ -319,43 +353,43 @@ struct st_configitems {
struct st_configitems config_list[] = {
/* General config settings */
{"wifi","Wifi mode (0/1/2/3)", 0, &sonde.config.wifi},
{"debug","Debug mode (0/1)", 0, &sonde.config.debug},
{"maxsonde","Maxsonde (requires reboot?)", 0, &sonde.config.maxsonde},
{"wifi", "Wifi mode (0/1/2/3)", 0, &sonde.config.wifi},
{"debug", "Debug mode (0/1)", 0, &sonde.config.debug},
{"maxsonde", "Maxsonde (requires reboot?)", 0, &sonde.config.maxsonde},
/* Spectrum display settings */
{"spectrum","ShowSpectrum (s)", 0, &sonde.config.spectrum},
{"startfreq","Startfreq (MHz)", 0, &sonde.config.startfreq},
{"channelbw","Bandwidth (kHz)", 0, &sonde.config.channelbw},
{"timer","Spectrum Timer", 0, &sonde.config.timer},
{"marker","Spectrum MHz marker", 0, &sonde.config.marker},
{"noisefloor","Sepctrum noisefloor", 0, &sonde.config.noisefloor},
{"spectrum", "ShowSpectrum (s)", 0, &sonde.config.spectrum},
{"startfreq", "Startfreq (MHz)", 0, &sonde.config.startfreq},
{"channelbw", "Bandwidth (kHz)", 0, &sonde.config.channelbw},
{"timer", "Spectrum Timer", 0, &sonde.config.timer},
{"marker", "Spectrum MHz marker", 0, &sonde.config.marker},
{"noisefloor", "Sepctrum noisefloor", 0, &sonde.config.noisefloor},
{"---", "---", -1, NULL},
/* APRS settings */
{"call","Call", 8, sonde.config.call},
{"passcode","Passcode", 8, sonde.config.passcode},
{"call", "Call", 8, sonde.config.call},
{"passcode", "Passcode", 8, sonde.config.passcode},
{"---", "---", -1, NULL},
/* AXUDP settings */
{"axudp.active","AXUDP active", -3, &sonde.config.udpfeed.active},
{"axudp.host","AXUDP Host", 63, sonde.config.udpfeed.host},
{"axudp.port","AXUDP Port", 0, &sonde.config.udpfeed.port},
{"axudp.idformat","DFM ID Format", -2, &sonde.config.udpfeed.idformat},
{"axudp.highrate","Rate limit", 0, &sonde.config.udpfeed.highrate},
{"axudp.active", "AXUDP active", -3, &sonde.config.udpfeed.active},
{"axudp.host", "AXUDP Host", 63, sonde.config.udpfeed.host},
{"axudp.port", "AXUDP Port", 0, &sonde.config.udpfeed.port},
{"axudp.idformat", "DFM ID Format", -2, &sonde.config.udpfeed.idformat},
{"axudp.highrate", "Rate limit", 0, &sonde.config.udpfeed.highrate},
{"---", "---", -1, NULL},
/* APRS TCP settings, current not used */
{"tcp.active","APRS TCP active", -3, &sonde.config.tcpfeed.active},
{"tcp.host","ARPS TCP Host", 63, sonde.config.tcpfeed.host},
{"tcp.port","APRS TCP Port", 0, &sonde.config.tcpfeed.port},
{"tcp.idformat","DFM ID Format", -2, &sonde.config.tcpfeed.idformat},
{"tcp.highrate","Rate limit", 0, &sonde.config.tcpfeed.highrate},
{"tcp.active", "APRS TCP active", -3, &sonde.config.tcpfeed.active},
{"tcp.host", "ARPS TCP Host", 63, sonde.config.tcpfeed.host},
{"tcp.port", "APRS TCP Port", 0, &sonde.config.tcpfeed.port},
{"tcp.idformat", "DFM ID Format", -2, &sonde.config.tcpfeed.idformat},
{"tcp.highrate", "Rate limit", 0, &sonde.config.tcpfeed.highrate},
{"---", "---", -1, NULL},
/* Hardware dependeing settings */
{"oled_sda","OLED SDA (needs reboot)", 0, &sonde.config.oled_sda},
{"oled_scl","OLED SCL (needs reboot)", 0, &sonde.config.oled_scl},
{"oled_rst","OLED RST (needs reboot)", 0, &sonde.config.oled_rst},
{"button_pin","Button input port (needs reboot)", 0, &sonde.config.button_pin},
{"led_pout","LED output port (needs reboot)", 0, &sonde.config.led_pout},
{"oled_sda", "OLED SDA (needs reboot)", 0, &sonde.config.oled_sda},
{"oled_scl", "OLED SCL (needs reboot)", 0, &sonde.config.oled_scl},
{"oled_rst", "OLED RST (needs reboot)", 0, &sonde.config.oled_rst},
{"button_pin", "Button input port (needs reboot)", 0, &sonde.config.button_pin},
{"led_pout", "LED output port (needs reboot)", 0, &sonde.config.led_pout},
};
const static int N_CONFIG=(sizeof(config_list)/sizeof(struct st_configitems));
const static int N_CONFIG = (sizeof(config_list) / sizeof(struct st_configitems));
void addConfigStringEntry(char *ptr, int idx, const char *label, int len, char *field) {
sprintf(ptr + strlen(ptr), "<tr><td>%s</td><td><input name=\"CFG%d\" type=\"text\" value=\"%s\"/></td></tr>\n",
@ -424,12 +458,12 @@ const char *handleConfigPost(AsyncWebServerRequest *request) {
for (int i = 0; i < params; i++) {
String strlabel = request->getParam(i)->name();
const char *label = strlabel.c_str();
if(strncmp(label, "CFG", 3)!=0) continue;
int idx = atoi(label+3);
if (strncmp(label, "CFG", 3) != 0) continue;
int idx = atoi(label + 3);
Serial.printf("idx is %d\n", idx);
if(config_list[idx].type == -1) continue; // skip separator entries, should not happen
if (config_list[idx].type == -1) continue; // skip separator entries, should not happen
AsyncWebParameter *value = request->getParam(label, true);
if(!value) continue;
if (!value) continue;
String strvalue = value->value();
Serial.printf("Processing %s=%s\n", config_list[idx].name, strvalue.c_str());
f.printf("%s=%s\n", config_list[idx].name, strvalue.c_str());
@ -438,6 +472,38 @@ const char *handleConfigPost(AsyncWebServerRequest *request) {
setupConfigData();
}
const char *createUpdateForm(boolean run) {
char *ptr = message;
char tmp[4];
strcpy(ptr, "<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"></head><body><form action=\"update.html\" method=\"post\">");
if(run) {
strcat(ptr, "<p>Doing update, wait until reboot</p>");
} else {
strcat(ptr, "<input type=\"submit\" name=\"master\" value=\"Master-Update\"></input><br><input type=\"submit\" name=\"devel\" value=\"Devel-Update\">");
}
strcat(ptr, "</form></body></html>");
return message;
}
const char *handleUpdatePost(AsyncWebServerRequest *request) {
Serial.println("Handling post request");
int params = request->params();
for (int i = 0; i < params; i++) {
String param = request->getParam(i)->name();
Serial.println(param.c_str());
if(param.equals("devel")) {
Serial.println("equals devel");
updateBin = &updateBinD;
}
else if(param.equals("master")) {
Serial.println("equals master");
updateBin = &updateBinM;
}
}
Serial.println("Updating: "+*updateBin);
enterMode(ST_UPDATE);
}
const char* PARAM_MESSAGE = "message";
void SetupAsyncServer() {
@ -478,9 +544,17 @@ void SetupAsyncServer() {
handleConfigPost(request);
request->send(200, "text/html", createConfigForm());
});
server.on("/status.html", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(200, "text/html", createStatusForm());
});
server.on("/update.html", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(200, "text/html", createUpdateForm(0));
});
server.on("/update.html", HTTP_POST, [](AsyncWebServerRequest * request) {
handleUpdatePost(request);
request->send(200, "text/html", createUpdateForm(1));
});
// Route to load style.css file
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
@ -505,12 +579,16 @@ int fetchWifiIndex(const char *id) {
}
Serial.printf("No match: '%s' vs '%s'\n", id, networks[i].id.c_str());
const char *cfgid = networks[i].id.c_str();
int len=strlen(cfgid);
if(strlen(id)>len) len=strlen(id);
int len = strlen(cfgid);
if (strlen(id) > len) len = strlen(id);
Serial.print("SSID: ");
for(int i = 0; i < len; i++) { Serial.printf("%02x ", id[i]); } Serial.println("");
for (int i = 0; i < len; i++) {
Serial.printf("%02x ", id[i]);
} Serial.println("");
Serial.print("Conf: ");
for(int i = 0; i < len; i++) { Serial.printf("%02x ", cfgid[i]); } Serial.println("");
for (int i = 0; i < len; i++) {
Serial.printf("%02x ", cfgid[i]);
} Serial.println("");
}
return -1;
}
@ -587,9 +665,9 @@ void setup()
char buf[12];
// Open serial communications and wait for port to open:
Serial.begin(115200);
for(int i=0; i<39; i++) {
for (int i = 0; i < 39; i++) {
int v = gpio_get_level((gpio_num_t)i);
Serial.printf("%d:%d ",i,v);
Serial.printf("%d:%d ", i, v);
}
Serial.println("");
pinMode(LORA_LED, OUTPUT);
@ -623,6 +701,7 @@ void setup()
setupWifiList();
button1.pin = sonde.config.button_pin;
pinMode(button1.pin, INPUT);
// == show initial values from config.txt ========================= //
if (sonde.config.debug == 1) {
@ -664,7 +743,6 @@ void setup()
}
// == show initial values from config.txt ========================= //
#if 0
// == check the radio chip by setting default frequency =========== //
if (rs41.setFrequency(402700000) == 0) {
@ -719,9 +797,6 @@ void setup()
WiFi.onEvent(WiFiEvent);
}
enum MainState { ST_DECODER, ST_SCANNER, ST_SPECTRUM, ST_WIFISCAN };
static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN;
void enterMode(int mode) {
mainState = (MainState)mode;
if(mainState == ST_SPECTRUM) {
@ -829,9 +904,9 @@ void loopSpectrum() {
u8x8->drawString(13, 1, buf);
}
if (sonde.config.timer) {
int remaining = sonde.config.spectrum - (millis() - specTimer)/1000;
int remaining = sonde.config.spectrum - (millis() - specTimer) / 1000;
itoa(remaining, buf, 10);
Serial.printf("timer:%d config.spectrum:%d specTimer:%ld millis:%ld remaining:%d\n",sonde.config.timer, sonde.config.spectrum, specTimer, millis(), remaining);
Serial.printf("timer:%d config.spectrum:%d specTimer:%ld millis:%ld remaining:%d\n", sonde.config.timer, sonde.config.spectrum, specTimer, millis(), remaining);
if (sonde.config.marker != 0) {
marker = 1;
}
@ -870,10 +945,13 @@ String translateEncryptionType(wifi_auth_mode_t encryptionType) {
void enableNetwork(bool enable) {
if (enable) {
MDNS.begin("rdzsonde");
SetupAsyncServer();
udp.begin(WiFi.localIP(), LOCALUDPPORT);
MDNS.addService("http", "tcp", 80);
connected = true;
} else {
MDNS.end();
connected = false;
}
}
@ -1138,12 +1216,12 @@ void loopWifiScan() {
if (curidx >= 0 && index == -1) {
index = curidx;
Serial.printf("Match found at scan entry %d, config network %d\n", i, index);
}
}
}
if (index >= 0) { // some network was found
Serial.print("Connecting to: "); Serial.print(fetchWifiSSID(index));
Serial.print(" with password "); Serial.println(fetchWifiPw(index));
u8x8->drawString(0, 6, "Conn:");
u8x8->drawString(6, 6, fetchWifiSSID(index));
WiFi.begin(fetchWifiSSID(index), fetchWifiPw(index));
@ -1184,7 +1262,7 @@ void loopWifiScan() {
wifi_state = WIFI_CONNECTED;
delay(3000);
}
SetupAsyncServer();
enableNetwork(true);
initialMode();
if (sonde.config.spectrum != 0) { // enable Spectrum in config.txt: spectrum=number_of_seconds
@ -1195,6 +1273,177 @@ void loopWifiScan() {
}
}
/// Testing OTA Updates
/// somewhat based on Arduino's AWS_S3_OTA_Update
// Utility to extract header value from headers
String getHeaderValue(String header, String headerName) {
return header.substring(strlen(headerName.c_str()));
}
// OTA Logic
void execOTA() {
int contentLength = 0;
bool isValidContentType = false;
sonde.clearDisplay();
u8x8->setFont(u8x8_font_chroma48medium8_r);
u8x8->drawString(0, 0, "C:");
String dispHost = updateHost.substring(0,14);
u8x8->drawString(2, 0, dispHost.c_str());
Serial.println("Connecting to: " + updateHost);
// Connect to Update host
if (client.connect(updateHost.c_str(), updatePort)) {
// Connection succeeded, fecthing the bin
Serial.println("Fetching bin: " + String(*updateBin));
u8x8->drawString(0, 1, "Fetching update");
// Get the contents of the bin file
client.print(String("GET ") + *updateBin + " HTTP/1.1\r\n" +
"Host: " + updateHost + "\r\n" +
"Cache-Control: no-cache\r\n" +
"Connection: close\r\n\r\n");
// Check what is being sent
// Serial.print(String("GET ") + bin + " HTTP/1.1\r\n" +
// "Host: " + host + "\r\n" +
// "Cache-Control: no-cache\r\n" +
// "Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("Client Timeout !");
client.stop();
return;
}
}
// Once the response is available,
// check stuff
/*
Response Structure
HTTP/1.1 200 OK
x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0=
x-amz-request-id: 2D56B47560B764EC
Date: Wed, 14 Jun 2017 03:33:59 GMT
Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT
ETag: "d2afebbaaebc38cd669ce36727152af9"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 357280
Server: AmazonS3
{{BIN FILE CONTENTS}}
*/
while (client.available()) {
// read line till /n
String line = client.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();
// if the the line is empty,
// this is end of headers
// break the while and feed the
// remaining `client` to the
// Update.writeStream();
if (!line.length()) {
//headers ended
break; // and get the OTA started
}
// Check if the HTTP Response is 200
// else break and Exit Update
if (line.startsWith("HTTP/1.1")) {
if (line.indexOf("200") < 0) {
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
break;
}
}
// extract headers here
// Start with content length
if (line.startsWith("Content-Length: ")) {
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
// Next, the content type
if (line.startsWith("Content-Type: ")) {
String contentType = getHeaderValue(line, "Content-Type: ");
Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream") {
isValidContentType = true;
}
}
}
} else {
// Connect to updateHost failed
// May be try?
// Probably a choppy network?
Serial.println("Connection to " + String(updateHost) + " failed. Please check your setup");
// retry??
// execOTA();
}
// Check what is the contentLength and if content type is `application/octet-stream`
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
u8x8->drawString(0, 2, "Len: ");
String cls = String(contentLength);
u8x8->drawString(5, 2, cls.c_str());
// check contentLength and content type
if (contentLength && isValidContentType) {
// Check if there is enough to OTA Update
bool canBegin = Update.begin(contentLength);
u8x8->drawString(0, 4, "Starting update");
// If yes, begin
if (canBegin) {
Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
// No activity would appear on the Serial monitor
// So be patient. This may take 2 - 5mins to complete
u8x8->drawString(0, 5, "Please wait!");
size_t written = Update.writeStream(client);
if (written == contentLength) {
Serial.println("Written : " + String(written) + " successfully");
} else {
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?" );
// retry??
// execOTA();
}
if (Update.end()) {
Serial.println("OTA done!");
if (Update.isFinished()) {
Serial.println("Update successfully completed. Rebooting.");
u8x8->drawString(0, 7, "Rebooting....");
delay(1000);
ESP.restart();
} else {
Serial.println("Update not finished? Something went wrong!");
}
} else {
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
}
} else {
// not enough space to begin OTA
// Understand the partitions and
// space availability
Serial.println("Not enough space to begin OTA");
client.flush();
}
} else {
Serial.println("There was no content in the response");
client.flush();
}
// Back to some normal state
enterMode(ST_DECODER);
}
void loop() {
Serial.print("Running main loop. free heap:");
Serial.println(ESP.getFreeHeap());
@ -1203,6 +1452,7 @@ void loop() {
case ST_SCANNER: loopScanner(); break;
case ST_SPECTRUM: loopSpectrum(); break;
case ST_WIFISCAN: loopWifiScan(); break;
case ST_UPDATE: execOTA(); break;
}
#if 1
int rssi = sx1278.getRSSI();

Wyświetl plik

@ -15,7 +15,7 @@ oled_rst=16
# General config settings
#-------------------------------#
maxsonde=20
debug=0
debug=1
# wifi mode: 1=client in background; 2=AP in background; 3=client on startup, ap if failure
wifi=3
#-------------------------------#

Wyświetl plik

@ -1,2 +1,2 @@
const char *version_name = "RDZ_TTGO_SONDE";
const char *version_id = "master v0.6a";
const char *version_id = "master v0.6b";

Wyświetl plik

@ -197,7 +197,7 @@ void Sonde::addSonde(float frequency, SondeType type, int active, char *launchsi
sondeList[nSonde].type = type;
sondeList[nSonde].freq = frequency;
sondeList[nSonde].active = active;
sondeList[nSonde].launchsite = launchsite;
strncpy(sondeList[nSonde].launchsite, launchsite, 17);
memcpy(sondeList[nSonde].rxStat, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", 18); // unknown/undefined
nSonde++;
}
@ -334,8 +334,8 @@ void Sonde::updateDisplayScanner() {
u8x8->drawString(8, 0, sondeTypeStr[si()->type]);
snprintf(buf, 16, "%3.3f MHz", si()->freq);
u8x8->drawString(0,3, buf);
//snprintf(buf, 8, "%s", si()->launchsite);
//u8x8->drawString(0,5, buf);
snprintf(buf, 16, "%s", si()->launchsite);
u8x8->drawString(0,5, buf);
updateDisplayIP();
}

Wyświetl plik

@ -43,7 +43,7 @@ typedef struct st_sondeinfo {
// decoded ID
char id[10];
bool validID;
char *launchsite;
char launchsite[18];
// decoded position
float lat; // latitude
float lon; // longitude