OTA Solution - Build your own OTA platform (2/2, ESP32 OTA Application)

This commit is contained in:
Eric
2021-07-31 14:41:35 -07:00
parent 5c79489642
commit d5ebb9a165
16 changed files with 940 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
#include "ButtonCont.h"
#define RIGHT_BUTTON_PIN 35
static ButtonCont* instance = NULL;
void released(Button2& btn) {
instance->released_cb();
}
ButtonCont::ButtonCont() {}
ButtonCont::ButtonCont(FuncPtrVoid f) {
instance = this;
button = new Button2(RIGHT_BUTTON_PIN);
button->setReleasedHandler(released);
released_cb = f;
}
ButtonCont::~ButtonCont() {
delete button;
}
void ButtonCont::loop() {
button->loop();
}

View File

@@ -0,0 +1,16 @@
#include "Button2.h"
class ButtonCont {
private:
Button2* button;
friend void receiveCallback(Button2& btn);
typedef void (*FuncPtrVoid)(void);
public:
FuncPtrVoid released_cb;
ButtonCont(FuncPtrVoid f);
ButtonCont();
~ButtonCont();
void loop();
void eventTrigger();
};

View File

@@ -0,0 +1,138 @@
#include "Display.h"
Display::Display() {
tft = new TFT_eSPI();
}
Display::~Display() {
delete tft;
}
void Display::initTFT() {
tft->init();
tft->fillScreen(TFT_BLACK);
tft->setRotation(1);
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setTextDatum(MC_DATUM);
tft->setFreeFont(&Orbitron_Light_24);
tft->drawString("Waiting for WIFI-", tft->width() / 2, 50);
}
void Display::fillBlackScreen() {
tft->fillScreen(TFT_BLACK);
}
void Display::showVersion(int buildNum) {
String text = "Build#: ";
text += buildNum;
tft->drawString(text, tft->width() / 2, 80);
}
void Display::timeUpdate(String date, String time) {
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setTextDatum(MC_DATUM);
//tft->setFreeFont(&Orbitron_Light_24);
tft->setFreeFont(&Satisfy_24);
tft->setTextPadding(0);
tft->drawString(date, tft->width() / 2, 50);
tft->setTextPadding(tft->width() - 20);
tft->drawString(time, tft->width() / 2, 80);
}
void Display::showVersionBelow(int buildNum) {
tft->setFreeFont(&FreeSansBold9pt7b);
tft->setTextColor(TFT_YELLOW, TFT_BLACK);
tft->setTextDatum(BL_DATUM);
String text = "Current Build#: ";
text += buildNum;
tft->drawString(text, 0, tft->height());
}
void Display::newMessage(String msg) {
tft->setFreeFont(&FreeSansBold9pt7b);
tft->setTextColor(TFT_GREEN, TFT_BLACK);
tft->setTextDatum(TR_DATUM);
tft->drawString(msg, tft->width(), 0);
}
void Display::downloadScreen(int percent) {
if (percent == 0) {
this->fillBlackScreen();
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setFreeFont(&Orbitron_Light_24);
tft->setTextDatum(MC_DATUM);
tft->drawString("Downloading...", tft->width() / 2, 50);
}
this->drawProgressBar(20, tft->height() / 2 + 20, tft->width() - 40, 20, percent, TFT_RED, TFT_YELLOW);
}
void Display::drawProgressBar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t percent, uint16_t frameColor, uint16_t barColor) {
if (percent == 0) {
tft->fillRoundRect(x, y, w, h, 3, TFT_BLACK);
}
uint8_t margin = 2;
uint16_t barHeight = h - 2 * margin;
uint16_t barWidth = w - 2 * margin;
tft->drawRoundRect(x, y, w, h, 3, frameColor);
tft->fillRect(x + margin, y + margin, barWidth * percent / 100.0, barHeight, barColor);
}
void Display::downloadFailure(String cpName) {
this->fillBlackScreen();
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setFreeFont(&Orbitron_Light_24);
tft->setTextDatum(MC_DATUM);
tft->drawString("MD5 checksum", tft->width() / 2, 10);
tft->drawString("Wrong!", tft->width() / 2, 40);
tft->drawString("Contact to ", tft->width() / 2, 70);
tft->drawString(cpName, tft->width() / 2, 100);
}
void Display::downloadSuccess() {
this->fillBlackScreen();
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setFreeFont(&Orbitron_Light_24);
tft->setTextDatum(MC_DATUM);
tft->drawString("MD5 checksum", tft->width() / 2, 10);
tft->drawString("Correct!", tft->width() / 2, 40);
tft->drawString("Countdown", tft->width() / 2, 70);
tft->setTextColor(TFT_RED, TFT_BLACK);
tft->setTextPadding(tft->width() - 20);
for (int i = 3; i > -1; --i) {
tft->drawString(String(i), tft->width() / 2, 100);
delay(1000);
}
}
void Display::firmwareScreen(bool isStart, bool isDone) {
this->fillBlackScreen();
tft->setTextColor(TFT_WHITE, TFT_BLACK);
tft->setFreeFont(&Orbitron_Light_24);
tft->setTextDatum(MC_DATUM);
if (isStart) {
tft->drawString("Updating", tft->width() / 2, 40);
tft->drawString("Firmware!", tft->width() / 2, 70);
return;
}
if (isDone) {
tft->drawString("OTA Done!", tft->width() / 2, 10);
tft->drawString("Rebooting", tft->width() / 2, 40);
tft->drawString("Countdown", tft->width() / 2, 70);
} else {
tft->drawString("Sorry.", tft->width() / 2, 10);
tft->drawString("OTA Failure!", tft->width() / 2, 40);
tft->drawString("Try it again.", tft->width() / 2, 70);
}
tft->setTextColor(TFT_RED, TFT_BLACK);
tft->setTextPadding(tft->width() - 20);
for (int i = 3; i > -1; --i) {
tft->drawString(String(i), tft->width() / 2, 100);
delay(1000);
}
}

