before changing AsyncServer namespace

This commit is contained in:
Miro Zmrzli 2024-05-17 12:14:29 -07:00
parent 33dbf3fc7b
commit b9f10bbd30
17 changed files with 350 additions and 80 deletions

View File

@ -3,4 +3,10 @@
# first device connected
idf.py -DROLE=SENDER build
ret_val=$?
if (($ret_val != 0)); then
exit
fi
cp build/wellhub.bin /var/www/esp_ota

View File

@ -7,9 +7,11 @@
#include "errors.h"
#include "ProvisionSoftAP.h"
#include "OTA.h"
#define LED_PIN 26
App::App()
{
@ -20,21 +22,28 @@ void App::init()
m_led = new Led(LED_PIN);
m_wifi = new Wifi();
bool needs_provision = true;
if(SETTINGS.wifi.num > 0)
{
// try connecting
m_led->setPulse(0, 255, 0);
uint32_t status = m_wifi->connect();
uint32_t status = m_wifi->start();
if(status == WH_OK)
{
m_led->setColor(0, 0, 0);
return;
needs_provision = false;
}
}
m_led->setPulse(0, 0, 255);
ProvisionSoftAP p(80);
p.init("wellhub", "12345678");
if(needs_provision)
{
m_led->setPulse(0, 0, 255);
ProvisionSoftAP provision(80);
provision.start();
}
OTA ota;
ota.start();
}
void App::start()

View File

@ -1,5 +1,5 @@
idf_component_register(SRCS main.cpp App.cpp Settings.cpp Led.cpp TaskFactory.cpp Wifi.cpp utilities.cpp
ProvisionSoftAP.cpp ReaderWriter.cpp
ProvisionSoftAP.cpp ReaderWriter.cpp OTA.cpp
INCLUDE_DIRS "."
EMBED_TXTFILES ../html/logo.png ../html/provision.html
)

View File

