This commit is contained in:
Klaus K Wilting committed 2018-08-12 00:17:57 +02:00
1 parent 475a38999a
commit 5099d25965
11 files changed
+648 -9

No files matched your search

+225
View File
@@ -0,0 +1,225 @@
/*
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <WiFiClientSecure.h>
#include <Update.h>
#include <BintrayClient.h>
#include "SecureOTA.h"
const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE);
// Connection port (HTTPS)
const int port = 443;
// Connection timeout
const uint32_t RESPONSE_TIMEOUT_MS = 5000;
// Variables to validate firmware content
volatile int contentLength = 0;
volatile bool isValidContentType = false;
void checkFirmwareUpdates()
{
// Fetch the latest firmware version
const String latest = bintray.getLatestVersion();
if (latest.length() == 0)
{
Serial.println("Could not load info about the latest firmware, so nothing to update. Continue ...");
return;
}
else if (atoi(latest.c_str()) <= VERSION)
{
//Serial.println("The current firmware is up to date. Continue ...");
return;
}
Serial.println("There is a new version of firmware available: v." + latest);
processOTAUpdate(latest);
}
// A helper function to extract header value from header
inline String getHeaderValue(String header, String headerName)
{
return header.substring(strlen(headerName.c_str()));
}
/**
* OTA update processing
*/
void processOTAUpdate(const String &version)
{
String firmwarePath = bintray.getBinaryPath(version);
if (!firmwarePath.endsWith(".bin"))
{
Serial.println("Unsupported binary format. OTA update cannot be performed!");
return;
}
String currentHost = bintray.getStorageHost();
String prevHost = currentHost;
WiFiClientSecure client;
client.setCACert(bintray.getCertificate(currentHost));
if (!client.connect(currentHost.c_str(), port))
{
Serial.println("Cannot connect to " + currentHost);
return;
}
bool redirect = true;
while (redirect)
{
if (currentHost != prevHost)
{
client.stop();
client.setCACert(bintray.getCertificate(currentHost));
if (!client.connect(currentHost.c_str(), port))
{
Serial.println("Redirect detected! Cannot connect to " + currentHost + " for some reason!");
return;
}
}
//Serial.println("Requesting: " + firmwarePath);
client.print(String("GET ") + firmwarePath + " HTTP/1.1\r\n");
client.print(String("Host: ") + currentHost + "\r\n");
client.print("Cache-Control: no-cache\r\n");
client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0)
{
if (millis() - timeout > RESPONSE_TIMEOUT_MS)
{
Serial.println("Client Timeout !");
client.stop();
return;
}
}
while (client.available())
{
String line = client.readStringUntil('\n');
// Check if the line is end of headers by removing space symbol
line.trim();
// if the the line is empty, this is the end of the headers
if (!line.length())
{
break; // proceed to OTA update
}
// Check allowed HTTP responses
if (line.startsWith("HTTP/1.1"))
{
if (line.indexOf("200") > 0)
{
//Serial.println("Got 200 status code from server. Proceeding to firmware flashing");
redirect = false;
}
else if (line.indexOf("302") > 0)
{
//Serial.println("Got 302 status code from server. Redirecting to the new address");
redirect = true;
}
else
{
//Serial.println("Could not get a valid firmware url");
//Unexptected HTTP response. Retry or skip update?
redirect = false;
}
}
// Extracting new redirect location
if (line.startsWith("Location: "))
{
String newUrl = getHeaderValue(line, "Location: ");
//Serial.println("Got new url: " + newUrl);
newUrl.remove(0, newUrl.indexOf("//") + 2);
currentHost = newUrl.substring(0, newUrl.indexOf('/'));
newUrl.remove(newUrl.indexOf(currentHost), currentHost.length());
firmwarePath = newUrl;
//Serial.println("firmwarePath: " + firmwarePath);
continue;
}
// Checking headers
if (line.startsWith("Content-Length: "))
{
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
if (line.startsWith("Content-Type: "))
{
String contentType = getHeaderValue(line, "Content-Type: ");
//Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream")
{
isValidContentType = true;
}
}
}
}
// check whether we have everything for OTA update
if (contentLength && isValidContentType)
{
if (Update.begin(contentLength))
{
Serial.println("Starting Over-The-Air update. This may take some time to complete ...");
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??
}
if (Update.end())
{
if (Update.isFinished())
{
Serial.println("OTA update has successfully completed. Rebooting ...");
ESP.restart();
}
else
{
Serial.println("Something went wrong! OTA update hasn't been finished properly.");
}
}
else
{
Serial.println("An error Occurred. Error #: " + String(Update.getError()));
}
}
else
{
Serial.println("There isn't enough space to start OTA update");
client.flush();
}
}
else
{
Serial.println("There was no valid content in the response from the OTA server!");
client.flush();
}
}
+25
View File
@@ -0,0 +1,25 @@
/*
Copyright (c) 2014-present PlatformIO <contact@platformio.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef SECURE_OTA_H
#define SECURE_OTA_H
#include <Arduino.h>
void checkFirmwareUpdates();
void processOTAUpdate(const String &version);
#endif // SECURE_OTA_H
+1
View File
@@ -52,6 +52,7 @@ extern portMUX_TYPE timerMux;
extern volatile int SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ,
ChannelTimerIRQ, ButtonPressedIRQ;
extern QueueHandle_t LoraSendQueue, SPISendQueue;
extern TaskHandle_t WifiLoopTask;
extern std::array<uint64_t, 0xff>::iterator it;
extern std::array<uint64_t, 0xff> beacons;
+3 -1
View File
@@ -41,6 +41,8 @@ hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL,
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
TaskHandle_t WifiLoopTask = NULL;
// RTos send queues for payload transmit
#ifdef HAS_LORA
QueueHandle_t LoraSendQueue;
@@ -298,7 +300,7 @@ void setup() {
// gets it's seed from RF noise
reset_salt(); // get new 16bit for salting hashes
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
NULL, 0);
&WifiLoopTask, 0);
} // setup()
/* end Arduino SETUP
+26 -3
View File
@@ -138,7 +138,7 @@ void set_loraadr(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s",
val[0] ? "on" : "off");
cfg.adrmode = val[0] ? 1 : 0;
LMIC_setAdrMode(cfg.adrmode);
LMIC_setAdrMode(cfg.adrmode);
#else
ESP_LOGW(TAG, "Remote command: LoRa not implemented");
#endif // HAS_LORA
@@ -219,6 +219,29 @@ void get_gps(uint8_t val[]) {
#endif
};
void set_update(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get firmware update");
ESP_LOGI(TAG, "Stopping Wifi task on core 0");
vTaskDelete(WifiLoopTask);
ESP_LOGI(TAG, "Connecting to %s", WIFI_SSID);
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false)); // switch off monitor mode
//tcpipInit();
tcpip_adapter_init();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
ESP_LOGI(TAG, ".");
delay(500);
}
ESP_LOGI(TAG, "connected!");
checkFirmwareUpdates();
};
// assign previously defined functions to set of numeric remote commands
// format: opcode, function, #bytes params,
// flag (1 = do make settings persistent / 0 = don't)
@@ -233,8 +256,8 @@ cmd_t table[] = {
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
{0x80, get_config, 0, false}, {0x81, get_status, 0, false},
{0x84, get_gps, 0, false}};
{0x20, set_update, 0, false}, {0x80, get_config, 0, false},
{0x81, get_status, 0, false}, {0x84, get_gps, 0, false}};
const uint8_t cmdtablesize =
sizeof(table) / sizeof(table[0]); // number of commands in command table
+3
View File
@@ -6,6 +6,9 @@
#include "lorawan.h"
#include "macsniff.h"
#include <WiFi.h>
#include "SecureOTA.h"
// table of remote commands and assigned functions
typedef struct {
const uint8_t opcode;