View File

@@ -0,0 +1,21 @@
#include <TFT_eSPI.h>
class Display {
private:
TFT_eSPI* tft;
void drawProgressBar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t percent, uint16_t frameColor, uint16_t barColor);
public:
Display();
~Display();
void initTFT();
void showVersion(int buildNum);
void showVersionBelow(int buildNum);
void fillBlackScreen();
void timeUpdate(String date, String time);
void newMessage(String msg);
void downloadScreen(int percent);
void downloadFailure(String cpName);
void downloadSuccess();
void firmwareScreen(bool isStart, bool isDone);
};

View File

@@ -0,0 +1,117 @@
#include "FileIO.h"
FileIO::FileIO() {
if (!SPIFFS.begin()) {
//if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS initialisation failed!");
while (1) yield();
}
}
void FileIO::format() {
Serial.println("SPIFFS Format!");
SPIFFS.format();
}
void FileIO::listSPIFFS() {
Serial.println(F("\r\nListing SPIFFS files:"));
static const char line[] PROGMEM = "=================================================";
Serial.println(FPSTR(line));
Serial.println(F(" File name Size"));
Serial.println(FPSTR(line));
fs::File root = SPIFFS.open("/");
if (!root) {
Serial.println(F("Failed to open directory"));
return;
}
if (!root.isDirectory()) {
Serial.println(F("Not a directory"));
return;
}
fs::File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print("DIR : ");
String fileName = file.name();
Serial.print(fileName);
} else {
String fileName = file.name();
Serial.print(" " + fileName);
// File path can be 31 characters maximum in SPIFFS
int spaces = 33 - fileName.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
String fileSize = (String)file.size();
spaces = 10 - fileSize.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
Serial.println(fileSize + " bytes");
}
file = root.openNextFile();
}
Serial.println(FPSTR(line));
Serial.println();
}
fs::File FileIO::openFile(String fileName, bool isReadOnly) {
if (isReadOnly) {
return SPIFFS.open(fileName, "r");
} else {
this->removeFile(fileName);
return SPIFFS.open(fileName, "w");
}
}
void FileIO::closeFile(fs::File file) {
file.close();
}
void FileIO::removeFile(String fileName) {
if (SPIFFS.exists(fileName)) {
SPIFFS.remove(fileName);
}
}
int FileIO::getFileSize(String fileName) {
fs::File file = SPIFFS.open(fileName, "r");
if (!file) {
return 0;
}
int fileSize = file.size();
file.close();
return fileSize;
}
void FileIO::mdContextInit() {
mbedtls_md_type_t md_type = MBEDTLS_MD_MD5;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
mbedtls_md_starts(&ctx);
}
void FileIO::mdContextUpdate(const unsigned char* buff, int c) {
mbedtls_md_update(&ctx, buff, c);
}
String FileIO::md5Result() {
byte md5Result[16];
mbedtls_md_finish(&ctx, md5Result);
mbedtls_md_free(&ctx);
String checksum = "";
for (int i = 0; i < sizeof(md5Result); i++) {
char str[3];
sprintf(str, "%02x", (int)md5Result[i]);
checksum += str;
}
return checksum;
}