@ -58,7 +58,6 @@ void Led::run()
while(true)
{
// vTaskSuspend(NULL);
xQueueReceive(m_queue, &msg, portMAX_DELAY);
if(msg.program == PROGRAM::STEADY)

View File

@ -12,12 +12,9 @@ class Led
struct LED_QUEUE
{
uint8_t program;
struct
{
uint8_t r;
uint8_t g;
uint8_t b;
};
uint8_t r;
uint8_t g;
uint8_t b;
};
public:

225
main/OTA.cpp Normal file
View File

@ -0,0 +1,225 @@
/*
* OTA.cpp
*
* Created on: Apr 23, 2019
* Author: miro
*/
#include "esp_system.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_flash_partitions.h"
#include "esp_partition.h"
#include "string.h"
#include "OTA.h"
#define EXAMPLE_SERVER_URL "http://192.168.1.131/wellhub.bin"
static const char *TAG = "OTA";
#define _FORCE_UPDATE
OTA::OTA()
{
}
void OTA::httpCleanup(esp_http_client_handle_t client)
{
esp_http_client_close(client);
esp_http_client_cleanup(client);
}
void OTA::taskFatalError()
{
ESP_LOGE(TAG, "Exiting task due to fatal error...");
(void) vTaskDelete(NULL);
while (1)
{
;
}
}
void OTA::start()
{
esp_err_t err;
/* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
esp_ota_handle_t update_handle = 0;
const esp_partition_t *update_partition = NULL;
ESP_LOGI(TAG, "Starting OTA check...");
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
if (configured != running)
{
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
configured->address, running->address);
ESP_LOGW(TAG,
"(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
}
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", running->type, running->subtype,
running->address);
esp_http_client_config_t config = { };
config.url = EXAMPLE_SERVER_URL;
esp_http_client_handle_t client = esp_http_client_init(&config);
if (client == NULL)
{
ESP_LOGE(TAG, "Failed to initialize HTTP connection");
}
err = esp_http_client_open(client, 0);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
esp_http_client_cleanup(client);
return;
}
esp_http_client_fetch_headers(client);
update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype,
update_partition->address);
assert(update_partition != NULL);
int binary_file_length = 0;
/*deal with all receive packet*/
bool image_header_was_checked = false;
while (1)
{
int data_read = esp_http_client_read(client, otaWriteData, BUFFSIZE);
if (data_read < 0)
{
ESP_LOGE(TAG, "Error: SSL data read error");
esp_http_client_close(client);
esp_http_client_cleanup(client);
taskFatalError();
}
else if (data_read > 0)
{
printf(".");
if (image_header_was_checked == false)
{
// this is the first 1k of received image
esp_app_desc_t new_app_info;
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t))
{
// check current version with downloading
memcpy(&new_app_info,
&otaWriteData[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)],
sizeof(esp_app_desc_t));
ESP_LOGI(TAG, "New firmware");
ESP_LOGI(TAG, "version: %s", new_app_info.version);
ESP_LOGI(TAG, " name: %s", new_app_info.project_name);
ESP_LOGI(TAG, " c time: %s", new_app_info.time);
ESP_LOGI(TAG, " c date: %s", new_app_info.date);
ESP_LOGI(TAG, "idf ver: %s", new_app_info.idf_ver);
// ESP_LOGI(TAG, " sha: %s", new_app_info.app_elf_sha256);
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "Running firmware");
ESP_LOGI(TAG, "version: %s", running_app_info.version);
ESP_LOGI(TAG, " name: %s", running_app_info.project_name);
ESP_LOGI(TAG, " c time: %s", running_app_info.time);
ESP_LOGI(TAG, " c date: %s", running_app_info.date);
ESP_LOGI(TAG, "idf ver: %s", running_app_info.idf_ver);
// ESP_LOGI(TAG, " sha: %s", running_app_info.app_elf_sha256);
}
const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
esp_app_desc_t invalid_app_info;
if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK)
{
ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
}
// check current version with last invalid partition
if (last_invalid_app != NULL)
{
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version) + sizeof(new_app_info.project_name) + sizeof(new_app_info.time)) == 0)
{
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.",
invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
httpCleanup(client);
return;
}
}
#ifndef FORCE_UPDATE
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version) + sizeof(new_app_info.project_name) + sizeof(new_app_info.time) + sizeof(new_app_info.date)) == 0)
{
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
httpCleanup(client);
return;
}
#endif
image_header_was_checked = true;
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "esp_ota_begin succeeded");
}
else
{
ESP_LOGE(TAG, "received package is not fit len");
httpCleanup(client);
taskFatalError();
}
}
err = esp_ota_write(update_handle, (const void *) otaWriteData, data_read);
if (err != ESP_OK)
{
httpCleanup(client);
taskFatalError();
}
binary_file_length += data_read;
ESP_LOGD(TAG, "Written image length %d", binary_file_length);
}
else if (data_read == 0)
{
ESP_LOGI(TAG, "Connection closed,all data received");
break;
}
}
printf("\n");
ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length);
if (esp_ota_end(update_handle) != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_end failed!");
httpCleanup(client);
taskFatalError();
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "Prepare to restart system!");
esp_restart();
return;
}
OTA::~OTA()
{
}

34
main/OTA.h Normal file
View File

@ -0,0 +1,34 @@
/*
* OTA.h
*
* Created on: Apr 23, 2019
* Author: miro
*/
#ifndef __OTA_H__
#define __OTA_H__
#define BUFFSIZE 1024
#define HASH_LEN 32 /* SHA-256 digest length */
#include "esp_http_client.h"
class OTA
{
public:
void start();
private:
char otaWriteData[BUFFSIZE + 1] = { 0 };
void httpCleanup(esp_http_client_handle_t client);
private:
void taskFatalError();
public:
OTA();
virtual ~OTA();
};
#endif /* __OTA_H__ */

View File

