From 36d30ee0cb05c162377ded84055f1f3f85b8ba14 Mon Sep 17 00:00:00 2001 From: Nic Limper Date: Fri, 28 Apr 2023 14:51:51 +0200 Subject: [PATCH] auto channel select, ap config screen --- ESP32_AP-Flasher/data/www/index.html | 58 +++++++++- ESP32_AP-Flasher/data/www/main.css | 54 +++++++--- ESP32_AP-Flasher/data/www/main.js | 56 +++++++++- ESP32_AP-Flasher/include/commstructs.h | 16 +++ ESP32_AP-Flasher/include/newproto.h | 3 +- ESP32_AP-Flasher/include/serial.h | 3 + ESP32_AP-Flasher/include/tag_db.h | 3 + ESP32_AP-Flasher/include/udp.h | 1 + ESP32_AP-Flasher/include/web.h | 5 +- ESP32_AP-Flasher/platformio.ini | 1 + ESP32_AP-Flasher/src/main.cpp | 21 +++- ESP32_AP-Flasher/src/newproto.cpp | 15 ++- ESP32_AP-Flasher/src/serial.cpp | 16 +-- ESP32_AP-Flasher/src/tag_db.cpp | 28 ++++- ESP32_AP-Flasher/src/udp.cpp | 143 +++++++++++++++++++------ ESP32_AP-Flasher/src/web.cpp | 51 ++++++++- 16 files changed, 400 insertions(+), 74 deletions(-) diff --git a/ESP32_AP-Flasher/data/www/index.html b/ESP32_AP-Flasher/data/www/index.html index 9b70dc31..d2dbafa6 100644 --- a/ESP32_AP-Flasher/data/www/index.html +++ b/ESP32_AP-Flasher/data/www/index.html @@ -47,6 +47,60 @@

+
+
+

Access Point config

+

+ + +

+

+ + +

+

+ +

+ +

+ Active access points:
+ + + + + + + + +
ipaliastagschfw ver
+

+

+ reboot AP + download tagDB +

+

+ Github OpenEPaperLink +

