testing
This commit is contained in:
1 parent
475a38999a
commit
5099d25965
11 files changed
+648
-9
No files matched your search
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user