@ -1,10 +1,10 @@
/*
* ProvisionSoftAP.cpp
*
* Created on: Apr 17, 2019
* Modified: 2024
* Author: miro
*/
///
/// © MiroZ 2024
///
/// Created on: Apr 17, 2019
/// Modified: 2024
///
#include <DNSServer.h>
#include "WiFi.h"
#include "Arduino.h"
@ -100,7 +100,7 @@ void ProvisionSoftAP::handleLogo(AsyncWebServerRequest* request)
* ssid[in] ssid of the AP
* password[in] password for the AP
*/
void ProvisionSoftAP::init(const char * ssid, const char * password)
void ProvisionSoftAP::start(const char * ssid, const char * password)
{
// start AP
@ -125,43 +125,14 @@ void ProvisionSoftAP::init(const char * ssid, const char * password)
m_webSocket->onEvent(std::bind(&ProvisionSoftAP::websocketEvent, this, _1, _2, _3, _4, _5, _6));
m_webServer->addHandler(m_webSocket);
m_webServer->on("/", std::bind(&ProvisionSoftAP::handlePortal, this, _1));
m_webServer->on("/provision.html", std::bind(&ProvisionSoftAP::handlePortal, this, _1));
m_webServer->on("/generate_204", std::bind(&ProvisionSoftAP::handlePortal, this, _1)); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
m_webServer->on("/fwlink", std::bind(&ProvisionSoftAP::handlePortal, this, _1)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
// m_webServer->on("/provision.html", std::bind(&ProvisionSoftAP::handlePortal, this, _1));
// m_webServer->on("/generate_204", std::bind(&ProvisionSoftAP::handlePortal, this, _1)); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
// m_webServer->on("/fwlink", std::bind(&ProvisionSoftAP::handlePortal, this, _1)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
m_webServer->on("/logo.png", std::bind(&ProvisionSoftAP::handleLogo, this, _1));
m_webServer->onNotFound(std::bind(&ProvisionSoftAP::handlePortal, this, _1));
m_webServer->begin();
// char buf[64], buf1[32];
// m_rwriter->copyString("command:verify_wifi|ssid:gumball|pwd:12345688");
// ESP_LOGI(TAG, "%d", m_rwriter->elementIs(0, "command:verify_wifi"));
// uint32_t loc = m_rwriter->getNthDelimiter(0);
// if(m_rwriter->hasMore(loc))
// ESP_LOGI(TAG, "%d", loc);
// while(m_rwriter->hasMore(loc))
// {
// loc = m_rwriter->getNextDelimiter(loc);
// ESP_LOGI(TAG, "%d", loc);
// }
// if(m_rwriter->getElementAt(buf, 64, 3))
// ESP_LOGI(TAG, "'%s'", buf);
// bool ret_val = m_rwriter->getAt(buf, 64, 3);
// ESP_LOGI(TAG, "(%d) '%s'", ret_val, buf);
// Parser p(buf, ":");
// while(m_rwriter->getNext(buf, 64))
// {
// p.reset();
// while(p.getNext(buf1, 32))
// ESP_LOGI(TAG, "'%s'", buf1);
// }
while (true)
{
m_dnsServer.processNextRequest();
@ -202,6 +173,16 @@ void ProvisionSoftAP::init(const char * ssid, const char * password)
}
}
void ProvisionSoftAP::start()
{
uint8_t mac[6];
WiFi.macAddress(mac);
char ssid[33];
sprintf(ssid, "Wellhub-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
start(ssid, "12345678");
}
const char verify_wifi[] = "command:verify_wifi";
void ProvisionSoftAP::parseWebsocketCommand(char* data, size_t len)
@ -282,7 +263,7 @@ void ProvisionSoftAP::tryConnect()
SETTINGS.wifi.selected = 0;
SETTINGS.wifi.num = 1;
Settings::getInstance().saveData();
SETTINGS_SAVE;
vTaskDelay(3000 / portTICK_PERIOD_MS);
waitBufferEmpty();

View File

@ -1,12 +1,12 @@
/*
* ProvisionSoftAP.h
*
* Created on: Apr 17, 2019
* Author: miro
*/
///
/// © MiroZ 2024
///
/// Created on: Apr 17, 2019
/// Modified: 2024
///
#ifndef MAIN_PROVISIONSOFTAP_H_
#define MAIN_PROVISIONSOFTAP_H_
#ifndef __PROVISIONSOFTAP_H__
#define __PROVISIONSOFTAP_H__
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
@ -43,10 +43,11 @@ private:
void waitBufferEmpty();
public:
void init(const char * ssid, const char * password);
void start(const char * ssid, const char * password);
void start();
ProvisionSoftAP(int port = 80);
virtual ~ProvisionSoftAP();
};
#endif /* MAIN_PROVISIONSOFTAP_H_ */
#endif /* __PROVISIONSOFTAP_H__ */

View File

@ -70,7 +70,7 @@ struct SETTINGS_LEGACY
uint32_t TEMP_OFFSET;
};
#define SETTINGS_VERSION 3 // cannot be 0
#define SETTINGS_VERSION 2 // cannot be 0
#define SETTINGS_NUM_WIFI_ENTRIES 8
// wifi definitions
@ -126,5 +126,6 @@ public:
};
#define SETTINGS Settings::getInstance().data()
#define SETTINGS_SAVE Settings::getInstance().saveData()
#endif /* __SETTINGS_H__ */