+
+
@@ -55,8 +109,8 @@
Currently active tags:
-
reboot AP
- +
AP config
+
diff --git a/ESP32_AP-Flasher/data/www/main.css b/ESP32_AP-Flasher/data/www/main.css index d24cf8c6..be547bdc 100644 --- a/ESP32_AP-Flasher/data/www/main.css +++ b/ESP32_AP-Flasher/data/www/main.css @@ -64,7 +64,7 @@ label { gap: 20px; } -#rebootbutton { +#rebootbutton, #downloadDBbutton, #apconfigbutton, .filebutton { padding: 2px 5px; background-color: #cccccc; text-decoration: none; @@ -72,13 +72,6 @@ label { cursor: pointer; } -.filebutton { - padding: 2px 5px; - background-color: #cccccc; - text-decoration: none; - color: black; -} - .columns div { flex: 1; } @@ -89,14 +82,14 @@ input[type="text"], input[type="button"], input[type="submit"], button { - -webkit-appearance: none; + appearance: none; border-radius: 0; } input { border: solid 1px #666666; padding: 4px; - -webkit-border-radius: 0px; + border-radius: 0px; } input[type=button] { @@ -109,10 +102,10 @@ input[type=button]:hover { } select { padding: 4px; - -webkit-border-radius: 0px; + border-radius: 0px; } -#configbox { +#configbox, #apconfigbox { display: none; position: fixed; top: 80px; @@ -124,24 +117,53 @@ select { box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63); } -#configbox p { +#configbox p, #apconfigbox p { padding: 5px; } -#configbox h3 { +#configbox h3, #apconfigbox h3 { font-size: 1.5em; font-weight: bold; } -#configbox input { +#configbox input, #apconfigbox input { border: solid 1px #666666; padding: 4px; } -#configbox label { +#configbox label, #apconfigbox label { text-transform: capitalize; } +#apconfigbox { + background-color: #e6f0d3; +} + +#aptable { + width: 100%; + border-spacing: 0; +} + +#aptable th { + text-align: left; + background-color: #00000020; + padding: 0px 3px; +} + +#aptable th, #aptable td { + border-right: 1px solid #000010; + padding: 0px 3px; +} + +#aptable td:nth-child(1), #aptable th:nth-child(1) { + border-left: 1px solid #000010; +} + +#aptable td:nth-child(3), +#aptable td:nth-child(4) { + text-align: right; +} + #cfgdelete { position: absolute; bottom: 15px; diff --git a/ESP32_AP-Flasher/data/www/main.js b/ESP32_AP-Flasher/data/www/main.js index 6cd58191..d350d958 100644 --- a/ESP32_AP-Flasher/data/www/main.js +++ b/ESP32_AP-Flasher/data/www/main.js @@ -34,7 +34,14 @@ let servertimediff = 0; let socket; connect(); setInterval(updatecards, 1000); -window.addEventListener("load", function () { loadTags(0) }); +window.addEventListener("load", function () { + fetch("/get_ap_list") + .then(response => response.json()) + .then(data => { + if (data.alias) $(".logo").innerHTML = data.alias; + }) + loadTags(0) +}); function loadTags(pos) { fetch("/get_db?pos="+pos) @@ -69,6 +76,14 @@ function connect() { $('#sysinfo').innerHTML = 'free heap: ' + msg.sys.heap + ' bytes ┇ db size: ' + msg.sys.dbsize + ' bytes ┇ db record count: ' + msg.sys.recordcount + ' ┇ littlefs free: ' + msg.sys.littlefsfree + ' bytes'; servertimediff = (Date.now() / 1000) - msg.sys.currtime; } + if (msg.apitem) { + var row = $("#aptable").insertRow(); + row.insertCell(0).innerHTML = "" + msg.apitem.ip + ""; + row.insertCell(1).innerHTML = msg.apitem.alias; + row.insertCell(2).innerHTML = msg.apitem.count; + row.insertCell(3).innerHTML = msg.apitem.channel; + row.insertCell(4).innerHTML = msg.apitem.version; + } }); socket.addEventListener("close", (event) => { @@ -208,9 +223,11 @@ $('#clearlog').onclick = function () { $('#messages').innerHTML=''; } -$('.closebtn').onclick = function (event) { - event.target.parentNode.style.display='none'; -} +document.querySelectorAll('.closebtn').forEach(button => { + button.addEventListener('click', (event) => { + event.target.parentNode.style.display = 'none'; + }); +}); $('#taglist').addEventListener("click", (event) => { let currentElement = event.target; @@ -242,7 +259,6 @@ $('#taglist').addEventListener("click", (event) => { }) $('#cfgsave').onclick = function () { - let contentMode = $('#cfgcontent').value; let extraoptions = contentModeOptions[contentMode]; let obj={}; @@ -292,6 +308,36 @@ $('#rebootbutton').onclick = function () { socket.close(); } +$('#apconfigbutton').onclick = function () { + var table = document.getElementById("aptable"); + var rowCount = table.rows.length; + for (var i = rowCount - 1; i > 0; i--) { + table.deleteRow(i); + } + $('#apconfigbox').style.display = 'block' + fetch("/get_ap_list") + .then(response => response.json()) + .then(data => { + $('#apcfgalias').value = data.alias; + $('#apcfgchid').value = data.channel; + }) +} + +$('#apcfgsave').onclick = function () { + let formData = new FormData(); + formData.append("alias", $('#apcfgalias').value); + formData.append("channel", $('#apcfgchid').value); + fetch("/save_apcfg", { + method: "POST", + body: formData + }) + .then(response => response.text()) + .then(data => showMessage(data)) + .catch(error => showMessage('Error: ' + error)); + $(".logo").innerHTML = $('#apcfgalias').value; + $('#apconfigbox').style.display = 'none'; +} + function contentselected() { let contentMode = $('#cfgcontent').value; let extraoptions = contentModeOptions[contentMode]; diff --git a/ESP32_AP-Flasher/include/commstructs.h b/ESP32_AP-Flasher/include/commstructs.h index ac73dd81..a1a15e05 100644 --- a/ESP32_AP-Flasher/include/commstructs.h +++ b/ESP32_AP-Flasher/include/commstructs.h @@ -86,4 +86,20 @@ struct pendingData { #define BLOCK_DATA_SIZE 4096 #define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData) +#define PKT_AVAIL_DATA_REQ 0xE5 +#define PKT_AVAIL_DATA_INFO 0xE6 +#define PKT_XFER_COMPLETE 0xEA +#define PKT_XFER_TIMEOUT 0xED +#define PKT_CANCEL_XFER 0xEC +#define PKT_APLIST_REQ 0x80 +#define PKT_APLIST_REPLY 0x81 + +struct APlist { + uint32_t src; + char alias[32]; + uint8_t channelId; + uint8_t tagCount; + uint16_t version; +} __packed; + #pragma pack(pop) \ No newline at end of file diff --git a/ESP32_AP-Flasher/include/newproto.h b/ESP32_AP-Flasher/include/newproto.h index 4a755815..92f3417f 100644 --- a/ESP32_AP-Flasher/include/newproto.h +++ b/ESP32_AP-Flasher/include/newproto.h @@ -10,4 +10,5 @@ extern void prepareExternalDataAvail(struct pendingData* pending, IPAddress remo extern void processXferComplete(struct espXferComplete* xfc); extern void processXferTimeout(struct espXferComplete* xfc); extern void processDataReq(struct espAvailDataReq* adr); -void refreshAllPending(); \ No newline at end of file +void refreshAllPending(); +void setAPchannel(); diff --git a/ESP32_AP-Flasher/include/serial.h b/ESP32_AP-Flasher/include/serial.h index bc597799..d3911058 100644 --- a/ESP32_AP-Flasher/include/serial.h +++ b/ESP32_AP-Flasher/include/serial.h @@ -1,5 +1,8 @@ #include +extern struct espSetChannelPower curChannel; +extern uint16_t version; + void zbsTx(uint8_t* packetdata, uint8_t len); void zbsRxTask(void* parameter); diff --git a/ESP32_AP-Flasher/include/tag_db.h b/ESP32_AP-Flasher/include/tag_db.h index 83d819bd..eb24ca22 100644 --- a/ESP32_AP-Flasher/include/tag_db.h +++ b/ESP32_AP-Flasher/include/tag_db.h @@ -49,6 +49,7 @@ class tagRecord { }; extern std::vector tagDB; +extern DynamicJsonDocument APconfig; String tagDBtoJson(uint8_t mac[6] = nullptr, uint8_t startPos = 0); bool deleteRecord(uint8_t mac[6]); void fillNode(JsonObject &tag, tagRecord* &taginfo); @@ -56,5 +57,7 @@ void saveDB(String filename); void loadDB(String filename); uint8_t getTagCount(); void clearPending(tagRecord* taginfo); +void initAPconfig(); +void saveAPconfig(); #pragma pack(pop) \ No newline at end of file diff --git a/ESP32_AP-Flasher/include/udp.h b/ESP32_AP-Flasher/include/udp.h index 980a6174..f2a25a08 100644 --- a/ESP32_AP-Flasher/include/udp.h +++ b/ESP32_AP-Flasher/include/udp.h @@ -10,6 +10,7 @@ class UDPcomm { UDPcomm(); ~UDPcomm(); void init(); + void getAPList(); void netProcessDataReq(struct espAvailDataReq* eadr); void netProcessXferComplete(struct espXferComplete* xfc); void netProcessXferTimeout(struct espXferComplete* xfc); diff --git a/ESP32_AP-Flasher/include/web.h b/ESP32_AP-Flasher/include/web.h index 524234df..991d9e13 100644 --- a/ESP32_AP-Flasher/include/web.h +++ b/ESP32_AP-Flasher/include/web.h @@ -1,5 +1,5 @@ -#include +#include #include #include @@ -11,9 +11,10 @@ void wsLog(String text); void wsErr(String text); void wsSendTaginfo(uint8_t mac[6]); void wsSendSysteminfo(); +void wsSendAPitem(struct APlist* apitem); extern uint64_t swap64(uint64_t x); -extern AsyncWebSocket ws; //("/ws"); +extern AsyncWebSocket ws; extern SemaphoreHandle_t wsMutex; extern TaskHandle_t websocketUpdater; \ No newline at end of file diff --git a/ESP32_AP-Flasher/platformio.ini b/ESP32_AP-Flasher/platformio.ini index b87f2863..b7cd9bb3 100644 --- a/ESP32_AP-Flasher/platformio.ini +++ b/ESP32_AP-Flasher/platformio.ini @@ -131,6 +131,7 @@ board = esp32dev board_build.partitions = no_ota.csv build_flags = + -DCORE_DEBUG_LEVEL=0 -D SIMPLE_AP -D FLASHER_AP_SS=5 diff --git a/ESP32_AP-Flasher/src/main.cpp b/ESP32_AP-Flasher/src/main.cpp index 6c8856bd..27e7a984 100644 --- a/ESP32_AP-Flasher/src/main.cpp +++ b/ESP32_AP-Flasher/src/main.cpp @@ -50,12 +50,22 @@ void setup() { Serial.printf("Flash Size %d, Flash Speed %d\n", ESP.getFlashChipSize(), ESP.getFlashChipSpeed()); Serial.println("##################################\n\n"); - Serial.println(ESP.getFreeHeap()); + Serial.printf("Total heap: %d\n", ESP.getHeapSize()); + Serial.printf("Free heap: %d\n", ESP.getFreeHeap()); + Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize()); + Serial.printf("Free PSRAM: %d\n\n", ESP.getFreePsram()); - Serial.printf("Total heap: %d", ESP.getHeapSize()); - Serial.printf("Free heap: %d", ESP.getFreeHeap()); - Serial.printf("Total PSRAM: %d", ESP.getPsramSize()); - Serial.printf("Free PSRAM: %d", ESP.getFreePsram()); + Serial.printf("ESP32 Partition table:\n"); + Serial.printf("| Type | Sub | Offset | Size | Label |\n"); + Serial.printf("| ---- | --- | -------- | -------- | ---------------- |\n"); + esp_partition_iterator_t pi = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + if (pi != NULL) { + do { + const esp_partition_t* p = esp_partition_get(pi); + Serial.printf("| %02x | %02x | 0x%06X | 0x%06X | %-16s |\r\n", + p->type, p->subtype, p->address, p->size, p->label); + } while (pi = (esp_partition_next(pi))); + } #ifdef HAS_USB xTaskCreate(usbFlasherTask, "flasher", 10000, NULL, configMAX_PRIORITIES - 10, NULL); @@ -64,6 +74,7 @@ void setup() { configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "0.nl.pool.ntp.org", "europe.pool.ntp.org", "time.nist.gov"); // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv + initAPconfig(); init_web(); init_udp(); diff --git a/ESP32_AP-Flasher/src/newproto.cpp b/ESP32_AP-Flasher/src/newproto.cpp index cd2c1116..7eb5285c 100644 --- a/ESP32_AP-Flasher/src/newproto.cpp +++ b/ESP32_AP-Flasher/src/newproto.cpp @@ -432,4 +432,17 @@ void refreshAllPending() { wsSendTaginfo(taginfo->mac); } } -}; \ No newline at end of file +}; + +void setAPchannel() { + if (APconfig["channel"].as() == 0) { + // trigger channel autoselect + UDPcomm udpsync; + udpsync.getAPList(); + } else { + if (curChannel.channel != APconfig["channel"].as()) { + curChannel.channel = APconfig["channel"].as(); + if (version) sendChannelPower(&curChannel); + } + } +} diff --git a/ESP32_AP-Flasher/src/serial.cpp b/ESP32_AP-Flasher/src/serial.cpp index 3e53e214..0dd4d74a 100644 --- a/ESP32_AP-Flasher/src/serial.cpp +++ b/ESP32_AP-Flasher/src/serial.cpp @@ -35,6 +35,9 @@ volatile uint8_t cmdReplyValue = CMD_REPLY_WAIT; #define AP_SERIAL_PORT Serial1 +uint8_t channelList[6]; +struct espSetChannelPower curChannel = {0, 11, 8}; + bool txStart() { while (1) { if (xPortInIsrContext()) { @@ -153,9 +156,9 @@ void sendCancelPending(struct pendingData* pending) { AP_SERIAL_PORT.write(((uint8_t*)pending)[c]); } if (waitCmdReply()) goto cxdsent; - AP_SERIAL_PORT.printf("CXD send failed in try %d\n", attempt); + Serial.printf("CXD send failed in try %d\n", attempt); } - AP_SERIAL_PORT.print("CXD failed to send...\n"); + Serial.print("CXD failed to send...\n"); txEnd(); return; cxdsent: @@ -172,9 +175,9 @@ bool sendChannelPower(struct espSetChannelPower* scp) { AP_SERIAL_PORT.write(((uint8_t*)scp)[c]); } if (waitCmdReply()) goto scpSent; - AP_SERIAL_PORT.printf("SCP send failed in try %d\n", attempt); + Serial.printf("SCP send failed in try %d\n", attempt); } - AP_SERIAL_PORT.print("SCP failed to send...\n"); + Serial.print("SCP failed to send...\n"); txEnd(); return false; scpSent: @@ -402,6 +405,8 @@ void zbsRxTask(void* parameter) { vTaskDelay(2 / portTICK_PERIOD_MS); rampTagPower(FLASHER_AP_POWER, true); wsErr("The AP tag crashed. Restarting tag, regenerating all pending info."); + vTaskDelay(3000 / portTICK_PERIOD_MS); + sendChannelPower(&curChannel); refreshAllPending(); } } else { @@ -423,9 +428,8 @@ void zbsRxTask(void* parameter) { } else { Serial.println("Failed to update version on the AP :("); } - } else if (!fsversion) { - Serial.println("No ZBS/Zigbee FW binary found on SPIFFS, please upload a zigbeebase000X.bin - format binary to enable flashing"); } + sendChannelPower(&curChannel); firstrun = false; } } diff --git a/ESP32_AP-Flasher/src/tag_db.cpp b/ESP32_AP-Flasher/src/tag_db.cpp index 58bc96c3..b1fe45ec 100644 --- a/ESP32_AP-Flasher/src/tag_db.cpp +++ b/ESP32_AP-Flasher/src/tag_db.cpp @@ -2,12 +2,13 @@ #include #include - +#include #include #include "LittleFS.h" std::vector tagDB; +DynamicJsonDocument APconfig(150); tagRecord* tagRecord::findByMAC(uint8_t mac[6]) { for (int16_t c = 0; c < tagDB.size(); c++) { @@ -221,3 +222,28 @@ void clearPending(tagRecord* taginfo) { } taginfo->pending = false; } + +void initAPconfig() { + LittleFS.begin(true); + File configFile = LittleFS.open("/current/apconfig.json", "r"); + if (!configFile) { + //default values' + Serial.println("APconfig not found"); + APconfig["channel"] = 0; + APconfig["alias"] = String(); + return; + } + DeserializationError error = deserializeJson(APconfig, configFile); + if (error) { + configFile.close(); + Serial.println("apconfig.json file corrupted, or not enough space in apconfig to hold it"); + return; + } + configFile.close(); +} + +void saveAPconfig() { + fs::File configFile = LittleFS.open("/current/apconfig.json", "w"); + serializeJson(APconfig, configFile); + configFile.close(); +} \ No newline at end of file diff --git a/ESP32_AP-Flasher/src/udp.cpp b/ESP32_AP-Flasher/src/udp.cpp index 8215c0e6..8ec0c4c8 100644 --- a/ESP32_AP-Flasher/src/udp.cpp +++ b/ESP32_AP-Flasher/src/udp.cpp @@ -4,17 +4,18 @@ #include "AsyncUDP.h" #include "commstructs.h" #include "newproto.h" +#include "tag_db.h" +#include "web.h" +#include "serial.h" -#define PKT_AVAIL_DATA_REQ 0xE5 -#define PKT_AVAIL_DATA_INFO 0xE6 -#define PKT_XFER_COMPLETE 0xEA -#define PKT_XFER_TIMEOUT 0xED -#define PKT_CANCEL_XFER 0xEC -#define PKT_ID_APS 0x80 +#define UDPIP IPAddress(239, 10, 0, 1) +#define UDPPORT 16033 UDPcomm udpsync; -uint8_t channelList[6] = {11, 15, 20, 25, 26, 27}; +extern uint8_t channelList[6]; +extern espSetChannelPower curChannel; +extern uint16_t version; void init_udp() { udpsync.init(); @@ -29,63 +30,139 @@ UDPcomm::~UDPcomm() { } void UDPcomm::init() { - if (udp.listenMulticast(IPAddress(239, 10, 0, 1), 16033)) { + if (udp.listenMulticast(UDPIP, UDPPORT)) { udp.onPacket([this](AsyncUDPPacket packet) { - this->processPacket(packet); + if (packet.remoteIP() != WiFi.localIP()) { + this->processPacket(packet); + } }); } + setAPchannel(); } void UDPcomm::processPacket(AsyncUDPPacket packet) { - if (packet.data()[0] == PKT_AVAIL_DATA_INFO) { - espAvailDataReq* adr = (espAvailDataReq*)&packet.data()[1]; - adr->src[7] = 0xFF; - processDataReq(adr); + switch (packet.data()[0]) { + case PKT_AVAIL_DATA_INFO: { + espAvailDataReq* adr = (espAvailDataReq*)&packet.data()[1]; + adr->src[7] = 0xFF; + processDataReq(adr); + break; + } + case PKT_XFER_COMPLETE: { + espXferComplete* xfc = (espXferComplete*)&packet.data()[1]; + processXferComplete(xfc); + break; + } + case PKT_XFER_TIMEOUT: { + espXferComplete* xfc = (espXferComplete*)&packet.data()[1]; + processXferTimeout(xfc); + break; + } + case PKT_AVAIL_DATA_REQ: { + pendingData* pending = (pendingData*)&packet.data()[1]; + prepareExternalDataAvail(pending, packet.remoteIP()); + break; + } + case PKT_APLIST_REQ: { + IPAddress senderIP = packet.remoteIP(); + + APlist APitem; + APitem.src = WiFi.localIP(); + strcpy(APitem.alias, APconfig["alias"]); + APitem.channelId = curChannel.channel; + APitem.tagCount = getTagCount(); + APitem.version = version; + + uint8_t buffer[sizeof(struct APlist) + 1]; + buffer[0] = PKT_APLIST_REPLY; + memcpy(buffer + 1, &APitem, sizeof(struct APlist)); + udp.writeTo(buffer, sizeof(buffer), senderIP, UDPPORT); + break; + } + case PKT_APLIST_REPLY: { + APlist* APreply = (APlist*)&packet.data()[1]; + //remove active channel from list + for (int i = 0; i < 6; i++) { + if (channelList[i] == APreply->channelId) channelList[i] = 0; + } + wsSendAPitem(APreply); + break; + } } - if (packet.data()[0] == PKT_XFER_COMPLETE) { - espXferComplete* xfc = (espXferComplete*)&packet.data()[1]; - processXferComplete(xfc); +} + +void autoselect(void* pvParameters) { + // reset channel list + uint8_t values[] = {11, 15, 20, 25, 26, 27}; + memcpy(channelList, values, sizeof(values)); + // wait 5s for channelList to collect all AP's + vTaskDelay(5000 / portTICK_PERIOD_MS); + + curChannel.channel = 0; + for (int i = 0; i < 6; i++) { + if (channelList[i] > 0) { + curChannel.channel = channelList[i]; + break; + } } - if (packet.data()[0] == PKT_XFER_TIMEOUT) { - espXferComplete* xfc = (espXferComplete*)&packet.data()[1]; - processXferTimeout(xfc); - } - if (packet.data()[0] == PKT_AVAIL_DATA_REQ) { - pendingData* pending = (pendingData*)&packet.data()[1]; - prepareExternalDataAvail(pending, packet.remoteIP()); - } - if (packet.data()[0] == PKT_ID_APS) { - Serial.println("ap list req"); - IPAddress senderIP = packet.remoteIP(); - unsigned int senderPort = packet.remotePort(); - //todo: autoselect channel + if (curChannel.channel == 0) { + curChannel.channel = 11; + } + APconfig["channel"] = curChannel.channel; + do { + vTaskDelay(1000 / portTICK_PERIOD_MS); + } while (!version); + + sendChannelPower(&curChannel); + saveAPconfig(); + + vTaskDelay(1000 / portTICK_PERIOD_MS); + vTaskDelete(NULL); +} + +void UDPcomm::getAPList() { + APlist APitem; + APitem.src = WiFi.localIP(); + strcpy(APitem.alias, APconfig["alias"]); + APitem.channelId = curChannel.channel; + APitem.tagCount = getTagCount(); + APitem.version = version; + wsSendAPitem(&APitem); + + if (APconfig["channel"].as() == 0) { + xTaskCreate(autoselect, "autoselect", 10000, NULL, configMAX_PRIORITIES - 10, NULL); } + + uint8_t buffer[sizeof(struct APlist) + 1]; + buffer[0] = PKT_APLIST_REQ; + memcpy(buffer + 1, &APitem, sizeof(struct APlist)); + udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT); } void UDPcomm::netProcessDataReq(struct espAvailDataReq* eadr) { uint8_t buffer[sizeof(struct espAvailDataReq) + 1]; buffer[0] = PKT_AVAIL_DATA_INFO; memcpy(buffer + 1, eadr, sizeof(struct espAvailDataReq)); - udp.writeTo(buffer, sizeof(buffer), IPAddress(239, 10, 0, 1), 16033); + udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT); } void UDPcomm::netProcessXferComplete(struct espXferComplete* xfc) { uint8_t buffer[sizeof(struct espXferComplete) + 1]; buffer[0] = PKT_XFER_COMPLETE; memcpy(buffer + 1, xfc, sizeof(struct espXferComplete)); - udp.writeTo(buffer, sizeof(buffer), IPAddress(239, 10, 0, 1), 16033); + udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT); } void UDPcomm::netProcessXferTimeout(struct espXferComplete* xfc) { uint8_t buffer[sizeof(struct espXferComplete) + 1]; buffer[0] = PKT_XFER_TIMEOUT; memcpy(buffer + 1, xfc, sizeof(struct espXferComplete)); - udp.writeTo(buffer, sizeof(buffer), IPAddress(239, 10, 0, 1), 16033); + udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT); } void UDPcomm::netSendDataAvail(struct pendingData* pending) { uint8_t buffer[sizeof(struct pendingData) + 1]; buffer[0] = PKT_AVAIL_DATA_REQ; memcpy(buffer + 1, pending, sizeof(struct pendingData)); - udp.writeTo(buffer, sizeof(buffer), IPAddress(239, 10, 0, 1), 16033); + udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT); } \ No newline at end of file diff --git a/ESP32_AP-Flasher/src/web.cpp b/ESP32_AP-Flasher/src/web.cpp index ef1e21bf..51d16795 100644 --- a/ESP32_AP-Flasher/src/web.cpp +++ b/ESP32_AP-Flasher/src/web.cpp @@ -16,6 +16,7 @@ #include "newproto.h" #include "settings.h" #include "tag_db.h" +#include "udp.h" extern uint8_t data_to_send[]; @@ -168,6 +169,24 @@ void wsSendTaginfo(uint8_t mac[6]) { xSemaphoreGive(wsMutex); } +void wsSendAPitem(struct APlist* apitem) { + DynamicJsonDocument doc(250); + JsonObject ap = doc.createNestedObject("apitem"); + + char version_str[6]; + sprintf(version_str, "%04X", apitem->version); + + ap["ip"] = ((IPAddress)apitem->src).toString(); + ap["alias"] = apitem->alias; + ap["count"] = apitem->tagCount; + ap["channel"] = apitem->channelId; + ap["version"] = version_str; + + if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY); + ws.textAll(doc.as()); + if (wsMutex) xSemaphoreGive(wsMutex); +} + void init_web() { LittleFS.begin(true); @@ -273,6 +292,36 @@ void init_web() { } }); + server.on("/get_ap_list", HTTP_GET, [](AsyncWebServerRequest *request) { + UDPcomm udpsync; + udpsync.getAPList(); + File configFile = LittleFS.open("/current/apconfig.json", "r"); + if (!configFile) { + request->send(500, "text/plain", "Error opening apconfig.json file"); + return; + } + request->send(configFile, "application/json"); + configFile.close(); + }); + + server.on("/save_apcfg", HTTP_POST, [](AsyncWebServerRequest *request) { + if (request->hasParam("alias", true) && request->hasParam("channel", true)) { + APconfig["alias"] = request->getParam("alias", true)->value(); + APconfig["channel"] = request->getParam("channel", true)->value(); + saveAPconfig(); + setAPchannel(); + } + request->send(200, "text/plain", "Ok, saved"); + }); + + server.on("/backup_db", HTTP_GET, [](AsyncWebServerRequest *request) { + saveDB("/current/tagDB.json"); + File file = LittleFS.open("/current/tagDB.json", "r"); + AsyncWebServerResponse *response = request->beginResponse(file, "tagDB.json", String(), true); + request->send(response); + file.close(); + }); + server.onNotFound([](AsyncWebServerRequest *request) { if (request->url() == "/" || request->url() == "index.htm") { request->send(200, "text/html", "-"); @@ -291,7 +340,6 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index } else { filename = "unknown.jpg"; } - Serial.print((String) "UploadStart: " + filename); request->_tempFile = LittleFS.open("/" + filename, "w"); } if (len) { @@ -299,7 +347,6 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index request->_tempFile.write(data, len); } if (final) { - Serial.println((String) " End: " + filename + ", " + index + len); request->_tempFile.close(); if (request->hasParam("mac", true)) { String dst = request->getParam("mac", true)->value();