View File

@@ -0,0 +1,23 @@
#ifndef FileIO_H_
#define FileIO_H_
#include "SPIFFS.h"
#include "mbedtls/md.h"
class FileIO {
private:
mbedtls_md_context_t ctx;
public:
static constexpr const char* TEMP_BIN_FILE = "/download_firmware.bin";
FileIO();
void format();
void listSPIFFS();
fs::File openFile(String fileName, bool isReadOnly);
void closeFile(fs::File file);
void removeFile(String fileName);
int getFileSize(String fileName);
void mdContextInit();
void mdContextUpdate(const unsigned char* buff, int c);
String md5Result();
};
#endif

View File

@@ -0,0 +1,16 @@
#ifndef MyFirmware_H_
#define MyFirmware_H_
#include <Arduino.h>
struct firmware_t {
String company;
int build_num;
String build_date;
String server_file_path;
int file_size;
String md5_checksum;
};
typedef struct firmware_t Firmware;
#endif

View File

@@ -0,0 +1,168 @@
#include "Network.h"
#include <WiFi.h>
#define WIFI_SSID "ThatProject"
#define WIFI_PASS "California"
#define BASE_URL "http://192.168.0.2:9001/api"
const String API_KEY = "THIS_IS_MY_OWN_API_KEY";
Network::Network() {
localServerTime = 0;
}
void Network::WiFiBegin() {
WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
}
void Network::fetchLocalServerTime() {
if ((WiFi.status() == WL_CONNECTED)) {
String targetURL = BASE_URL;
targetURL += "/get/time";
http.begin(targetURL);
if (http.GET() == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String time = doc["timestamp"];
Serial.println(time);
Serial.println(time.toInt());
localServerTime = time.toInt();
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
}
long Network::getLocalServerTime() {
return localServerTime;
}
Firmware Network::checkVersion() {
Firmware firmware;
firmware.build_num = -1;
if ((WiFi.status() == WL_CONNECTED)) {
String targetURL = BASE_URL;
targetURL += "/get/version";
http.begin(targetURL);
if (http.GET() == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return firmware;
}
firmware.company = doc["companyName"].as<String>();
firmware.build_num = doc["buildNum"];
firmware.build_date = doc["buildDate"].as<String>();
firmware.server_file_path = doc["serverFilePath"].as<String>();
firmware.file_size = doc["fileSize"];
firmware.md5_checksum = doc["md5Checksum"].as<String>();
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
return firmware;
}
String Network::fileDownload(FuncPtrInt callback, FileIO** fileIO, String target_path) {
String md5CheckSum = "wrong";
if ((WiFi.status() == WL_CONNECTED)) {
fs::File file = (*fileIO)->openFile(FileIO::TEMP_BIN_FILE, false);
String targetURL = BASE_URL;
targetURL += "/post/update";
http.begin(targetURL);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
String httpRequestData = "api_key=" + API_KEY + "&target_path=" + target_path;
if (file && http.POST(httpRequestData) == HTTP_CODE_OK) {
callback(0);
(*fileIO)->mdContextInit();
int fileSize = http.getSize();
Serial.print("File Length: ");
Serial.println(fileSize);
int unDownloadSize = fileSize;
int downloadSize = 0;
int preDownloadedPercent = 0;
uint8_t buff[128] = { 0 };
WiFiClient* stream = http.getStreamPtr();
while (http.connected() && (fileSize > 0 || fileSize == -1)) {
size_t size = stream->available();
if (size) {
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
file.write(buff, c);
(*fileIO)->mdContextUpdate(buff, c);
if (fileSize > 0) fileSize -= c;
downloadSize += c;
int downloadedPercent = int((downloadSize * 100 / unDownloadSize));
if (preDownloadedPercent != downloadedPercent) {
callback(downloadedPercent);
preDownloadedPercent = downloadedPercent;
}
}
delay(1);
}
Serial.println();
Serial.print("[HTTP] connection closed or file end.\n");
(*fileIO)->closeFile(file);
(*fileIO)->listSPIFFS();
Serial.println("======MD5 CHECKSUM");
md5CheckSum = (*fileIO)->md5Result();
Serial.println(md5CheckSum);
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
return md5CheckSum;
}

View File

@@ -0,0 +1,21 @@
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include "FileIO.h"
#include "MyFirmware.h"
class Network {
private:
HTTPClient http;
StaticJsonDocument<300> doc;
long localServerTime;
typedef void (*FuncPtrInt)(int);
public:
Network();
void WiFiBegin();
void fetchLocalServerTime();
long getLocalServerTime();
Firmware checkVersion();
String fileDownload(FuncPtrInt callback, FileIO** fileIO, String target_path);
};

View File

@@ -0,0 +1,174 @@
#include <Arduino.h>
#include "SimpleOTA.h"
static SimpleOTA *instance = NULL;
SimpleOTA::SimpleOTA() {
t1 = 0;
t2 = 0;
currentState = NONE;
instance = this;
}
SimpleOTA::~SimpleOTA() {
}
void buttonCallbackEvent() {
Serial.println("buttonCallbackEvent");
if (instance->currentState == SERVER_FOUND && instance->version->hasNewUpdate()) {
instance->startDownload();
}
}
void networkDownloadEvent(int percent) {
Serial.print("networkDownloadEvent downloadPercent: ");
if (percent == 0) {
instance->currentState = FIRMWARE_DOWNLOAD_START;
}
Serial.println(percent);
instance->display->downloadScreen(percent);
}
void SimpleOTA::begin() {
this->initDisplay();
this->initVersion();
this->initNetwork();
this->initFileIO();
this->initButton();
}
void SimpleOTA::loop() {
switch (currentState) {
case NETWORK_CONNECTED:
if (millis() - t1 >= 1000) {
t1 = millis();
this->requestLocalServerTime();
}
break;
case SERVER_FOUND:
if (millis() - t1 >= 1000) {
t1 = millis();
this->updateTime();
display->showVersionBelow(version->getCurrentVersion());
}
if (millis() - t2 >= 1000 * 10) {
t2 = millis();
this->serverFirmwareCheck();
}
break;
default: break;
}
buttonCont->loop();
}
void SimpleOTA::initDisplay() {
Serial.println("initDisplay");
display = new Display();
display->initTFT();
}
void SimpleOTA::initVersion() {
Serial.println("initVersion");
version = new VersionCont();
display->showVersion(version->getCurrentVersion());
}
void SimpleOTA::initNetwork() {
Serial.println("initNetwork");
network = new Network();
currentState = NETWORK_BEGIN;
network->WiFiBegin();
currentState = NETWORK_CONNECTED;
this->requestLocalServerTime();
}
void SimpleOTA::initFileIO() {
Serial.println("initFileIO");
fileIO = new FileIO();
//fileIO->format();
fileIO->listSPIFFS();
}
void SimpleOTA::initButton() {
Serial.println("initButton");
void (*ptr)(void) = &buttonCallbackEvent;
buttonCont = new ButtonCont(ptr);
}
void SimpleOTA::requestLocalServerTime() {
network->fetchLocalServerTime();
if (network->getLocalServerTime() != 0) {
rtc.setTime(network->getLocalServerTime());
display->fillBlackScreen();
currentState = SERVER_FOUND;
}
}
void SimpleOTA::updateTime() {
struct tm timeinfo = rtc.getTimeStruct();
display->timeUpdate(rtc.getDate(), rtc.getTime());
}
void SimpleOTA::serverFirmwareCheck() {
version->setNewFirmware(network->checkVersion());
if (version->newFirmwareVersion() == -1) {
display->newMessage("Server Not Responding");
} else {
if (version->hasNewUpdate()) {
display->newMessage("New Build Available! ->");
}
}
}
void SimpleOTA::startDownload() {
void (*ptr)(int) = &networkDownloadEvent;
bool compareMD5Checksum = version->md5CompareTo(network->fileDownload(ptr, &fileIO, version->getFirmwareServerPath()));
bool compareFileSize = version->fileSizeCompareTo(fileIO->getFileSize(FileIO::TEMP_BIN_FILE));
Serial.println("======compareMD5Checksum");
Serial.println(compareMD5Checksum);
Serial.println("======Downloaded File SIze");
Serial.println(compareFileSize);
if (compareMD5Checksum && compareFileSize) {
display->downloadSuccess();
this->updateFirmware();
} else {
display->downloadFailure(version->getCPName());
delay(5000);
display->fillBlackScreen();
currentState = SERVER_FOUND;
}
}
void SimpleOTA::updateFirmware() {
currentState = FIRMWARE_DOWNLOAD_START;
display->firmwareScreen(true, false);
Updater *updater = new Updater();
if (updater->updateFromFS(&fileIO)) {
Serial.println("UPDATE DONE");
currentState = FIRMWARE_UPDATED;
version->saveVersion(version->newFirmwareVersion());
display->firmwareScreen(false, true);
ESP.restart();
} else {
Serial.println("UPDATE FAILURE");
display->firmwareScreen(false, false);
delay(3000);
display->fillBlackScreen();
currentState = SERVER_FOUND;
}
delete updater;
}

View File

@@ -0,0 +1,48 @@
#include "Display.h"
#include "VersionCont.h"
#include "Network.h"
#include "ButtonCont.h"
#include "Updater.h"
#include <ESP32Time.h>
typedef enum {
NONE,
NETWORK_BEGIN,
NETWORK_CONNECTED,
SERVER_FOUND,
FIRMWARE_DOWNLOAD_START,
FIRMWARE_UPDATED
} SimpleOTA_State_t;
class SimpleOTA {
private:
Display *display;
VersionCont *version;
Network *network;
FileIO *fileIO;
ButtonCont *buttonCont;
ESP32Time rtc;
long t1, t2;
void initDisplay();
void initVersion();
void initNetwork();
void initFileIO();
void initButton();
void requestLocalServerTime();
void updateTime();
void serverFirmwareCheck();
void startDownload();
void updateFirmware();
friend void buttonCallbackEvent();
friend void networkDownloadEvent(int percent);
SimpleOTA_State_t currentState;
public:
SimpleOTA();
~SimpleOTA();
void begin();
void loop();
};

View File

@@ -0,0 +1,16 @@
#include "SimpleOTA.h"
SimpleOTA *simpleOTA;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
simpleOTA = new SimpleOTA();
simpleOTA->begin();
}
void loop() {
// put your main code here, to run repeatedly:
simpleOTA->loop();
delay(10);
}

View File

@@ -0,0 +1,56 @@
#include "Updater.h"
void Updater::performUpdate(Stream& updateSource, size_t updateSize) {
if (Update.begin(updateSize)) {
size_t written = Update.writeStream(updateSource);
if (written == updateSize) {
Serial.println("Written : " + String(written) + " successfully");
} else {
Serial.println("Written only : " + String(written) + "/" + String(updateSize) + ". Retry?");
}
if (Update.end()) {
Serial.println("OTA done!");
if (Update.isFinished()) {
Serial.println("Update successfully completed. Rebooting.");
} else {
Serial.println("Update not finished? Something went wrong!");
}
} else {
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
}
} else {
Serial.println("Not enough space to begin OTA");
}
}
// check given FS for valid update.bin and perform update if available
bool Updater::updateFromFS(FileIO** fileIO) {
fs::File updateBin = (*fileIO)->openFile(FileIO::TEMP_BIN_FILE, true);
if (updateBin) {
if (updateBin.isDirectory()) {
Serial.println("Error, update.bin is not a file");
return false;
}
bool updateResult = false;
size_t updateSize = updateBin.size();
if (updateSize > 0) {
Serial.println("Try to start update");
this->performUpdate(updateBin, updateSize);
updateResult = true;
} else {
Serial.println("Error, file is empty");
updateResult = false;
}
(*fileIO)->closeFile(updateBin);
(*fileIO)->removeFile(FileIO::TEMP_BIN_FILE);
return updateResult;
} else {
Serial.println("Could not load update.bin from SPIFFS");
return false;
}
}

View File

@@ -0,0 +1,10 @@
#include "FileIO.h"
#include <Update.h>
class Updater {
private:
void performUpdate(Stream& updateSource, size_t updateSize);
public:
bool updateFromFS(FileIO** fileIO);
};

View File

@@ -0,0 +1,70 @@
#include "VersionCont.h"
#include <EEPROM.h>
#define EEPROM_SIZE 1
VersionCont::VersionCont() {
this->loadVersion();
hasNewFirmware = false;
}
int VersionCont::getCurrentVersion() {
return firmwareVersion;
}
void VersionCont::loadVersion() {
EEPROM.begin(EEPROM_SIZE);
firmwareVersion = EEPROM.read(0);
if (firmwareVersion >= 255 || firmwareVersion == 0) {
firmwareVersion = 1;
this->saveVersion(firmwareVersion);
}
}
void VersionCont::saveVersion(int buildNum) {
if (buildNum > 255) buildNum = 255;
EEPROM.write(0, buildNum);
EEPROM.commit();
}
void VersionCont::setNewFirmware(Firmware firmware) {
newFirmware = firmware;
if (newFirmware.build_num != -1) {
Serial.printf("buildNum: %d\n", newFirmware.build_num);
Serial.printf("fileSize: %d\n", newFirmware.file_size);
Serial.printf("MD5Checksum: %s\n", newFirmware.md5_checksum.c_str());
Serial.printf("build_date: %s\n", newFirmware.build_date.c_str());
Serial.printf("company: %s\n", newFirmware.company.c_str());
Serial.printf("server_file_path: %s\n", newFirmware.server_file_path.c_str());
if (firmwareVersion < newFirmware.build_num) {
hasNewFirmware = true;
}
}
}
bool VersionCont::hasNewUpdate() {
return hasNewFirmware;
}
bool VersionCont::md5CompareTo(String checksum) {
return newFirmware.md5_checksum == checksum;
}
bool VersionCont::fileSizeCompareTo(int fileSize) {
return newFirmware.file_size == fileSize;
}
int VersionCont::newFirmwareVersion() {
return newFirmware.build_num;
}
String VersionCont::getCPName() {
return newFirmware.company != NULL ? newFirmware.company : "";
}
String VersionCont::getFirmwareServerPath() {
return newFirmware.server_file_path != NULL ? newFirmware.server_file_path : "";
}

View File

@@ -0,0 +1,21 @@
#include "MyFirmware.h"
class VersionCont {
private:
int firmwareVersion;
void loadVersion();
Firmware newFirmware;
bool hasNewFirmware;
public:
VersionCont();
int getCurrentVersion();
void saveVersion(int buildNum);
void setNewFirmware(Firmware firmware);
bool hasNewUpdate();
bool md5CompareTo(String checksum);
bool fileSizeCompareTo(int fileSize);
int newFirmwareVersion();
String getCPName();
String getFirmwareServerPath();
};