View File

@ -4,27 +4,34 @@
TaskFactory::TaskFactory()
{
#ifdef USE_MUTEX
m_xMutex = xSemaphoreCreateMutex();
assert(m_xMutex);
#endif
}
TaskFactory::~TaskFactory()
{
#ifdef USE_MUTEX
if(m_xMutex != NULL)
vSemaphoreDelete(m_xMutex);
#endif
}
TaskHandle_t TaskFactory::createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core)
{
TaskHandle_t task_handle = nullptr;
#ifdef USE_MUTEX
if (xSemaphoreTake(m_xMutex, portMAX_DELAY))
{
#endif
m_task_function = task_function;
xTaskCreatePinnedToCore(taskStarter, name, stack_size, this, priority, &task_handle, core);
#ifdef USE_MUTEX
xSemaphoreGive(m_xMutex);
}
#endif
return task_handle;
}

View File

@ -12,26 +12,24 @@
typedef std::function<void()> TASK_FUNCTION;
// no need for mutex here
#define _USE_MUTEX
class TaskFactory
{
protected:
#ifdef USE_MUTEX
SemaphoreHandle_t m_xMutex = NULL;
#endif
TASK_FUNCTION m_task_function = nullptr;
protected:
static void taskStarter(void * ptr) {
(static_cast<TaskFactory*>(ptr)->run());
}
void run(){
m_task_function();
}
static void taskStarter(void * ptr) { (static_cast<TaskFactory*>(ptr)->run()); }
void run(){ m_task_function(); }
public:
TaskHandle_t createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core);
static uint32_t getStackHighWaterMark(TaskHandle_t task){
return (uint32_t)uxTaskGetStackHighWaterMark(task);
}
static uint32_t getStackHighWaterMark(TaskHandle_t task){ return (uint32_t)uxTaskGetStackHighWaterMark(task); }
TaskFactory();
~TaskFactory();

View File

@ -84,7 +84,7 @@ uint32_t Wifi::connectTo(int index)
/// @brief Connects to wifi. Returns immediately if already connected.
/// @return WH_OK | WH_ERR_WIFI_NOT_PROVISIONED
uint32_t Wifi::connect()
uint32_t Wifi::start()
{
if(SETTINGS.wifi.num == 0)
{

View File

@ -27,7 +27,7 @@ protected:
void wifi_event(arduino_event_id_t event, arduino_event_info_t info);
public:
uint32_t connect();
uint32_t start();
};
#endif /* __WIFI_H__ */

View File

@ -10,6 +10,8 @@ if (($ret_val != 0)); then
exit
fi
cp build/wellhub.bin /var/www/esp_ota
if [$1 == '']; then
idf.py -p /dev/ttyUSB1 -b 2000000 flash && idf.py -p /dev/ttyUSB1 monitor -B 450000
else

View File

@ -45,7 +45,7 @@ CONFIG_ENABLE_ARDUINO_DEPENDS=y
CONFIG_ARDUINO_RUN_CORE1=y
# CONFIG_ARDUINO_RUN_NO_AFFINITY is not set
CONFIG_ARDUINO_RUNNING_CORE=1
CONFIG_ARDUINO_LOOP_STACK_SIZE=8192
CONFIG_ARDUINO_LOOP_STACK_SIZE=1024
# CONFIG_ARDUINO_EVENT_RUN_CORE0 is not set
CONFIG_ARDUINO_EVENT_RUN_CORE1=y
# CONFIG_ARDUINO_EVENT_RUN_NO_AFFINITY is not set

View File

@ -190,6 +190,16 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
#
# AsyncTCP Configuration
#
# CONFIG_ASYNC_TCP_RUN_CORE0 is not set
CONFIG_ASYNC_TCP_RUN_CORE1=y
# CONFIG_ASYNC_TCP_RUN_NO_AFFINITY is not set
CONFIG_ASYNC_TCP_RUNNING_CORE=1
CONFIG_ASYNC_TCP_USE_WDT=y
# end of AsyncTCP Configuration
#
# Compiler options
#